📄 multibox.java
字号:
}
public void updateInternal () { // small enough that redraw whole thing
getPreferredSize();
offg.setColor(parent.unselectedBackground);
offg.fillRect(0, 0, preferredSize.width, preferredSize.height);
FontMetrics fg = offg.getFontMetrics();
for (int i = 0; i < parent.columns(); ++i) {
offg.setColor(parent.unselectedText);
offg.drawString(parent.headingAt(i), parent.pixposition(i),
parent.toplinepix());
int linewidth = fg.stringWidth(parent.headingAt(i));
offg.setColor(parent.selectedBackground);
offg.drawLine(parent.pixposition(i) + LIP,
preferredSize.height - BAR_HEIGHT,
parent.pixposition(i) + linewidth - LIP,
preferredSize.height - BAR_HEIGHT);
}
}
public void reJig () { // call when width changes - i.e. font.
offi = null; // provoke us to remake offscreen.
repaint();
}
public void update(Graphics g) {
if (g == null)
return;
if (offi == null) {
offi = createImage(parent.pixwidth(), parent.lineheight() + EXTRA_HEIGHT);
offg = offi.getGraphics();
offg.setFont(parent.listFont);
updateInternal(); // uI called if color changes.
}
int realwidth = parent.listCanvas.getSize().width;
width = getSize().width;
height = getSize().height;
g.clipRect(0, 0, realwidth, height);
g.drawImage(offi, -xoffset, 0, null);
if (realwidth > parent.pixwidth()) {
g.setColor(parent.unselectedBackground);
g.fillRect(parent.pixwidth() + xoffset, 0,
realwidth - parent.pixwidth(),
parent.lineheight() + EXTRA_HEIGHT);
}
}
public void paint(Graphics g) {
update(g);
}
public Dimension getPreferredSize () {
preferredSize.width = parent.pixwidth();
preferredSize.height = parent.lineheight() + EXTRA_HEIGHT;
return preferredSize;
}
public Dimension getMinimumSize () {
return getPreferredSize();
}
} // end inner class MultiHeadingCanvas
/** LineData is the internal storage per item used by MultiBox. It contains an
* Object, theUseful, which is storage for client(of MultiBox)--based
* information; for example, ServerPlayerContainer uses it to store
* ServerPlayers. field contains a string for each text field of the item,
* plus a final extra "field" which is non-null to represent "activity" of the
* item.
**/
class LineData {
Object theUseful;
String[] fields;
LineData(Object theUseful1, String[] fields1) {
// near copy-constructor, just to inhibit nasty fiddlings
// with fields, without proper channels....
theUseful = theUseful1;
fields = new String[fields1.length];
for (int i = 0; i < fields1.length; ++i) {
fields[i] = fields1[i];
}
}
}
// Moved these out of MultiListCanvas to satisfy the compiler.
private static final int BITMAP_YINC = 10;
private static final int BITMAP_YINIT = 20;
/** MultiListCanvas draws the actual list for a MultiBox.
* It also reaches out into the MultiBox to manage scrollbars.
* The reVScroll() method should be called to inform the vertical
* scrollbar of changes in list contents.
* It intercepts reshape() requests to determine its own size.
* It can draw a single selection, and also examines the final
* "invisible" field of each line for nullness, to decide whether to
* mark the line as "active", currently represented by cross-hatching.
**/
class MultiListCanvas extends Canvas {
private MultiBox parent;
private Graphics offg;
private Image offi;
private int xoffset, yoffset;
public int yoffset () { return yoffset; }
public int xoffset () { return xoffset; }
private Dimension preferredSize = new Dimension();
// private int width, height;
private int bitmapheight = BITMAP_YINIT;
private Image hatcher;
private Image hatchers;
MultiListCanvas(MultiBox parent1) {
parent = parent1;
addComponentListener(new sizeListener());
// allocateOff();
}
private void expandInternal () {
bitmapheight += BITMAP_YINC;
allocateOff();
}
private void allocateOff () {
offi = createImage(parent.pixwidth(), parent.lineheight() * bitmapheight);
// System.out.println(" "+offi + parent.pixwidth() + " " + parent.lineheight()*bitmapheight);
if (offi == null)
return; //during constructor??
int bmcx = parent.pixposition(1) - parent.gutter();
int bmcy = parent.lineheight();
int[] bmh = new int[bmcx * bmcy];
int[] bmhs = new int[bmcx * bmcy];
int utrgb = parent.unselectedText.getRGB();
int strgb = parent.selectedText.getRGB();
for (int i = 0; i < bmcy; ++ i) {
for (int j = 0; j < bmcx; ++ j) {
if ((i + j) % 5 == 0) {
bmh[i * bmcx + j] = utrgb;
bmhs[i * bmcx + j] = strgb;
}
}
}
hatcher = createImage(new MemoryImageSource(bmcx, bmcy, bmh, 0, bmcx));
hatchers = createImage(new MemoryImageSource(bmcx, bmcy, bmhs, 0, bmcx));
offg = offi.getGraphics();
offg.setFont(parent.listFont);
updateInternal();
}
public void reJig () { // call when width changes - i.e. font.
allocateOff();
repaint();
}
public void updateInternal () { // small enough that redraw whole thing
getPreferredSize();
updateInternal(0, parent.lines() - 1);
}
public void updateLine(int line) {
if (line < 0 || line >= parent.lines())
return;
updateInternal(line, line);
}
public void updateInternal(int topline, int bottomline) {
if (offg == null
|| (bottomline - topline) < 0)
return;
// System.out.println("uI "+topline+" "+bottomline);
getPreferredSize();
if (parent.lines() > bitmapheight) { // if exceeded dimensions of offscreen,
// expand it, and change request to complete redraw....
expandInternal();
topline = 0;
bottomline = parent.lines() - 1;
}
int selected = parent.getSelectedIndex();
offg.setColor(parent.unselectedBackground);
if (selected >= topline && selected <= bottomline) {
// The selected item is in the visible area...
// +++ Why two calls to fillRect() here? Seems could just clear the
// whole thing since the selected item area gets colored in later.
offg.fillRect(0, topline * parent.lineheight(), preferredSize.width,
(selected - topline) * parent.lineheight());
offg.fillRect(0, (selected + 1) * parent.lineheight(), preferredSize.width,
(bottomline - selected) * parent.lineheight());
offg.setColor(parent.selectedBackground);
offg.fillRect(0, selected * parent.lineheight(), preferredSize.width,
parent.lineheight());
}
else { // draw unselected region background
offg.fillRect(0, topline * parent.lineheight(), preferredSize.width,
(1 + bottomline - topline) * parent.lineheight());
}
offg.setColor(parent.unselectedText);
FontMetrics fm = getFontMetrics(parent.listFont);
for (int i = topline; i <= bottomline; ++i) {
if (i == selected)
offg.setColor(parent.selectedText);
// hatch drawing moved up for improved visibility.
if (parent.fieldAt(i, parent.columns()) != null) {
if (i == selected)
offg.drawImage(hatchers, 0, i * parent.lineheight(), this);
else
offg.drawImage(hatcher, 0, i * parent.lineheight(), this);
}
for (int j = 0; j < parent.columns(); ++j) {
int spos = parent.pixposition(j); // default is left justify.
String format = parent.formatAt(j);
if (format.equals("r")) {
spos = parent.pixposition(j + 1) - parent.gutter() -
fm.stringWidth(parent.fieldAt(i, j));
}
// +++ This is repeatedly calling fieldAt, which calls lineDataAt,
// which calls Vector.elementAt, which is notoriously slow.
// Should call lineDataAt once per line only.
offg.drawString(parent.fieldAt(i, j), spos,
parent.toplinepix() + i * parent.lineheight());
} // end each column
// now deal with activity
if (i == selected)
offg.setColor(parent.unselectedText);
} // end each line
int topreppos = topline * parent.lineheight() - yoffset;
if (bottomline == parent.lines() - 1) // if showing bottom line, do blank too
repaint(0 - xoffset, topreppos, getSize().width, getSize().height - topreppos);
else
repaint(0 - xoffset, topreppos, getSize().width,
(1 + bottomline - topline) * parent.lineheight() );
}
public void update(Graphics g) {
if (g == null)
return;
int width = getSize().width;
int height = getSize().height;
if (offi == null)
allocateOff();
// g.drawImage(offi, -xoffset, -yoffset, null);
// System.out.println(" "+width+" "+parent.pixwidth());
// System.out.println(" "+height+" "+parent.pixheight());
if (width > parent.pixwidth()) { // draw the bit off to the right
int pw = parent.pixwidth() - xoffset;
int sw = (width - parent.pixwidth());
int selected = parent.getSelectedIndex();
// System.out.println(" "+pw+" "+sw+" "+selected);
g.setColor(parent.unselectedBackground);
if (selected >= 0) {
g.fillRect(pw, -yoffset, sw, selected * parent.lineheight());
g.fillRect(pw, (selected + 1) * parent.lineheight() - yoffset, sw,
(parent.lines() - selected) * parent.lineheight());
g.setColor(parent.selectedBackground);
g.fillRect(pw, selected * parent.lineheight() - yoffset, sw,
parent.lineheight());
}
else {
g.fillRect(pw, -yoffset, sw, parent.pixheight());
}
}
int bp = parent.pixheight() - yoffset; // bottom pixel of list posn
if (height > bp) { // draw the bit off the bottom
g.setColor(parent.unselectedBackground);
g.fillRect(0, bp, width, height - bp);
}
Rectangle atrect = new Rectangle(-xoffset, -yoffset, parent.pixwidth(),
parent.pixheight());
Rectangle cliprect = g.getClipBounds();
if (cliprect == null)
return; // if the bastard won't give us a clipRect.
atrect = atrect.intersection(g.getClipBounds());
g.clipRect(atrect.x, atrect.y, atrect.width, atrect.height);
g.drawImage(offi, -xoffset, -yoffset, null);
}
public void paint(Graphics g) {
update(g);
}
public void scroll(int xposition, int yposition) {
int si = parent.scroll_increment();
xoffset = xposition * si; yoffset = yposition * si;
repaint();
}
public Dimension getPreferredSize () {
preferredSize.height = parent.lineheight() * parent.visLines();
preferredSize.width = parent.pixwidth();
return preferredSize;
}
class sizeListener extends ComponentAdapter {
public void componentResized(ComponentEvent ce) {
Rectangle rect = getBounds();
int maxxval = parent.pixwidth();
if (xoffset > maxxval)
xoffset = maxxval;
if (xoffset < 0)
xoffset = 0;
parent.hScroll.setValues(xoffset, rect.width, 0, maxxval);
parent.hScroll.setBlockIncrement(rect.width);
reVScroll();
update(getGraphics());
}
}
public void reVScroll () {
int height = getSize().height;
int si = parent.scroll_increment();
int maxyval = parent.pixheight();
if (yoffset > maxyval)
yoffset = maxyval;
if (yoffset < 0)
yoffset = 0;
parent.vScroll.setValues(yoffset / si, height / si, 0, maxyval / si);
// This Math.max is because X complains if the scrollbar increment is < 1.
// The right solution is probably to ensure that the window can't be resized
// smaller than one line + headings. -sigue
parent.vScroll.setBlockIncrement(Math.max(1, (height - parent.lineheight()) / si));
parent.setVisLines(getSize().height / parent.lineheight());
}
}
} // end class MultiBox
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -