我试图实现搜索与所有匹配搜索的谷歌铬样型以黄色突出显示和当前的匹配橙色高亮显示,并有可能与转移输入或向后+ Enter键向前导航。我使用Swing组件是Netbeans的摇摆大纲基本上看起来像一个JTree表。它的工作原理,直到轮廓通过单击任何列进行排序。在这个例子中,只有一个列。
为了使我们所需要的轮廓罐子从位于这里的Netbeans的分配这个例子中工作的NetBeans \平台\模块\为org-netbeans-摆动outline.jar。另一种选择是把这个摇篮构建文件(的build.gradle)在摇篮项目的根目录:
plugins {
id 'java-library'
}
dependencies {
compile 'uk.gov.nationalarchives.thirdparty.netbeans:org-netbeans-swing-outline:7.2'
}
repositories {
mavenCentral()
}
树模型有把搜索到列表的搜索功能findNodesWithPattern:
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.regex.Pattern;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
public class TestTreeModel extends DefaultTreeModel {
private static final long serialVersionUID = 1L;
public TestTreeModel() {
super(buildModel());
}
private static TreeNode buildModel() {
DefaultMutableTreeNode root = new DefaultMutableTreeNode("");
for (int i = 0; i < 3; i++) {
DefaultMutableTreeNode node = new DefaultMutableTreeNode("test" + i);
for (int j = 0; j < 3; j++) {
node.add(new DefaultMutableTreeNode("subtest" + j));
}
root.add(node);
}
return root;
}
@Override
public DefaultMutableTreeNode getRoot() {
return (DefaultMutableTreeNode) super.getRoot();
}
public List<TreeNode> findNodesMatchingPattern(Pattern pattern) {
List<TreeNode> matchingNodes = new ArrayList<>();
findNodesWithpattern(matchingNodes, getRoot(), pattern);
return matchingNodes;
}
private void findNodesWithpattern(List<TreeNode> matchingNodes, TreeNode node, Pattern pattern) {
if (pattern.matcher(node.toString()).find()) {
matchingNodes.add(node);
}
Enumeration<DefaultMutableTreeNode> children = node.children();
while (children.hasMoreElements()) {
findNodesWithpattern(matchingNodes, children.nextElement(), pattern);
}
}
}
还有,其定义了一个名为值一列与所述对象的哈希码的行模型(用于演示目的只)
import org.netbeans.swing.outline.RowModel;
public class TestRowModel implements RowModel {
@Override
public Class getColumnClass(int column) {
return Integer.class;
}
@Override
public int getColumnCount() {
return 1;
}
@Override
public String getColumnName(int column) {
return "Value";
}
@Override
public Object getValueFor(Object node, int column) {
return node.hashCode();
}
@Override
public boolean isCellEditable(Object node, int column) {
return false;
}
@Override
public void setValueFor(Object node, int column, Object value) {
// do nothing for now
}
}
渲染它负责在黄色或橙色突出:
import java.awt.Color;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import org.netbeans.swing.outline.RenderDataProvider;
public class TestRenderData implements RenderDataProvider {
private String searchPattern;
private TreeNode currentMatch;
@Override
public java.awt.Color getBackground(Object o) {
return null;
}
@Override
public String getDisplayName(Object o) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) o;
if (searchPattern == null || searchPattern.length() == 0) {
return node.toString();
}
try {
Pattern pattern = Pattern.compile("(" + searchPattern + ")");
Matcher matcher = pattern.matcher(node.toString());
Color bgColor = Color.YELLOW;
if (matcher.find()) {
if (node == currentMatch) {
bgColor = Color.ORANGE;
}
}
String bgHexColor = Integer.toHexString(bgColor.getRGB() & 0xffffff);
String replacement = matcher.replaceAll("<span style=\"background-color: #" + bgHexColor + "\">$1</span>");
return "<html>" + replacement + "</html>";
} catch (PatternSyntaxException e) {
return node.toString();
}
}
@Override
public java.awt.Color getForeground(Object o) {
return null;
}
@Override
public javax.swing.Icon getIcon(Object o) {
return null;
}
@Override
public String getTooltipText(Object o) {
return null;
}
@Override
public boolean isHtmlDisplayName(Object o) {
return false;
}
public void setSearchPattern(String searchPattern) {
this.searchPattern = searchPattern;
}
public void setCurrentMatch(TreeNode currentMatch) {
this.currentMatch = currentMatch;
}
}
主类构建具有快速过滤(非匹配的节点被过滤掉),并且触发搜索按键侦听轮廓。当回车键被输入,它增加一个计数器(nthMatch)和指数nthMatch在橙渲染highited当前匹配。
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Enumeration;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuBar;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import org.netbeans.swing.etable.QuickFilter;
import org.netbeans.swing.outline.DefaultOutlineModel;
import org.netbeans.swing.outline.Outline;
import org.netbeans.swing.outline.OutlineModel;
public class MainFrame extends JFrame {
private static final long serialVersionUID = 1L;
public MainFrame() {
TestTreeModel treeMdl = new TestTreeModel();
OutlineModel mdl = DefaultOutlineModel.createOutlineModel(treeMdl, new TestRowModel(), true, "Test");
Outline outline = new Outline();
TestRenderData renderData = new TestRenderData();
outline.setRenderDataProvider(renderData);
outline.setRootVisible(false);
outline.setModel(mdl);
JScrollPane jScrollPane1 = new JScrollPane(outline);
jScrollPane1.setViewportView(outline);
JMenuBar mb = new JMenuBar();
JLabel searchPatternLabel = new JLabel(" Search : ");
mb.add(searchPatternLabel);
JTextField searchPatternTextField = new JTextField();
searchPatternLabel.setLabelFor(searchPatternTextField);
outline.setQuickFilter(0, new QuickFilter() {
@Override
public boolean accept(Object aValue) {
if (searchPatternTextField.getText() == null || searchPatternTextField.getText().length() == 0) {
return true;
}
if (aValue instanceof DefaultMutableTreeNode) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) aValue;
Enumeration<DefaultMutableTreeNode> children = node.children();
while (children.hasMoreElements()) {
DefaultMutableTreeNode child = (DefaultMutableTreeNode) children.nextElement();
if (accept(child)) {
return true;
}
}
try {
Pattern searchPattern = Pattern.compile(searchPatternTextField.getText());
return searchPattern.matcher(node.toString()).find();
} catch (PatternSyntaxException ex) {
return true;
}
}
return false;
}
});
mb.add(searchPatternTextField);
setJMenuBar(mb);
getContentPane().add(jScrollPane1);
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
searchPatternTextField.addKeyListener(new KeyAdapter() {
private int nthMatch = 0;
@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
if (e.isShiftDown()) {
nthMatch--;
} else {
nthMatch++;
}
}
try {
Pattern searchPattern = Pattern.compile(searchPatternTextField.getText());
List<TreeNode> matchingNodes = treeMdl.findNodesMatchingPattern(searchPattern);
if (matchingNodes.size() > 0) {
if (nthMatch >= matchingNodes.size()) {
nthMatch = 0;
}
if (nthMatch < 0) {
nthMatch = 0;
}
TreeNode matchingNode = matchingNodes.get(nthMatch);
renderData.setCurrentMatch(matchingNode);
TreePath matchingNodePath = new TreePath(((DefaultMutableTreeNode) matchingNode).getPath());
outline.expandPath(matchingNodePath);
outline.scrollRectToVisible(outline.getPathBounds(matchingNodePath));
renderData.setSearchPattern(searchPatternTextField.getText());
}
} catch (PatternSyntaxException ex) {
}
//outline.repaint();
treeMdl.nodeChanged(treeMdl.getRoot());
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new MainFrame();
}
});
}
}
作为一个基本的情况下,我找“测试”反复按Enter键。搜索结果的顺序乱了,只要点击排序列。有迹象表明,似乎做一个索引映射和2种继承的方法convertRowIndexToModel和convertRowIndexToView大纲,但我不知道如何使用它们。
每当搜索领域的变化,只是告知新的搜索模式的渲染器。这将需要亮点,在黄色 - 为 - 您 - 类型部分护理:
searchPatternTextField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void removeUpdate(DocumentEvent e) {
renderData.setSearchPattern(searchPatternTextField.getText());
treeMdl.nodeChanged(treeMdl.getRoot());
}
@Override
public void insertUpdate(DocumentEvent e) {
renderData.setSearchPattern(searchPatternTextField.getText());
treeMdl.nodeChanged(treeMdl.getRoot());
}
@Override
public void changedUpdate(DocumentEvent e) {
renderData.setSearchPattern(searchPatternTextField.getText());
treeMdl.nodeChanged(treeMdl.getRoot());
}
});
然后监听输入和Shift +回车键。只是查找在视图先前,当前和下一个匹配的节点:
searchPatternTextField.addKeyListener(new KeyAdapter() {
private void showMatchingNode(TreeNode node) {
renderData.setCurrentMatch(node);
TreePath matchingNodePath = new TreePath(((DefaultMutableTreeNode) node).getPath());
outline.expandPath(matchingNodePath);
outline.scrollRectToVisible(outline.getPathBounds(matchingNodePath));
}
public TreeNode findNextMatchingNode(boolean lookForPrevious) {
try {
Pattern searchPattern = Pattern.compile(searchPatternTextField.getText());
boolean currentMatchFound = false;
TreeNode previousMatch = null;
for (int i = 0; i < outline.getRowCount(); i++) {
TreeNode node = (TreeNode) outline.getValueAt(i, 0);
if (node == renderData.getCurrentMatch()) {
currentMatchFound = true;
if (previousMatch != null && lookForPrevious) {
return previousMatch;
}
} else if (searchPattern.matcher(node.toString()).find()) {
if (renderData.getCurrentMatch() == null || (currentMatchFound && !lookForPrevious)) {
return node;
}
previousMatch = node;
}
}
} catch (PatternSyntaxException ex) {
}
return null;
}
@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
TreeNode node = findNextMatchingNode(e.isShiftDown());
if (node != null) {
showMatchingNode(node);
}
treeMdl.nodeChanged(treeMdl.getRoot());
}
}
});