キーワードを強調表示する方法2
編集をしているとき、キーワードが入力されると自動的に強調表示されるモノを作ってみます。ドキュメントが変わったときには、DocumentListenerで通知してもらいます。
import java.awt.Color; import javax.swing.*; import javax.swing.event.*; import javax.swing.text.*; public class JTextPaneTest2 extends JFrame { JTextPane pane; JTextPaneTest2() { super("JTextPaneTest2"); setDefaultCloseOperation(EXIT_ON_CLOSE); setSize(640, 480); pane = new JTextPane(); StyledDocument doc = (StyledDocument) pane.getDocument(); doc.addDocumentListener(new DocListener()); getContentPane().add(pane); pane.setText("検索文字は「文字」と「String」です。\n"+ "大文字、小文字は区別しています。\n"+ "なので、Stringは引っかかっても、stringやSTRINGには引っかかりません。\n"+ "また単語ごとの検索もダメなので、SuperStringにも引っかかってしまいます。\n"+ "ソースファイルの強調表示をやろうとすると、\"文字列中の単語\"や\n"+ "/** コメント中の文字 */ なども考慮しなければならないので厄介。\n"+ "秀丸のように、正規表現を駆使したり、対象の言語にあった字句解析を行う必要があります。\n"+ "♪ねぇムーミン。こっち向いて。恥ずかしがら〜な〜いで〜。文字文字しな〜い〜で〜。♪"); invokeSetHighlight(); setVisible(true); } void setHighlight() { String text = pane.getText(); StyledDocument doc = (StyledDocument) pane.getDocument(); // すべての属性を消す SimpleAttributeSet plane = new SimpleAttributeSet(); doc.setCharacterAttributes(0, text.length(), plane, true); // キーワードを強調表示 SimpleAttributeSet attr = new SimpleAttributeSet(); //StyleConstants.setBold(attr, true); // 太字 //StyleConstants.setForeground(attr, Color.BLUE); // 文字の色 StyleConstants.setBackground(attr, Color.YELLOW); // 背景の色 // キーワードが見つかったら、属性をつける。 String[] keywords = {"文字", "String"}; for (int i=0; i<keywords.length; i++) { String keyword = keywords[i]; int pos = text.indexOf(keyword); while (pos != -1) { doc.setCharacterAttributes(pos, keyword.length(), attr, true); pos = text.indexOf(keyword, pos+keyword.length()); } } } void invokeSetHighlight() { // ドキュメント変更中に呼ぶと競合するので、処理後に呼ぶようにする。 SwingUtilities.invokeLater(new Runnable() { public void run() { setHighlight(); } }); } class DocListener implements DocumentListener { public void insertUpdate(DocumentEvent e) { System.out.println("insertUpdate(e)"+e); invokeSetHighlight(); } public void removeUpdate(DocumentEvent e) { System.out.println("removeUpdate(e)"+e); invokeSetHighlight(); } public void changedUpdate(DocumentEvent e) { System.out.println("changedUpdate(e)"+e); // 属性が変わったときは、何もしなくてよい。 } } public static void main(String[] args) { new JTextPaneTest2(); } }
入力するたびにキーワードに色がつくので、最近のエディタっぽいです。
ここではキーワードの検索に、StringクラスのindexOf(String)を使っています。
一般の文章だと、これでOKなのですが、プログラムのソースだと、これだけでは不十分です。
大文字、小文字は区別されるので、SQLなどでは使えません。また、プログラムの場合、文字列やコメントは別の色で表示したいですし、その中にキーワードがあってもそれは無視すべきです。単語ごとに色分けすべきなので、Word のようになるべきではありません。
そうなってくると、秀丸のように正規表現を駆使したり、その言語ごとに特化した字句解析を行う必要があります。話がややこしくなるので、ここではそれ以降の議論は行いません。
上記のプログラムでは、ドキュメントが変更されるたびに、全ドキュメントのキーワードを検索しなおしているので、ドキュメントが長かったり、キー入力が速い人だと、効率が悪くてレスポンスに影響が出るかもしれません。その場合は、「入力中はチェックせずに、入力が終わった1秒後にチェックする」とか、「入力した行(の前後)のみをチェックする」などの方法を取るべきかもしれません。