2

ここ数日、私は小さなテキスト エディタにハイライト機能を実装しようとしてきました。何らかの理由で、奇妙な結果が得られます。

ここに画像の説明を入力

与えられた例では、それぞれの "dolor" を強調表示する必要があります。最初の出現は正しく検出され、強調表示されますが、次の出現は正しくありません。

これまでに書いたコードは次のとおりです。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.DefaultHighlighter.DefaultHighlightPainter;
import javax.swing.text.DefaultStyledDocument;

/**
 * Highlighting created on 04.11.2013<br>
 * <br>
 * Specification:<br>
 */
public class Highlighting extends JFrame implements MouseListener {

    private JScrollPane scrollPane;
    private JTextPane textPane;

    private DefaultHighlighter highlighter;
    private DefaultHighlightPainter painter;

    public static void main(String[] args) {
        new Highlighting().setVisible(true);
    }

    /**
     * 
     */
    public Highlighting() {
        this.initialize();
        this.build();
        this.configure();
    }

    /**
     *
     */
    public void initialize() {
        this.scrollPane = new JScrollPane();
        this.textPane = new JTextPane();
        this.highlighter = new DefaultHighlighter();
        this.painter = new DefaultHighlightPainter(Color.RED);
    }

    /**
     *
     */
    public void build() {
        this.add(this.scrollPane);
    }

    /**
     *
     */
    public void configure() {
        this.scrollPane.setViewportView(this.textPane);
        this.textPane.setHighlighter(this.highlighter);
        this.textPane.addMouseListener(this);
        this.textPane.setDocument(new DefaultStyledDocument());

        this.setPreferredSize(new Dimension(400, 500));
        this.pack();
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    /**
     * 
     */
    private void highlight() {
        this.highlighter.removeAllHighlights();

        String selectedText = this.textPane.getSelectedText();
        String text = this.textPane.getText();

        int wordlength = selectedText.length();

        int index = 0;
        while ((index = text.indexOf(selectedText, index)) != -1) {

            try {
                this.highlighter.addHighlight(index, index + wordlength, this.painter);
            } catch (BadLocationException e) {
                e.printStackTrace();
            }

            index += wordlength;
        }
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        if (e.getClickCount() == 2) {
            this.highlight();
        }
    }

    @Override
    public void mousePressed(MouseEvent e) {}

    @Override
    public void mouseReleased(MouseEvent e) {}

    @Override
    public void mouseEntered(MouseEvent e) {}

    @Override
    public void mouseExited(MouseEvent e) {}

}

これは行区切り記号 ( \r\n) と関係がありますか?

4

2 に答える 2

9

Aと AJTextComponentの実装は異なります。を使用して、ドキュメントのコンテンツ (テキスト) を に書き込み、書式を設定してテキストを返し、行/段落の区切りをドキュメントに挿入します。ただし、次の方法でドキュメントのコンテンツを直接返します。getText()JTextPane/JEditorPanegetText()JTextPane/JEditorPaneEditorKitStringWriterJTextCompoent

document.getText(0, document.getLength());

jTextPane1.getText().length()長さ :とを比較してみると、よりよく理解できますjTextPane1().getDocument().getLength()

次のように文字列を挿入して長さの違いを再現します。

DefaultStyleDocument.insertString(0, str, primaryStyle)

when str = "I\n not"   ; document length = 6, getText().length = 7
when str = "I\r\n not" ; document length = 7, getText().length = 8
when str = "I\n\n not" ; document length = 7, getText().length = 9!

したがって、ハイライト テキスト プログラムで、次を使用してコンテンツ テキストを読んでみてください。

DefaultStyledDocument document = (DefaultStyledDocument) jTextPane1.getDocument();
try {
    contText = document.getText(0, document.getLength());
} catch (BadLocationException ex) {
     Logger.getLogger(JTextPaneTest.class.getName()).log(Level.SEVERE, null, ex);
 }

contText次に、あなたが行っていたように、選択したテキスト位置を検索すると、準備が整います。なぜなら、位置オフセットにhighlighter.addHighlight(int p0, int p1, Highlighter.HighlightPainter p)を使用するからです。document

使用CaretListener:

テキスト選択時に強調表示するにはCaretListener、マウスとキーボードの選択処理コードをまったく追加する必要がないため、を使用することをお勧めします。

ここに画像の説明を入力

jTextPane1.addCaretListener(new CaretListener() {
        public void caretUpdate(CaretEvent evt) {
            if(evt.getDot() == evt.getMark())return;

    JTextPane txtPane = (JTextPane) evt.getSource();
    DefaultHighlighter highlighter = (DefaultHighlighter) txtPane.getHighlighter();
    highlighter.removeAllHighlights();
    DefaultHighlightPainter hPainter = new DefaultHighlightPainter(new Color(0xFFAA00));
    String selText = txtPane.getSelectedText();
    String contText = "";// = jTextPane1.getText();

    DefaultStyledDocument document = (DefaultStyledDocument) txtPane.getDocument();

    try {
        contText = document.getText(0, document.getLength());
    } catch (BadLocationException ex) {
        Logger.getLogger(JTextPaneTest.class.getName()).log(Level.SEVERE, null, ex);
    }

    int index = 0;

    while((index = contText.indexOf(selText, index)) > -1){

        try {
            highlighter.addHighlight(index, selText.length()+index, hPainter);
            index = index + selText.length();
        } catch (BadLocationException ex) {
            Logger.getLogger(JTextPaneTest.class.getName()).log(Level.SEVERE, null, ex);
           //System.out.println(index);
        }
       }
        }
    });
于 2013-11-04T15:22:43.860 に答える
4

たとえば、次を参照してください。

  • ハイライターの消し方highlighter.removeHighlight(h);

  • View.modelToView新しいハイライター

  • new line \nこのコードからは不可能な、内側の選択を決定する方法がわからないことに注意してください

ここに画像の説明を入力 ここに画像の説明を入力

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.UIManager;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Document;
import javax.swing.text.Highlighter;
import javax.swing.text.JTextComponent;
import javax.swing.text.LayeredHighlighter;
import javax.swing.text.Position;
import javax.swing.text.View;

public class HighlightExample {

    private JFrame f = new JFrame("Highlight example");
    private JPanel panel = new JPanel();
    private JTextPane textPane = new JTextPane();
    private JTextField tf = new JTextField("wrapping!");
    private String word;
    private Highlighter highlighter = new UnderlineHighlighter(null);

    public HighlightExample() {
        textPane.setHighlighter(highlighter);
        textPane.setText("This text pane contains no html. It supports letter wrapping, "
                + "\nThis text pane contains no html. It supports letter wrapping!, "
                + "\nThis text pane contains no html. It supports letter wrapping?, "
                + "\nThis text pane contains no html. It supports letter wrapping-, "
                + "\nThis text pane contains no html. It supports letter wrapping!, "
                + "\nThis text pane contains no html. It supports letter wrapping_, "
                + "\nThis text pane contains no html. It supports letter wrapping!, "
                + "\nThis text pane contains no html. It supports letter wrapping?, "
                + "\nThis text pane contains no html. It supports letter wrapping!, "
                + "\nThis text pane contains no html. It supports letter wrapping, "
                + "\nThis text pane contains no html. It supports letter wrapping!, "
                + "\nThis text pane contains no html. It supports letter wrapping-, "
                + "\nThis text pane contains no html. It supports letter wrapping!, "
                + "\nThis text pane contains no html. It supports letter wrapping?");
        panel.setLayout(new BorderLayout());
        panel.add(new JLabel("Enter word, then press ENTER key: "), "West");
        panel.add(tf, "Center");
        /*try {
         textPane.read(new FileReader("links1.html"), null);
         } catch (Exception e) {
         System.out.println("Failed to load file " + args[0]);
         System.out.println(e);
         }*/
        final WordSearcher searcher = new WordSearcher(textPane);
        tf.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent evt) {
                word = tf.getText().trim();
                int offset = searcher.search(word);
                if (offset != -1) {
                    try {
                        textPane.scrollRectToVisible(textPane
                                .modelToView(offset));
                    } catch (BadLocationException e) {
                    }
                }
            }
        });
        textPane.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent evt) {
                searcher.search(word);
            }

            @Override
            public void removeUpdate(DocumentEvent evt) {
                searcher.search(word);
            }

            @Override
            public void changedUpdate(DocumentEvent evt) {
            }
        });
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(panel, "South");
        f.add(new JScrollPane(textPane), "Center");
        f.setSize(400, 400);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        UIManager.put("TextPane.caretForeground", Color.yellow);
        UIManager.put("TextPane.selectionBackground", Color.green);
        UIManager.put("TextPane.selectionForeground", Color.blue);
        /*try {
         UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
         } catch (Exception evt) {
         }*/
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new HighlightExample();
            }
        });
    }
}

// A simple class that searches for a word in
// a document and highlights occurrences of that word
class WordSearcher {

    protected JTextComponent comp;
    protected Highlighter.HighlightPainter painter;

    public WordSearcher(JTextComponent comp) {
        this.comp = comp;
        this.painter = new UnderlineHighlighter.UnderlineHighlightPainter(Color.red);
    }

    // Search for a word and return the offset of the first occurrence. 
    // Highlights are added for all occurrences found.
    public int search(String word) {
        int firstOffset = -1;
        Highlighter highlighter = comp.getHighlighter();
        // Remove any existing highlights for last word
        Highlighter.Highlight[] highlights = highlighter.getHighlights();
        for (int i = 0; i < highlights.length; i++) {
            Highlighter.Highlight h = highlights[i];
            if (h.getPainter() instanceof UnderlineHighlighter.UnderlineHighlightPainter) {
                highlighter.removeHighlight(h);
            }
        }
        if (word == null || word.equals("")) {
            return -1;
        }
        String content = null; // Look for the word we are given - insensitive search
        try {
            Document d = comp.getDocument();
            content = d.getText(0, d.getLength()).toLowerCase();
        } catch (BadLocationException e) {
            return -1; // Cannot happen
        }
        word = word.toLowerCase();
        int lastIndex = 0;
        int wordSize = word.length();
        while ((lastIndex = content.indexOf(word, lastIndex)) != -1) {
            int endIndex = lastIndex + wordSize;
            try {
                highlighter.addHighlight(lastIndex, endIndex, painter);
            } catch (BadLocationException e) {
                // Nothing to do
            }
            if (firstOffset == -1) {
                firstOffset = lastIndex;
            }
            lastIndex = endIndex;
        }
        return firstOffset;
    }
}

class UnderlineHighlighter extends DefaultHighlighter {

    protected static final Highlighter.HighlightPainter sharedPainter = new UnderlineHighlightPainter(null);// Shared painter used for default highlighting   
    protected Highlighter.HighlightPainter painter; // Painter used for this highlighter

    public UnderlineHighlighter(Color c) {
        painter = (c == null ? sharedPainter : new UnderlineHighlightPainter(c));
    }

    // Convenience method to add a highlight with the default painter.
    public Object addHighlight(int p0, int p1) throws BadLocationException {
        return addHighlight(p0, p1, painter);
    }

    @Override
    public void setDrawsLayeredHighlights(boolean newValue) {
        if (newValue == false) {// Illegal if false - we only support layered highlights
            throw new IllegalArgumentException(
                    "UnderlineHighlighter only draws layered highlights");
        }
        super.setDrawsLayeredHighlights(true);
    }

    // Painter for underlined highlights
    public static class UnderlineHighlightPainter extends LayeredHighlighter.LayerPainter {

        protected Color color; // The color for the underline

        public UnderlineHighlightPainter(Color c) {
            color = c;
        }

        @Override
        public void paint(Graphics g, int offs0, int offs1, Shape bounds,
                JTextComponent c) {// Do nothing: this method will never be called            
        }

        @Override
        public Shape paintLayer(Graphics g, int offs0, int offs1, Shape bounds,
                JTextComponent c, View view) {
            g.setColor(color == null ? c.getSelectionColor() : color);
            Rectangle alloc = null;
            if (offs0 == view.getStartOffset() && offs1 == view.getEndOffset()) {
                if (bounds instanceof Rectangle) {
                    alloc = (Rectangle) bounds;
                } else {
                    alloc = bounds.getBounds();
                }
            } else {
                try {
                    Shape shape = view.modelToView(offs0, Position.Bias.Forward, offs1,
                            Position.Bias.Backward, bounds);
                    alloc = (shape instanceof Rectangle) ? (Rectangle) shape : shape.getBounds();
                } catch (BadLocationException e) {
                    return null;
                }
            }
            FontMetrics fm = c.getFontMetrics(c.getFont());
            int baseline = alloc.y + alloc.height - fm.getDescent() + 1;
            g.drawLine(alloc.x, baseline, alloc.x + alloc.width, baseline);
            g.drawLine(alloc.x, baseline + 1, alloc.x + alloc.width, baseline + 1);
            return alloc;
        }
    }
}
于 2013-11-04T11:46:08.953 に答える