我在JTextpane中打开文件时自动着色Java关键字

时间:2014-07-30 08:00:13

标签: java swing colors keyword jtextpane

我想将颜色应用于java关键字。当我打开一个文件时,它会在通知异常中提升尝试突变,程序没有完全显示,颜色也没有应用。 这是我的代码,

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FileDialog;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JInternalFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;

public class JavaKeywordsColor extends javax.swing.JFrame {

    private JTextPane textPane;
    private Color color = Color.BLACK;
    private int i = 0;
    private JPanel noWrapPanel;
    private JScrollPane scrollpane;
    private JTextField status;
    private StyledDocument d;
    private String[] keywords = {"import ", "class ", "int ", "public ", "private"};

    public JavaKeywordsColor() {
        initComponents();
    }

    private void initComponents() {
        tp = new javax.swing.JTabbedPane();
        jMenuBar1 = new javax.swing.JMenuBar();
        jMenu1 = new javax.swing.JMenu();
        Open = new javax.swing.JMenuItem();
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        jMenu1.setText("File");
        Open.setText("Open");
        Open.addActionListener(new java.awt.event.ActionListener() {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                OpenActionPerformed(evt);
            }
        });
        jMenu1.add(Open);
        jMenuBar1.add(jMenu1);
        setJMenuBar(jMenuBar1);
        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addComponent(tp, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE));
        layout.setVerticalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addComponent(tp, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 279, Short.MAX_VALUE));
        pack();
    }// </editor-fold>                        

    private void OpenActionPerformed(java.awt.event.ActionEvent evt) {
        FileDialog fd = new FileDialog(JavaKeywordsColor.this, "Select File", FileDialog.LOAD);
        fd.setVisible(true);
        String title;
        String sts;
        if (fd.getFile() != null) {
            sts = fd.getDirectory() + fd.getFile();
            title = fd.getFile();
            BufferedReader br = null;
            StringBuffer str = new StringBuffer("");
            try {
                br = new BufferedReader(new FileReader(sts));
                String line;
                try {
                    while ((line = br.readLine()) != null) {
                        str.append(line + "\n");
                    }
                } catch (IOException ex) {
                    Logger.getLogger(JavaKeywordsColor.class.getName()).log(Level.SEVERE, null, ex);
                }
            } catch (FileNotFoundException ex) {
                Logger.getLogger(JavaKeywordsColor.class.getName()).log(Level.SEVERE, null, ex);
            }
            String t = str.toString();
            final JInternalFrame internalFrame = new JInternalFrame("", true, true);
            textPane = new JTextPane();
            // textPane.setEditorKit(new WrapEditorKit());
            d = textPane.getStyledDocument();
            d.addDocumentListener(new DocumentListener() {
                @Override
                public void insertUpdate(DocumentEvent de) {
                    jColorActionPerformed(de);
                }

                @Override
                public void removeUpdate(DocumentEvent de) {
                    jColorActionPerformed(de);
                }

                @Override
                public void changedUpdate(DocumentEvent de) {
                    jColorActionPerformed(de);
                }
            });
            Document doc = textPane.getDocument();
            textPane.setFont(new java.awt.Font("Miriam Fixed", 0, 13));
            internalFrame.add(textPane);
            i += 1;
            internalFrame.setName("Doc" + i);
            this.add(new javax.swing.JScrollPane(textPane));
            noWrapPanel = new JPanel(new BorderLayout());
            noWrapPanel.add(textPane);
            scrollpane = new JScrollPane(noWrapPanel);
            internalFrame.add(scrollpane);
            internalFrame.setTitle(title);
            tp.add(internalFrame);
            tp.setSelectedIndex(i - 1);
            internalFrame.setVisible(true);
            textPane.setText(t);
        }
    }

    private void jColorActionPerformed(DocumentEvent evt) {
        replace(textPane);
    }

    public void replace(javax.swing.JTextPane jp) {
        int cur = jp.getCaretPosition();
        StyleContext sc = StyleContext.getDefaultStyleContext();
        AttributeSet aset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, Color.BLUE);
        for (int ii = 0; ii < keywords.length; ii++) {
            int fromIndex = 0;
            String msg = keywords[ii];
            int nol = 0;     //number of lines upto keyword
            int len = 1;
            while (len != -1) {
                len = jp.getText().indexOf(msg, fromIndex);
                jp.setSelectedTextColor(Color.RED);
                if (len != -1) {
                    try {
                        nol = countLine(jp.getText(0, len + 1));
                    } catch (BadLocationException ex) {
                        break;
                    }
                    fromIndex = len + msg.length();
                    System.out.println("len = " + len + " nol=" + nol);
                    len -= nol;
                    jp.select(len, len + msg.length());
                    System.out.println("Selected Text = " + jp.getSelectedText());
                    jp.replaceSelection("");
                    jp.setCaretPosition(len);
                    jp.setCharacterAttributes(aset, false);
                    jp.replaceSelection(msg);
                }
            }
        }
        aset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, Color.BLACK);
        jp.setCharacterAttributes(aset, false);
        jp.setCaretPosition(cur);
    }

    public int countLine(String str) {
        int n = 0;
        for (int ii = 0; ii < str.length(); ii++) {
            if (str.charAt(ii) == '\n') {
                n++;
            }
        }
        return n;
    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new JavaKeywordsColor().setVisible(true);
            }
        });
    }
    private javax.swing.JMenuItem Open;
    private javax.swing.JMenu jMenu1;
    private javax.swing.JMenuBar jMenuBar1;
    private javax.swing.JTabbedPane tp;
}

1 个答案:

答案 0 :(得分:2)

异常的消息非常清楚。在侦听器通知正在进行时,不允许您改变文档。原因很清楚:修改会触发新的通知,而在像你这样的程序中,会引发StackOverflowError或无限循环。它还暗示,在其他听众尚未了解旧的修改时,可能会报告更新的修改。

您必须将修改安排到以后的时间,并保护您的代码不会对您自己的修改做出反应。将更新安排到以后的时间也可以帮助用户快速键入时的​​性能,因为您不想在每个插入的字符上解析整个文档。

因此,您应该替换添加DocumentListener

的部分
d.addDocumentListener(new DocumentListener() {
    @Override
    public void insertUpdate(DocumentEvent de) {
        jColorActionPerformed(de);
    }

    @Override
    public void removeUpdate(DocumentEvent de) {
        jColorActionPerformed(de);
    }

    @Override
    public void changedUpdate(DocumentEvent de) {
        jColorActionPerformed(de);
    }
});

这样的事情:

final class UpdateTrigger implements DocumentListener, ActionListener {
  final Timer timer=new Timer(150, this);
  boolean enabled=true;
  UpdateTrigger() {
    timer.setRepeats(false);
  }
  public void insertUpdate(DocumentEvent e) {
    if(enabled) timer.restart();
  }
  public void removeUpdate(DocumentEvent e) {
    if(enabled) timer.restart();
  }
  public void changedUpdate(DocumentEvent e) {
    if(enabled) timer.restart();
  }
  public void actionPerformed(ActionEvent e) {
    enabled=false;
    try { jColorActionPerformed(null); }
    finally { enabled=true; }
  }
}
d.addDocumentListener(new UpdateTrigger());

您可能会发现您的代码有更多问题超出了您的问题范围。顺便说一句,只是突出显示关键字对于正确的语法突出显示是不够的。你需要一个能理解语法结构的解析器,特别是注释和String文字,即使是最小的突出显示。

您应该学习Chapter 3 of the The Java® Language Specification以获得完整的图片。