Изменение цвета выделенного текста в jTextPane

Я создаю текстовый редактор с помощью JTextPane, который позволяет пользователю изменять цвет выделенного текста. Но когда пользователь выбирает текст, а затем выбирает вариант изменения цвета (например, на красный), текст не отображается красным, пока текст не будет отменен. Я попытался использовать setSelectedTextColor, чтобы изменить цвет выделенного текста, но это не сработало, поскольку это меняет текст на красный каждый раз, когда текст выбирается впоследствии. Есть ли способ, чтобы выделенный текст отображался в реальном цвете? Или как это работает в Word, где это не фактический цвет текста, но когда выбран текст разных цветов, они отображаются разными цветами, даже когда они выбраны.

Я использую следующий код для настройки JTextPane и кнопки, которая изменяет выделенный текст на красный:

JButton redButton = new JButton(new StyledEditorKit.ForegroundAction("red", Color.RED));
redButton.setFocusable(false);
buttonPanel.add(redButton);

JTextPane настроен так же, как и с типом содержимого HTML, и использует HTMLEditorKit:

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

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

Дайте мне знать, если вам понадобится больше исходного кода, чтобы разобраться в вопросе. Спасибо!


person smith8ar    schedule 30.09.2013    source источник


Ответы (4)


Взгляните на DefaultHighlightPainter внутренний класс DefaultHighlighter.

Метод

    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(). Вы можете расширить класс и адаптировать выделение.

Или воспользуйтесь более простым подходом, чтобы переопределить ваш JTextPane getSelectionColor(). В методе просто проверьте, выделен ли текст, и используйте атрибуты выбранных элементов, чтобы получить желаемый цвет. Если ничего не выбрано, просто верните super.getSelectedColor()

ОБНОВЛЕНИЕ: на самом деле применение цветов для выбора используется на низком уровне GlyphView's public void paint (Graphics g, Shape a) {... JTextComponent tc = (JTextComponent) c; Цвет 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 (подсветка, 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 и художника. Если вы определите своего текущего художника, цвет не будет использоваться.

person StanislavL    schedule 01.10.2013
comment
В моем случае я пытаюсь изменить цвет фактического текста, а не цвет выделения. Например, если я выделю два слова, одно слово будет черным, а другое - красным. При выделении я хочу, чтобы цвет текста отображался как правильный цвет, а цвет выделения оставался прежним. Но я не нашел никаких доказательств того, что Java поддерживает 2 разных выбранных цвета текста, поскольку существует метод setSelectedText, который позволяет мне изменить выбранный цвет текста только на один цвет и нет возможности для переменных цветов. Имеет ли это смысл? - person smith8ar; 01.10.2013
comment
Не могли бы вы опубликовать SSCCE с выбранными разными цветами? По-моему, вы должны заменить HighlighPainter по умолчанию своим собственным, где вы рисуете не только фон, но и выделенный текст желаемыми цветами. - person StanislavL; 02.10.2013

Похоже, вы используете что-то другое, кроме названия семейства шрифтов. Я повторно факторизовал этот пример, чтобы использовать JTextPane, и увидел ожидаемый результат. Как отмечено там, для действий требуется имя семейства шрифтов, например значение по умолчанию или face=SansSerif, как указано в FontFamilyAction вложен в StyledEditorKit.

изображение

JTextPane textPane = new JTextPane();
person trashgod    schedule 30.09.2013
comment
Я могу воссоздать ваш пример выше, используя setSelectedText (Color). Но мой вопрос в том, поддерживает ли Java возможность выбора цветов текста с переменным выбором или только один. Итак, если я выбрал 2 слова, один черный текст и один красный текст, и установил для выбранного цвета текста красный цвет (setSelectedTextColor (Color.RED)), тогда оба слова будут отображаться как красные при выделении, но я бы хотел, чтобы черное слово для отображения черного цвета даже при выделении. - person smith8ar; 01.10.2013
comment
Я не уверен, чего вы пытаетесь достичь; Действия EditorKit предназначены для работы с выделенным фрагментом, в то же время оставляя его читаемым. - person trashgod; 01.10.2013
comment
Моя проблема с выполнением действий с выделенным текстом, а скорее с тем, как текст отображается, когда он выделен. В вашем примере выделенный текст отображается красным цветом. Но скажем, что в исходном невыделенном тексте Stack красный, а OverFlow - черный. Когда он выделен, он все равно будет отображаться красным, как на вашем скриншоте. Поэтому мне интересно, есть ли способ, чтобы часть слова OverFlow по-прежнему отображалась черным при выделении, а Stack по-прежнему был красным. - person smith8ar; 01.10.2013
comment
Насколько мне известно, идея @ StanislavL, похоже, заслуживает продолжения. - person trashgod; 01.10.2013

Самый простой способ изменить цвет выделенного текста:

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);
person Ganesh Patel    schedule 14.07.2017

Добавляю свое мнение. Это может быть еще проще, чем описанные выше подходы.

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

        @Override
        public Color getSelectedTextColor() {
            return COLOR_YOU_WANT;
        }
    };
person shaILU    schedule 07.12.2020