📄 textarea.java
字号:
g.setColor(getForeground());
if (border)
g.drawRect(0, 0, width, height);
}
public void redisplay () {
if (offg != null)
redisplay(offg, true);
}
// signalling from redisplay to update, to avoid unnecessary redrawing
// of offscreen.
// best method could be to only call repaint() rather than redisplay(),
// but I am not confident this would not break something.... AMB.
private boolean valid = false;
// Do a full redisplay of the text in the canvas starting with
// the history element at the bottom of the canvas, hbot/lbot,
// and working toward the top.
private void redisplay (Graphics g, boolean repaint) {
if (g == null)
return;
synchronized (this) {
//Debug.println("redisplay: " + this);
FontMetrics metrics = Toolkit.getDefaultToolkit().getFontMetrics(g.getFont());
int index = hbot;
int lineHeight = metrics.getHeight();
int yy = ymax;
//int totalLines = (yy - ymin + 1) / lineHeight;
clearCanvas(g);
outer:
while (yy >= ymin && history.size() > 0 && index >= 0) {
HistoryElement elem = history.elementAt(index);
g.setColor(elem.color);
if (wrap) {
int line = (index == hbot) ? lbot : numLines(elem, metrics) - 1;
for (int i = line; yy >= ymin && i >= 0; i--) {
int offset = elem.getLineOffset(i);
int len = elem.getLineLength(i);
char[] chars = elem.getChars();
// skip initial whitespace on wrapped lines
//while (len > 0 && Character.isWhitespace(chars[offset])) {
//++offset; --len;
//}
g.drawChars(chars, offset, len, insets.left, yy);
//Debug.println(" drew elem " + index + ", " + line + " at y = " + yy);
yy -= lineHeight;
}
}
else { // wrap = false
char[] text = elem.getChars();
g.drawChars(text, 0, text.length, insets.left, yy);
//Debug.println(" drew elem " + index + " at y = " + yy);
yy -= lineHeight;
}
--index;
}
g.setColor(getForeground());
if (repaint) {
valid = true;
repaint();
}
//Debug.println("redisplay done: last elem drawn = " + (index - 1)
// + " yy = " + yy);
} // synchronized(this)
}
public synchronized void update (Graphics g) {
if (getSize().width != width || getSize().height != height) {
// If the width has changed, invalidate all line breaks.
if (getSize().width != width)
invalidateHistory();
width = getSize().width;
height = getSize().height;
insideWidth = width - insets.left - insets.right;
FontMetrics metrics = Toolkit.getDefaultToolkit().getFontMetrics(font);
ymin = insets.top + metrics.getAscent() + 1;
ymax = height - metrics.getDescent() - insets.bottom;
rows = (ymax - (ymin - 1)) / metrics.getHeight() + 1;
// If at bottom before resizing, reset so that still at bottom
// after resizing.
if (atBottom() && history.size() > 0) {
// The width may have been changed, in which case lbot may
// be incorrect. Recompute last line in history and make it
// the last line displayed.
hbot = history.endIndex();
lbot = numLines(history.elementAt(hbot), null) - 1;
}
// Free the resources held by the old offscreen image.
if (offscreen != null)
offscreen.flush();
offscreen = createImage(width, height);
offg = offscreen.getGraphics();
offg.setFont(font);
valid = false;
} // end resizing
if (!valid) // almost certainly this update didn't come from redisplay().
redisplay(offg, false);
else
valid = false; // the next update will behave as normal.
if (g != null)
g.drawImage(offscreen, 0, 0, this);
}
// This is called directly by the AWT when the component is
// exposed (or resized?).
public synchronized void paint (Graphics g) {
if (g != null)
update(g);
}
// Write to a stream.
public void save (java.io.PrintWriter out) {
history.save(out);
}
} // end class TextCanvas
/*
Bug: make the TextCanvas 196 pixels wide and display the string
"a b c ddd e f g h i j k l mmm n o p q r s t u v w x yp z 1"
and notice that the majority of yp is written off the right side
of the canvas. I assume this is because the canvas doesn't get resized
correctly by the BorderLayout when the scrollbar is added.
*/
public class TextArea extends Panel implements AdjustmentListener {
private TextCanvas canvas;
private Scrollbar vscroll;
private Scrollbar hscroll = null;
private String vscrollPosition = "East"; // or "West"
protected TextArea () {}
public TextArea (int rows, int cols, String text, boolean wrap) {
canvas = new TextCanvas(text, rows, cols, 1000, 10000, wrap);
canvas.setInsets(new Insets(1, 3, 1, 1)); // top, left, bottom, right
canvas.setBorder(true);
vscroll = new Scrollbar(Scrollbar.VERTICAL, 0, rows, 0, rows);
vscroll.addAdjustmentListener(this);
setLayout(new java.awt.BorderLayout());
add("Center", canvas);
add(vscrollPosition, vscroll);
if (!wrap) {
int w = canvas.getSize().width;
hscroll = new Scrollbar(Scrollbar.HORIZONTAL, 0, w, 0, w);
hscroll.addAdjustmentListener(this);
add("South", hscroll);
}
if (text != null)
appendText(text);
}
public TextArea (int rows, int cols) {
this(rows, cols, null, false); // noWrap compatible w/ java.awt.TextArea
}
public TextArea (String text, int rows, int cols) {
this(rows, cols, text, false);
}
public void insertText (String str, int pos) {
// +++ Not yet implemented
}
// This is just separated out for debugging...
// Reminder to myself:
// visible is the number of visible units between min and max (i.e.,
// the relative size of the scroll bar "bubble".
// value is the value of the top (or left) of the scroll bar bubble,
// and it should range between min and max - visible.
// This seems to contradict the doc for java.awt.Scrollbar.
private void setScrollValues (Scrollbar bar, int value, int visible, int min, int max) {
bar.setValues(value, visible, min, max);
/*
Debug.println((bar == vscroll ? "v" : "h") + "scroll values: val="
+ value + ", vis=" + visible + ", min=" + min
+ ", max=" + max);
*/
}
public void appendText (String str) {
appendText(str, canvas.getForeground());
}
public void appendText (String str, Color color) {
canvas.appendText(str, color);
updateScrollValues();
}
public void setText (String text) {
canvas.clearHistory();
appendText(text);
}
public void clearAll () {
canvas.clearHistory();
updateScrollValues();
canvas.repaint();
}
private void updateScrollValues () {
int rows = canvas.getRows(); // number of display lines in the canvas
int pos = canvas.getBottomDisplayedLine();
setScrollValues(vscroll,
Math.max(0, (pos - rows) + 1), // value
rows, // visible rows
0, // min possible value
Math.max(rows, canvas.getHistoryLines())); // max value
// +++ Setting the block increment only needs to be done when the
// TextArea changes size, but I don't have time to figure out
// the right way to do that now.
vscroll.setBlockIncrement(canvas.getRows());
if (hscroll != null) {
int w = canvas.getSize().width;
int maxWidth = canvas.getMaxLineWidth();
setScrollValues(hscroll, hscroll.getValue(), w, 0, maxWidth);
}
}
/**
* Replaces text from the indicated start to end position with the
* new text specified.
* @param str the text to use as the replacement.
* @param start the start position.
* @param end the end position.
* @see #insertText
* @see #replaceText
*/
public void replaceText (String str, int start, int end) {
// +++ Not yet implemented
}
public int getRows () { return canvas.getRows(); }
public int getColumns () { return canvas.getColumns(); }
public void setEditable (boolean e) {
// +++ Not yet implemented
}
/* debugging
public void setBounds (int x, int y, int w, int h) {
Debug.println("bounds = " + x + "," + y + "," + w + "," + h);
Ergo.printStackTrace();
super.setBounds(x, y, w, h);
}
public void setBounds (java.awt.Rectangle r) {
Debug.println("bounds = " + x + "," + y + "," + w + "," + h);
Ergo.printStackTrace();
super.setBounds(r);
}
*/
// Preferred size = rows x columns
public Dimension getPreferredSize () {
Dimension v = vscroll.getPreferredSize();
Dimension c = canvas.getPreferredSize();
Dimension d = null;
if (hscroll == null)
d = new Dimension(v.width + c.width, c.height);
else {
Dimension h = hscroll.getPreferredSize();
d = new Dimension(v.width + c.width, c.height + h.height);
}
// Debug.println("TextArea.getPreferredSize returning " + d);
return d;
}
public Dimension getMinimumSize () {
return getPreferredSize();
}
public void setColorVec (Color[] c) {
canvas.setForeground(c[0]);
canvas.setBackground(c[1]);
repaint(); // hopefully enough.
}
public void setFont (Font f) {
canvas.setFont(f);
repaint();
}
// Implement AdjustmentListener interface...
public void adjustmentValueChanged (AdjustmentEvent e) {
if (e.getAdjustable() == vscroll) {
switch (e.getAdjustmentType()) {
case AdjustmentEvent.UNIT_INCREMENT:
canvas.moveViewportDown(1);
break;
case AdjustmentEvent.UNIT_DECREMENT:
canvas.moveViewportUp(1);
break;
case AdjustmentEvent.BLOCK_INCREMENT:
canvas.pageDown();
break;
case AdjustmentEvent.BLOCK_DECREMENT:
canvas.pageUp();
break;
case AdjustmentEvent.TRACK:
//Debug.println("TRACK VALUE = " + e.getValue() + ", +rows-1 = "
// + (e.getValue() + canvas.getRows() - 1));
canvas.scrollTo(e.getValue() + canvas.getRows() - 1);
break;
}
updateScrollValues();
}
}
// Write to a stream.
public void save (java.io.PrintWriter out) {
canvas.save(out);
}
//
// Delegate some methods to the TextCanvas
//
public void addMouseListener (MouseListener ml) { canvas.addMouseListener(ml); }
} // end class TextArea
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -