JTree 如何實現高亮節點,如何實現排選,如何實現滑鼠移動高亮?
阿新 • • 發佈:2018-11-02
先上圖,看看是不是你們想要的類似效果:
滑鼠移動到樹節點所在行的任意位置,實現高亮。
滑鼠點選到樹節點所在行的任意位置,實現高亮並選中該節點。
網上找了好久都沒找到這樣的實現方法,可能是swing 現在用的人太少了。
在這裡希望能為想要用swing JTree的朋友提供一點參考。
下面是我的我的JTree 類的完整程式碼,裡面有一些資料邏輯是我係統中的,所以你們只需要參考就行,不要完全複製
package cn.tz.cj.ui; import cn.tz.cj.bo.Auth; import cn.tz.cj.entity.NoteBook; import cn.tz.cj.service.NoteBookService; import cn.tz.cj.service.NoteService; import cn.tz.cj.service.intf.INoteBookService; import cn.tz.cj.service.intf.INoteService; import javax.swing.*; import javax.swing.tree.*; import java.awt.*; import java.awt.event.*; import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.Set; public class NoteBookTree extends JTree { private static final String ROOTNODE_NAME = "NoteBooks"; private static final Color SELECTED_BACKGROUD = new Color(115, 115, 115); private static final Color MOUSE_BACKGROUD = new Color(222, 222, 222); private static final int TREENODE_HIGH_LINE = 30; private INoteBookService noteBookService = new NoteBookService(); private INoteService noteService = new NoteService(); private MainForm mainForm; private int mouseRow; public NoteBookTree(MainForm mainForm) { this.mainForm = mainForm; init(); } private void init() { // 資料載入 refresh(null, null, null); // 事件繫結 bindEvent(); // 樹樣式渲染 this.setCellRenderer(new MyTreeCellRenderer()); this.addFocusListener(fl); this.setOpaque(false); this.setRowHeight(TREENODE_HIGH_LINE); this.setRootVisible(false); this.setShowsRootHandles(true); } public void refresh(String key, String lastSelectedNotebook, String lastSelectedNote) { loadTree(key, lastSelectedNotebook, lastSelectedNote); findInTree();// 設定自動選中 mainForm.refreshNoteTools(); // 主頁右邊內容匹配顯示 } private void loadTree(String key, String lastSelectedNotebook, String lastSelectedNote) { Auth.getInstance().setSearchKey(key); Auth.getInstance().setSelectedNoteBookName(lastSelectedNotebook); Auth.getInstance().setSelectedNoteName(lastSelectedNote); DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(ROOTNODE_NAME); List<NoteBook> noteBooks = noteBookService.getNoteBooks(); Collections.sort(noteBooks); if (key == null || key.trim().equals("")) { for (NoteBook nb : noteBooks) { String notebook = nb.getNotebook(); DefaultMutableTreeNode notebookNode = new DefaultMutableTreeNode(notebook); Set<String> notesTitlesByNoteBook = noteService.getNotesTitlesByNoteBook(notebook); for (String title : notesTitlesByNoteBook) { DefaultMutableTreeNode noteNode = new DefaultMutableTreeNode(title); notebookNode.add(noteNode); } rootNode.add(notebookNode); } } else { boolean isRecordFirstSelected = false; for (NoteBook nb : noteBooks) { String notebook = nb.getNotebook(); DefaultMutableTreeNode notebookNode = new DefaultMutableTreeNode(notebook); Set<String> notesTitlesByNoteBook = noteService.getNotesTitlesByNoteBook(notebook); boolean match = false; for (String title : notesTitlesByNoteBook) { String a = title.toLowerCase(); String b = key.toLowerCase(); if (a.contains(b)) { DefaultMutableTreeNode noteNode = new DefaultMutableTreeNode(title); if (!isRecordFirstSelected) { if (lastSelectedNote == null && lastSelectedNotebook == null) { Auth.getInstance().setSelectedNoteBookName(notebook); Auth.getInstance().setSelectedNoteName(title); } isRecordFirstSelected = true; } notebookNode.add(noteNode); match = true; } } if (match || notebook.toLowerCase().contains(key.toLowerCase())) { rootNode.add(notebookNode); } } } TreeModel treeModel = new DefaultTreeModel(rootNode); this.setModel(treeModel); if (key != null && !key.trim().equals("")) { expandAll(this, new TreePath(rootNode), true); } } private void bindEvent() { this.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { int y = (int) e.getPoint().getY(); TreePath selPath = getPathForRow(matchRow(y)); setSelected(selPath); if (e.getButton() == e.BUTTON3) { if (selPath != null) { int level = selPath.getPathCount(); String sel = selPath.getLastPathComponent().toString(); if (level == 2) { noteBookMenu(sel).show(e.getComponent(), e.getX(), e.getY());//彈出右鍵選單 } else if (level == 3) { Object[] path = selPath.getPath(); noteMenu(path[1].toString(), sel).show(e.getComponent(), e.getX(), e.getY());//彈出右鍵選單 } } } else if (e.getButton() == e.BUTTON1) { mouseClickSelected(selPath); } } }); this.addMouseMotionListener(new MouseMotionAdapter() { @Override public void mouseMoved(MouseEvent arg0) { int y = (int) arg0.getPoint().getY(); mouseRow = matchRow(y); NoteBookTree.this.repaint(); } }); } private void mouseClickSelected(TreePath selPath) { if (selPath != null) { // mainForm.getEditor().autoSave(); int level = selPath.getPathCount(); Object[] path = selPath.getPath(); switch (level) { case 2: Auth.getInstance().setSelectedNoteBookName(path[1].toString()); Auth.getInstance().setSelectedNoteName(null); break; case 3: Auth.getInstance().setSelectedNoteBookName(path[1].toString()); Auth.getInstance().setSelectedNoteName(path[2].toString()); break; } if (this.isExpanded(selPath)) { this.collapsePath(selPath); } else { this.expandPath(selPath); } mainForm.refreshNoteTools(); } } private int matchRow(int y) { int r = -1; for (int i = 0; i < this.getRowCount(); i++) { Rectangle rowBounds = this.getRowBounds(i); int y1 = (int) rowBounds.getY(); int y2 = TREENODE_HIGH_LINE + (int) rowBounds.getY(); if (y >= y1 && y <= y2) { r = i; break; } } return r; } private JPopupMenu treeMenu() { JPopupMenu treeJPopupMenu = new JPopupMenu(); JMenuItem jMenuItem_addNotebook = new JMenuItem("新建筆記本"); jMenuItem_addNotebook.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { mainForm.getMouseLoading().startLoading(); onAddNotebook(); mainForm.getMouseLoading().stopLoading(); } }); treeJPopupMenu.add(jMenuItem_addNotebook); return treeJPopupMenu; } private JPopupMenu noteBookMenu(String notebookName) { JPopupMenu treeJPopupMenu = new JPopupMenu(); JMenuItem jMenuItem_addNote = new JMenuItem("新建筆記"); jMenuItem_addNote.setIcon(ImageIconMananger.NOTE.getImageIcon20_20()); jMenuItem_addNote.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { onAddNote(notebookName); } }); JMenuItem jMenuItem_rename = new JMenuItem("重新命名"); jMenuItem_rename.setIcon(ImageIconMananger.RENAME.getImageIcon20_20()); jMenuItem_rename.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { mainForm.getMouseLoading().startLoading(); String newName = (String) JOptionPane.showInputDialog(null, "", "請輸入筆記本的名稱", JOptionPane.QUESTION_MESSAGE, null, null, notebookName); if(!newName.equals(notebookName)){ noteBookService.rename(notebookName, newName); refresh(null, null, null); } mainForm.getMouseLoading().stopLoading(); } }); JMenuItem jMenuItem_remove = new JMenuItem("刪除筆記本"); jMenuItem_remove.setIcon(ImageIconMananger.DELETE.getImageIcon20_20()); jMenuItem_remove.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { mainForm.getMouseLoading().startLoading(); int i = JOptionPane.showConfirmDialog(null, "確定刪除筆記本[" + notebookName + "]?", "刪除筆記本", JOptionPane.YES_NO_OPTION); if (i == 0) { noteBookService.removeNoteBook(notebookName); refresh(null, null, null); } mainForm.getMouseLoading().stopLoading(); } }); treeJPopupMenu.add(jMenuItem_addNote); treeJPopupMenu.add(jMenuItem_rename); treeJPopupMenu.add(jMenuItem_remove); return treeJPopupMenu; } private JPopupMenu noteMenu(String notebookName, String noteName) { JPopupMenu treeJPopupMenu = new JPopupMenu(); JMenuItem jMenuItem_remove = new JMenuItem("刪除筆記"); jMenuItem_remove.setIcon(ImageIconMananger.DELETE.getImageIcon20_20()); jMenuItem_remove.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { mainForm.getMouseLoading().startLoading(); int i = JOptionPane.showConfirmDialog(null, "確定刪除筆記[" + noteName + "]?", "刪除筆記", JOptionPane.YES_NO_OPTION); if (i == 0) { noteService.removeNote(notebookName, noteName); refresh(null, null, null); } mainForm.getMouseLoading().stopLoading(); } }); treeJPopupMenu.add(jMenuItem_remove); return treeJPopupMenu; } /** * 定位選中的筆記 */ private void findInTree() { if (Auth.getInstance().getSelectedNoteBookName() == null) { return; } Object root = this.getModel().getRoot(); TreePath treePath = new TreePath(root); treePath = findInPath(treePath, Auth.getInstance().getSelectedNoteBookName(), Auth.getInstance().getSelectedNoteName()); setSelected(treePath); } private void setSelected(TreePath treePath) { if (treePath != null) { this.setSelectionPath(treePath); this.scrollPathToVisible(treePath); } } private TreePath findInPath(TreePath treePath, String notebookName, String noteName) { Object object = treePath.getLastPathComponent(); if (object == null) { return null; } String value = object.toString(); if (noteName != null && noteName.equals(value) && treePath.getParentPath().getLastPathComponent().toString().equals(notebookName)) { return treePath; } else if (noteName == null && notebookName.equals(value)) { return treePath; } else { TreeModel model = this.getModel(); int n = model.getChildCount(object); for (int i = 0; i < n; i++) { Object child = model.getChild(object, i); TreePath path = treePath.pathByAddingChild(child); path = findInPath(path, notebookName, noteName); if (path != null) { return path; } } return null; } } /** * 全部展開 * * @param tree * @param parent * @param expand */ private static void expandAll(JTree tree, TreePath parent, boolean expand) { // Traverse children TreeNode node = (TreeNode) parent.getLastPathComponent(); if (node.getChildCount() >= 0) { for (Enumeration e = node.children(); e.hasMoreElements(); ) { TreeNode n = (TreeNode) e.nextElement(); TreePath path = parent.pathByAddingChild(n); expandAll(tree, path, expand); } } // Expansion or collapse must be done bottom-up if (expand) { tree.expandPath(parent); } else { tree.collapsePath(parent); } } public void onAddNotebook() { String typeName = (String) JOptionPane.showInputDialog(null, "", "請輸入筆記本的名稱", JOptionPane.QUESTION_MESSAGE); if (typeName != null) { if (!typeName.equals("")) { if (typeName.length() <= 100) { noteBookService.addNoteBook(typeName); refresh(null, null, null); } else { JOptionPane.showMessageDialog(null, "筆記本名稱限制100字元!", "建立筆記本失敗", JOptionPane.WARNING_MESSAGE); } } else { JOptionPane.showMessageDialog(null, "筆記本名稱不能為空!", "建立筆記本失敗", JOptionPane.WARNING_MESSAGE); } } } public void onAddNote(String notebookName) { new EditForm(mainForm); } FocusListener fl = new FocusListener() { @Override public void focusGained(FocusEvent e) { e.getComponent().repaint(); } @Override public void focusLost(FocusEvent e) { e.getComponent().repaint(); } }; @Override public void paintComponent(Graphics g) { g.setColor(getBackground()); g.fillRect(0, 0, getWidth(), getHeight()); if (mouseRow > 0 && mouseRow < this.getRowCount()) { g.setColor(MOUSE_BACKGROUD); Rectangle r = getRowBounds(mouseRow); g.fillRect(0, r.y, getWidth(), r.height); g.drawRect(0, r.y, getWidth() - 1, r.height - 1); MyTreeCellRenderer.mouseEnter = true; MyTreeCellRenderer.mouseRow = mouseRow; } else { MyTreeCellRenderer.mouseEnter = false; } if (getSelectionCount() > 0) { g.setColor(SELECTED_BACKGROUD); for (int i : getSelectionRows()) { Rectangle r = getRowBounds(i); g.fillRect(0, r.y, getWidth(), r.height); } } super.paintComponent(g); if (getLeadSelectionPath() != null) { Rectangle r = getRowBounds(getRowForPath(getLeadSelectionPath())); g.setColor(SELECTED_BACKGROUD); g.drawRect(0, r.y, getWidth() - 1, r.height - 1); } } } class MyTreeCellRenderer extends DefaultTreeCellRenderer { private static final Color SELECTED_BACKGROUD = new Color(115, 115, 115); private static final Color MOUSE_BACKGROUD = new Color(222, 222, 222); public static boolean mouseEnter; public static int mouseRow; @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { //執行父類原型操作 JLabel l = (JLabel) super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); if (mouseEnter && !selected && mouseRow == row) { l.setBackground(mouseEnter ? MOUSE_BACKGROUD : tree.getBackground()); } else { l.setBackground(selected ? SELECTED_BACKGROUD : tree.getBackground()); } l.setOpaque(true); setText(value.toString()); setIcon(null); //得到每個節點的TreeNode DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; int level = node.getLevel(); switch (level) { case 1: setFont(new Font("SimSun", Font.BOLD, 16)); break; case 2: setFont(new Font("SimSun", Font.PLAIN, 14)); break; default: break; } return this; } }
滑鼠行選的核心是下面三段
this.addMouseMotionListener(new MouseMotionAdapter() { @Override public void mouseMoved(MouseEvent arg0) { int y = (int) arg0.getPoint().getY(); mouseRow = matchRow(y); NoteBookTree.this.repaint(); } });
private int matchRow(int y) { int r = -1; for (int i = 0; i < this.getRowCount(); i++) { Rectangle rowBounds = this.getRowBounds(i); int y1 = (int) rowBounds.getY(); int y2 = TREENODE_HIGH_LINE + (int) rowBounds.getY(); if (y >= y1 && y <= y2) { r = i; break; } } return r; }
@Override
public void paintComponent(Graphics g) {
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
if (mouseRow > 0 && mouseRow < this.getRowCount()) {
g.setColor(MOUSE_BACKGROUD);
Rectangle r = getRowBounds(mouseRow);
g.fillRect(0, r.y, getWidth(), r.height);
g.drawRect(0, r.y, getWidth() - 1, r.height - 1);
MyTreeCellRenderer.mouseEnter = true;
MyTreeCellRenderer.mouseRow = mouseRow;
} else {
MyTreeCellRenderer.mouseEnter = false;
}
if (getSelectionCount() > 0) {
g.setColor(SELECTED_BACKGROUD);
for (int i : getSelectionRows()) {
Rectangle r = getRowBounds(i);
g.fillRect(0, r.y, getWidth(), r.height);
}
}
super.paintComponent(g);
if (getLeadSelectionPath() != null) {
Rectangle r = getRowBounds(getRowForPath(getLeadSelectionPath()));
g.setColor(SELECTED_BACKGROUD);
g.drawRect(0, r.y, getWidth() - 1, r.height - 1);
}
}