在jTextPane中更改所选文本的颜色

7
我正在使用JTextPane创建一个文本编辑器,允许用户更改所选文本的颜色。但是当用户选择文本,然后选择更改颜色选项(比如,变成红色),文本在未取消选择之前不会显示为红色。我尝试使用setSelectedTextColor来更改所选文本的颜色,但由于这会在之后任何时候选择文本时将文本更改为红色,因此无法起作用。有没有办法使所选文本显示其实际颜色?或者像Word中的工作方式一样,在选择文本时它们不是文本的实际颜色,但当选择不同颜色的文本时,它们即使在选择时也显示为不同颜色。
我使用以下代码设置了JTextPane和按钮,以将所选文本更改为红色:
JButton redButton = new JButton(new StyledEditorKit.ForegroundAction("red", Color.RED));
redButton.setFocusable(false);
buttonPanel.add(redButton);

使用HTMLEditorKit将JTextPane设置为HTML内容类型:

p=new JTextPane();
p.setSize(300, 300);
kit = new HTMLEditorKit();
p.setEditorKit(kit);
p.setDocument(kit.createDefaultDocument());

p.setContentType("text/html");
p.setEditable(true);

如果您需要更多的源代码来理解问题,请告诉我。谢谢!

5个回答

5
请查看 DefaultHighlighter 类的内部类 DefaultHighlightPainter
该方法
    public void paint(Graphics g, int offs0, int offs1, Shape bounds, JTextComponent c) {
        Rectangle alloc = bounds.getBounds();
        try {
            // --- determine locations ---
            TextUI mapper = c.getUI();
            Rectangle p0 = mapper.modelToView(c, offs0);
            Rectangle p1 = mapper.modelToView(c, offs1);

            // --- render ---
            Color color = getColor();

            if (color == null) {
                g.setColor(c.getSelectionColor());
            }
            else {
                g.setColor(color);
            }

正如您所看到的,它使用getColor()getSelectionColor()。您可以扩展该类并调整高亮显示的绘画。

或者使用更简单的方法覆盖您的JTextPanegetSelectionColor()。在该方法中,只需检查文本是否已选择并使用所选元素的属性来获取所需的颜色即可。如果未选择任何内容,请返回super.getSelectedColor()

更新: 实际上,应用选择颜色是在低级别的GlyphView中使用的 public void paint(Graphics g, Shape a) { ... JTextComponent tc = (JTextComponent) c; Color selFG = tc.getSelectedTextColor();

        if (// there's a highlighter (bug 4532590), and
            (tc.getHighlighter() != null) &&
            // selected text color is different from regular foreground
            (selFG != null) && !selFG.equals(fg)) {

            Highlighter.Highlight[] h = tc.getHighlighter().getHighlights();
            if(h.length != 0) {
                boolean initialized = false;
                int viewSelectionCount = 0;
                for (int i = 0; i < h.length; i++) {
                    Highlighter.Highlight highlight = h[i];
                    int hStart = highlight.getStartOffset();
                    int hEnd = highlight.getEndOffset();
                    if (hStart > p1 || hEnd < p0) {
                        // the selection is out of this view
                        continue;
                    }
                    if (!SwingUtilities2.useSelectedTextColor(highlight, tc)) {
                        continue;
                    }

您可以看到,在SwingUtilities2.useSelectedTextColor(highlight, tc)中,应用选择颜色与视图的默认颜色有所不同。
在源代码中 http://kickjava.com/src/com/sun/java/swing/SwingUtilities2.java.htm
 public static boolean useSelectedTextColor(Highlighter.Highlight  JavaDoc h, JTextComponent  JavaDoc c) {
     Highlighter.HighlightPainter  JavaDoc painter = h.getPainter();
     String  JavaDoc painterClass = painter.getClass().getName();
     if (painterClass.indexOf("javax.swing.text.DefaultHighlighter") != 0 &&
             painterClass.indexOf("com.sun.java.swing.plaf.windows.WindowsTextUI") != 0) {
         return false;
     }
     try {
         DefaultHighlighter.DefaultHighlightPainter  JavaDoc defPainter =
                 (DefaultHighlighter.DefaultHighlightPainter  JavaDoc) painter;
         if (defPainter.getColor() != null &&
                 !defPainter.getColor().equals(c.getSelectionColor())) {
             return false;
         }
     } catch (ClassCastException  JavaDoc e) {
         return false;
     }
     return true;
 }

使用颜色取决于L&F和绘图器。如果您定义了自己的绘图器,则不会使用颜色。


在我的情况下,我试图使实际文本的颜色表现不同,而不是高亮的颜色。比如说,如果我将两个单词都高亮了,一个单词是黑色文本,另一个单词是红色文本。当高亮时,我希望文本颜色显示为正确的颜色,而高亮颜色保持不变。但我没有找到任何证据表明Java支持2种不同的选定文本颜色,因为有一个setSelectedText方法可以让我将选定文本颜色更改为一个颜色,而没有可变颜色的选项。这有意义吗? - smith8ar
你能否发布一个包含不同颜色选择的SSCCE?对我来说,你应该用自己的HighlightPainter替换默认的,其中你不仅要用所需的颜色绘制背景,还要绘制选择文本。 - StanislavL

3

看起来你可能使用的不是字体族名称。我重构了这个示例,使用了JTextPane,并看到了预期的结果。如上所述,操作需要一个字体族名称,例如默认或face=SansSerif,由StyledEditorKit中嵌套的FontFamilyAction类指定。

image

JTextPane textPane = new JTextPane();

我可以使用setSelectedText(Color)重新创建您上面的示例。但我的问题是Java是否支持具有可变选定文本颜色,还是仅支持一种颜色。因此,如果我选择了两个单词,一个黑色文本和一个红色文本,并将选定的文本颜色设置为红色(setSelectedTextColor(Color.RED)),那么当突出显示时,两个单词都会显示为红色,但我希望黑色单词在突出显示时仍然显示为黑色。 - smith8ar
我不确定你想要实现什么;EditorKit 操作旨在对选择进行操作,同时仍然保持选择可读。 - trashgod
我的问题不在于对所选文本执行操作,而是在于当文本被突出显示时的显示方式。在您的示例中,突出显示的文本显示为红色。但是假设在原始未选择的文本中,“Stack”为红色,“OverFlow”为黑色。当突出显示时,它仍将显示为全部红色,就像在您的屏幕截图中一样。因此,我想知道是否有一种方法可以使单词的“OverFlow”部分在突出显示时仍然显示为黑色,“Stack”仍然为红色。 - smith8ar
据我所知没有,但是@StanislavL的想法似乎值得追求。 - trashgod

0

改变所选文本颜色的最简单方法:

int start = textPane.getSelectionStart();
int end = textPane.getSelectionEnd();
int selectedLength = end - start;
StyleDocument style = pane.getStyledDocument();

//this give your attribute set of selected Text. 
AttributeSet oldSet = style.getCharacterElement(end-1).getAttributes();

//StyleContext for creating attribute set
StyleContext sc = StyleContext.getDefaultStyleContext();

// Attribute set which contains new color with old attributes
AttributeSet s = sc.addAttribute(oldSet, StyleConstants.Foreground, Color.RED);
//This set the color of the Text
style.setCharacterAttributes(start, selectedLength, s, true);

0

我想你和我一样在寻找这个问题的解决方案,即不要有selectedTextColor。我在各处都没有找到解决方案,但在绝望中,我尝试了以下方法:

JTextPane thePane = ...;
thePane.setSelectedTextColor(null);

它只是起作用了!所选文本的背景色更改为selectionColor,但文本字母保留其原始前景色。我正在编写自定义代码高亮器,因此我需要保留这些高亮(通过具有CSS类的HTMLDocument跨度应用)。它看起来像这样: JTextPane with selection retaining its foreground color

而不是像这样: enter image description here


0

补充我的观点。这可能比上述方法更简单。

    JEditorPane ep = new JEditorPane() {
        @Override
        public Color getSelectionColor() {
            return COLOR_YOU_WANT;
        }

        @Override
        public Color getSelectedTextColor() {
            return COLOR_YOU_WANT;
        }
    };

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接