我正试图在我的Java Swing应用程序中实现在JTextArea中搜索特定单词的按钮。谁能帮我实现高亮显示下一个和上一个匹配的按钮?请查看我的searchbutton的代码。现在它工作得很好。
PS.我想在新的应用程序中运行searchButton。我想在new Thread中运行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();
}
}
}));
不要使用线程。你只在耗时的任务中使用线程。搜索一个文本字符串不是一个耗时的任务。另外,Swing组件的更新需要在EDT上完成。所以你希望高亮显示是在EDT上完成的。
不要使用 grabFocus()。你已经使用了 requestFocusInWindow(),这是正确的方法。
使用 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);
}
}
不需要滚动逻辑,当文本被选中时,它会自动滚动。
如果你想在滚动时玩点花样,你可以将包含文本的行 "居中"。请看 文本工具 以获得一些允许你这样做的辅助方法。
注意,最好是从Document中获取文本,而不是组件。从Document中获取的文本只包含一个"\n "字符串作为行尾字符串。这意味着它将同时适用于JTextArea和JTextPane。请看。文本和新行 获取更多信息。
有两种方法可以在你的JTextArea中搜索匹配的文本。
使用String.indexOf(idx) [forward]和String.lastIndexOf(idx) [backward]来搜索文档文本,其中: idx
是当前的小数点位置,也可以使用String.toUppercase toLowercase对搜索文本和文档文本进行大小写区分。如果您不想让搜索结果区分大小写,您也可以在搜索文本和文档文本上使用String.toUppercase toLowercase。
使用MatcherPattern进行正则表达式搜索。这是更强大但更复杂的解决方案。顺便说一下,我正在努力推出一个DHTML解决方案,很长时间以来,我都想加入正则搜索。但最终我没有这样做--我认为客户(除非他们是内部也许)并不关心学习如何编写regex的问题