在 JTextArea JAVA SWING 中突出显示 next/previous 匹配项的 JButton

JButton that highlights next/previous match in JTextArea JAVA SWING

我正在尝试在我的 Java Swing 应用程序中实现在 JTextArea 中搜索特定单词的按钮。谁能帮我实现按钮来突出显示下一场和上一场比赛?请同时查看我的搜索按钮代码。现在它工作正常。

PS。我想在新线程中使用 运行 searchButton。这样可以吗???

searchButton.addActionListener(e -> new Thread(() -> {
        int pos = 0;
        // Get the text to find...convert it to lower case for eaiser comparision
        String find = searchField.getText().toLowerCase();
        // Focus the text area, otherwise the highlighting won't show up
        textArea.requestFocusInWindow();
        // Make sure we have a valid search term
        if (find != null && find.length() > 0) {
            Document document = textArea.getDocument();
            int findLength = find.length();
            try {
                boolean found = false;
                // Rest the search position if we're at the end of the document
                if (pos + findLength > document.getLength()) {
                    pos = 0;
                }
                // While we haven't reached the end...
                // "<=" Correction
                while (pos + findLength <= document.getLength()) {
                    // Extract the text from the docuemnt
                    String match = document.getText(pos, findLength).toLowerCase();
                    // Check to see if it matches or request
                    if (match.equals(find)) {
                        found = true;
                        break;
                    }
                    pos++;
                }
                // Did we find something...
                if (found) {
                    // Get the rectangle of the where the text would be visible...
                    Rectangle viewRect = textArea.modelToView(pos);
                    // Scroll to make the rectangle visible
                    textArea.scrollRectToVisible(viewRect);
                    // Highlight the text
                    textArea.setCaretPosition(pos + findLength);
                    textArea.select(pos, pos + findLength);
                    textArea.grabFocus();

                }

            } catch (Exception exp) {
                exp.printStackTrace();
            }
        }
    }));

有两种方法可以在文本中搜索 JTextArea 中的匹配项:

  1. 在文档文本上使用 String.indexOf(idx) [forward] 和 String.lastIndexOf(idx) [backward],其中 idx 是当前插入符位置.如果您不希望搜索区分大小写,您可能还想在搜索文本和文档文本中使用 String.toUppercase / toLowercase。

  2. 使用Matcher/Pattern进行正则表达式搜索。这是更强大但更复杂的解决方案。仅供参考,我正在努力推出一个 DHTML 解决方案,并且在最长的时间内我想包括正则表达式搜索。但最后我没有——我认为客户(除非他们可能是内部的)不关心学习如何编写正则表达式

  1. 不要使用线程。您仅将 Thread 用于耗时的任务。搜索文本字符串不是一项耗时的任务。此外,需要在 EDT 上完成对 Swing 组件的更新。所以你希望突出显示在 EDT 上完成。

  2. 不要使用 grabFocus()。您已经使用了 requestFocusInWindow() ,这是正确的使用方法。

  3. 使用String.indexOf(…)方法(如@ControlAltDel所建议)。那么就不需要循环代码了。您只需从当前插入符号位置搜索文本,您要么找到该词,要么找不到。

为了它的价值,我碰巧有旧代码可以做到这一点:

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;

public class TextComponentFindNext extends JFrame implements ActionListener
{
    JTextComponent textComponent;
    JTextField textField;

    public TextComponentFindNext()
        throws Exception
    {
        textComponent = new JTextPane();
        JScrollPane scrollPane = new JScrollPane( textComponent );
        scrollPane.setPreferredSize( new Dimension(500, 400) );
        getContentPane().add(scrollPane, BorderLayout.NORTH);

        textField = new JTextField(10);
        textField.setText("im");
        textField.addActionListener( this );
        getContentPane().add(textField, BorderLayout.WEST);

        JButton button = new JButton("Find Next");
        button.addActionListener( this );
        getContentPane().add(button, BorderLayout.EAST);

        FileReader reader = new FileReader( "TextComponentFindNext.java" );
        BufferedReader br = new BufferedReader(reader);
        textComponent.read(br, null);
        br.close();
    }

    public void actionPerformed(ActionEvent e)
    {
        String searchString = "";

        //  this works
        try
        {
            Document doc = textComponent.getDocument();
            searchString = doc.getText(0, doc.getLength());
        }
        catch(BadLocationException ble) {}

        //  this doesn't work
//      searchString = textComponent.getText();

        int offset = textComponent.getCaretPosition();
        String searchText = textField.getText();

        int start = searchString.indexOf(searchText, offset);

        if (start != -1)
        {
            textComponent.select(start, start + searchText.length());
            textComponent.requestFocusInWindow();
        }
    }

    public static void main(String[] args)
        throws Exception
    {
        JFrame frame = new TextComponentFindNext();
        frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible(true);
    }
}

不需要滚动逻辑,选中文本后会自动滚动。

如果您想要滚动,可以 "center" 包含文本的行。查看 Text Utilities 以获取一些帮助您执行此操作的方法。

注意,最好从文档中获取文本,而不是组件。文档中的文本仅包含一个“\n”字符串作为行尾字符串。这意味着它适用于 JTextArea 和 JTextPane。请参阅:Text and New Lines 了解更多信息。