【问题标题】:How to highlight text in a JTextPane with setFocusable(false)?如何使用 setFocusable(false) 突出显示 JTextPane 中的文本?
【发布时间】:2016-09-30 08:40:01
【问题描述】:

所以我有一个基本上用作控制台的JTextPane。我在JFrame 的中心字段和南字段的JTextField 中有它。 JTextField 将获取它拥有的文本,并在用户按下回车键时将其添加到 JTextPane。为了使JTextPane不能被用户编辑,我不得不setFocusable(false),因为使用setEditable(false)可以阻止任何文本出现在JTextPane上。但是虽然我不希望用户编辑窗格,但我仍然希望用户能够突出显示窗格中的文本,但我似乎找不到这样做的方法。

下面是一个示例,说明我的意思

示例

package resources;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.text.AttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;

public class SampeTextPane extends JFrame
{
    public SampeTextPane()
    {
        setPreferredSize(new Dimension(350, 200));
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        JTextPane display = new JTextPane();
        display.setBorder(new EmptyBorder(5, 5, 5, 5));
        display.setMargin(new Insets(5, 5, 5, 5));
        display.setFocusable(false);
        appendToPane(display, "Example", Color.BLUE);

        JTextField field = new JTextField();
        field.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                appendToPane(display, field.getText(), Color.BLACK);
                field.setText("");
            }
        });

        add(display, BorderLayout.CENTER);
        add(field, BorderLayout.SOUTH);

        pack();
        setVisible(true);
    }

    private void appendToPane(JTextPane pane, String text, Color color)
    {
        StyleContext sc = StyleContext.getDefaultStyleContext();
        AttributeSet aset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, color);

        aset = sc.addAttribute(aset, StyleConstants.Alignment, StyleConstants.ALIGN_JUSTIFIED);

        int len = pane.getDocument().getLength();
        pane.setCaretPosition(len);
        pane.setCharacterAttributes(aset, false);
        pane.replaceSelection(text + "\n");
    }

    public static void main(String[] args)
    {
        new SampeTextPane();
    }
}

提前感谢您的帮助。

【问题讨论】:

    标签: java swing highlight jtextpane focusable


    【解决方案1】:

    使用 setEditable(false) 阻止任何文本出现在 JTextPane 上。

    您可以使JTextPane 不可编辑,但您不能通过文本窗格更新文本。

    您可以通过Document 更新文本:

    //int len = pane.getDocument().getLength();
    //pane.setCaretPosition(len);
    //pane.setCharacterAttributes(aset, false);
    //pane.replaceSelection(text + "\n");
    
    try
    {
        StyledDocument doc = pane.getStyledDocument();
        doc.insertString(doc.getLength(), text, aset);
    }
    catch(BadLocationException e) { System.out.println(e); }
    

    【讨论】:

      【解决方案2】:

      另一个选项,虽然更复杂,是使用布尔标志来允许或禁止更改文档,建议 StanislavL here

      在你的情况下,它可能看起来像:

      import java.awt.*;
      import java.awt.event.ActionEvent;
      import java.awt.event.ActionListener;
      
      import javax.swing.*;
      import javax.swing.border.EmptyBorder;
      import javax.swing.text.AttributeSet;
      import javax.swing.text.BadLocationException;
      import javax.swing.text.DefaultStyledDocument;
      import javax.swing.text.DocumentFilter;
      import javax.swing.text.SimpleAttributeSet;
      import javax.swing.text.StyleConstants;
      import javax.swing.text.StyleContext;
      
      @SuppressWarnings("serial")
      public class SampeTextPane extends JFrame {
          private boolean isApi = false;
      
          public SampeTextPane() {
              setPreferredSize(new Dimension(350, 200));
              setDefaultCloseOperation(EXIT_ON_CLOSE);
      
              JTextPane display = new JTextPane();
      
              ((DefaultStyledDocument) display.getDocument()).setDocumentFilter(new DocFilter());
      
              display.setBorder(new EmptyBorder(5, 5, 5, 5));
              display.setMargin(new Insets(5, 5, 5, 5));
              // !! display.setFocusable(false);
              appendToPane(display, "Example", Color.BLUE);
      
              JTextField field = new JTextField();
              field.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent arg0) {
                      appendToPane(display, field.getText(), Color.BLACK);
                      field.setText("");
                  }
              });
      
              add(display, BorderLayout.CENTER);
              add(field, BorderLayout.SOUTH);
      
              pack();
              setVisible(true);
          }
      
          private void appendToPane(JTextPane pane, String text, Color color) {
              isApi = true;
      
              StyleContext sc = StyleContext.getDefaultStyleContext();
              AttributeSet aset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground,
                      color);
      
              aset = sc.addAttribute(aset, StyleConstants.Alignment, StyleConstants.ALIGN_JUSTIFIED);
              int len = pane.getDocument().getLength();
      
              String selection = pane.getSelectedText();
              if (selection == null) {
                  pane.setCaretPosition(len);
                  text += "\n";
              }        
              pane.setCharacterAttributes(aset, false);
              pane.replaceSelection(text);
      
              isApi = false;
          }
      
          private class DocFilter extends DocumentFilter {
              @Override
              public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr)
                      throws BadLocationException {
                  if (isApi) {
                      super.insertString(fb, offset, string, attr);
                  }
              }
      
              @Override
              public void remove(FilterBypass fb, int offset, int length) throws BadLocationException {
                  if (isApi) {
                      super.remove(fb, offset, length);
                  }
              }
      
              @Override
              public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs)
                      throws BadLocationException {
                  if (isApi) {
                      super.replace(fb, offset, length, text, attrs);
                  }
              }
          }
      
          public static void main(String[] args) {
              SwingUtilities.invokeLater(() -> new SampeTextPane());
          }
      
      }
      

      【讨论】:

      • 有趣的处理方式,据我所见,它对同一件事做了同样的事情,但它略微超出了我的 Java 知识。不过谢谢!
      • @Ryan:是的,Camickr 的建议更加更简洁,我很高兴你同意了。在他发布他的正确答案之前,我正在创建我的代码,所以我讨厌不发布我的“努力”。当然,我确实对他的回答投了赞成票。
      猜你喜欢
      • 2011-08-06
      • 1970-01-01
      • 2014-05-02
      • 1970-01-01
      • 2021-03-02
      • 1970-01-01
      • 2015-06-10
      • 2013-11-14
      • 2016-02-05
      相关资源
      最近更新 更多