问题
I have a JTextPane, with styledDocuent. I've inserted programmatically the text: "Hello World". Word "Hello" is red, and word "World" is green. Is there any way I can select the two words, and the selection rectangle becomes half red half green(or whatever color the selected character is)? By select, I mean, select text at runtime, not programmatically...
I believe here Changing color of selected text in jTextPane , StanislavL tells how this can be achieved, by I don't know how to implement it.
Edit:
SimpleAttributeSet aset = new SimpleAttributeSet();
StyleConstants.setForeground(aset, Color.RED);
muTextPane.setCharacterAttributes(aset, false);
try {
muTextPane.getStyledDocument().insertString(muTextPane.getCaretPosition(), "Hello", aset);
muTextPane.setCaretPosition(muTextPane.getStyledDocument().getLength());
} catch (BadLocationException ex) {
Logger.getLogger(View1.class.getName()).log(Level.SEVERE, null, ex);
}
StyleConstants.setForeground(aset, Color.GREEN);
muTextPane.setCharacterAttributes(aset, false);
try {
muTextPane.getStyledDocument().insertString(muTextPane.getCaretPosition(), " World", aset);
muTextPane.setCaretPosition(muTextPane.getStyledDocument().getLength());
} catch (BadLocationException ex) {
Logger.getLogger(View1.class.getName()).log(Level.SEVERE, null, ex);
}
回答1:
See if this is good enough for what you need. There is probably a better way to do it, but it works with your example.
public class ColorTextPane extends JFrame {
static JTextPane muTextPane = new JTextPane();
public static void main(String[] args) {
new ColorTextPane();
}
public ColorTextPane() {
///// Code from the question /////
SimpleAttributeSet aset = new SimpleAttributeSet();
StyleConstants.setForeground(aset, Color.RED);
StyleConstants.setFontSize(aset, 14);
muTextPane.setCharacterAttributes(aset, false);
try {
muTextPane.getStyledDocument().insertString(muTextPane.getCaretPosition(), "Hello", aset);
muTextPane.setCaretPosition(muTextPane.getStyledDocument().getLength());
} catch (BadLocationException ex) {
ex.printStackTrace();
}
StyleConstants.setForeground(aset, Color.GREEN);
muTextPane.setCharacterAttributes(aset, false);
try {
muTextPane.getStyledDocument().insertString(muTextPane.getCaretPosition(), " World", aset);
muTextPane.setCaretPosition(muTextPane.getStyledDocument().getLength());
} catch (BadLocationException ex) {
ex.printStackTrace();
}
///// End code from the question /////
muTextPane.setHighlighter(new MyHighlighter());
add(muTextPane);
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
private static class MyHighlighter extends DefaultHighlighter {
private static List<Interval> ranges = new ArrayList<>();
private static Map<Interval, Color> rangesColors = new HashMap<>();
private static LayeredHighlighter.LayerPainter DefaultPainter = new MyDHP(null);
@Override
public Object addHighlight(int p0, int p1, HighlightPainter p) throws BadLocationException {
return super.addHighlight(p0, p1, DefaultPainter);
}
@Override
public void removeHighlight(Object tag) {
super.removeHighlight(tag);
ranges.clear();
rangesColors.clear();
}
private static class MyDHP extends DefaultHighlightPainter {
public MyDHP(Color arg0) {
super(arg0);
}
@Override
public Shape paintLayer(Graphics g, int offs0, int offs1, Shape bounds, JTextComponent c, View view) {
Rectangle r;
if (offs0 == view.getStartOffset() && offs1 == view.getEndOffset()) {
// Contained in view, can just use bounds.
if (bounds instanceof Rectangle)
r = (Rectangle) bounds;
else
r = bounds.getBounds();
}
else {
// Should only render part of View.
try {
// --- determine locations ---
Shape shape = view.modelToView(offs0, Position.Bias.Forward,
offs1,Position.Bias.Backward, bounds);
r = (shape instanceof Rectangle) ? (Rectangle)shape : shape.getBounds();
} catch (BadLocationException e) {
// can't render
r = null;
}
}
if (r != null) {
// If we are asked to highlight, we should draw something even
// if the model-to-view projection is of zero width (6340106).
r.width = Math.max(r.width, 1);
// Override simple fillRect
Interval newInt = new Interval(offs0, offs1);
for (Interval interval : ranges) {
if (interval.semiIncludes(newInt)) {
g.setColor(rangesColors.get(interval));
g.fillRect(r.x, r.y, r.width, r.height);
return r;
}
}
ranges.add(newInt);
rangesColors.put(newInt, getColor());
g.setColor(rangesColors.get(newInt));
g.fillRect(r.x, r.y, r.width, r.height);
}
return r;
}
@Override
public Color getColor() {
return StyleConstants.getForeground(muTextPane.getCharacterAttributes());
}
}
}
}
class Interval {
int start;
int end;
Interval(int p0, int p1) {
start = Math.min(p0, p1);
end = Math.max(p0, p1);
}
boolean semiIncludes(Interval intv) {
if (intv.start == this.start || intv.end == this.end)
return true;
return false;
}
}
I create and set a new Highlighter
which keeps hold of the colors for each offset range in the document. It also has its own LayeredHighlighter.LayerPainter
where I partially override the paintLayer
method (some of it is copy-paste from the source).
The Interval
class is just a help utility, you can remove it and add its functionality inside the highlighting mechanism instead.
来源:https://stackoverflow.com/questions/22874269/multi-color-text-selection-in-jtextpane-swing