📄 basictreeui.java
字号:
completeUIUninstall(); } /** * Paints the specified component appropriate for the look and feel. This * method is invoked from the ComponentUI.update method when the specified * component is being painted. Subclasses should override this method and use * the specified Graphics object to render the content of the component. * * @param g * the Graphics context in which to paint * @param c * the component being painted; this argument is often ignored, but * might be used if the UI object is stateless and shared by multiple * components */ public void paint(Graphics g, JComponent c) { JTree tree = (JTree) c; if (currentVisiblePath == null) updateCurrentVisiblePath(); Rectangle clip = g.getClipBounds(); Insets insets = tree.getInsets(); if (clip != null && treeModel != null && currentVisiblePath != null) { int startIndex = tree.getClosestRowForLocation(clip.x, clip.y); int endIndex = tree.getClosestRowForLocation(clip.x + clip.width, clip.y + clip.height); paintVerticalPartOfLeg(g, clip, insets, currentVisiblePath); for (int i = startIndex; i <= endIndex; i++) { Object curr = currentVisiblePath.getPathComponent(i); boolean isLeaf = treeModel.isLeaf(curr); TreePath path = new TreePath(getPathToRoot(curr, 0)); boolean isExpanded = tree.isExpanded(path); Rectangle bounds = getPathBounds(tree, path); paintHorizontalPartOfLeg(g, clip, insets, bounds, path, i, isExpanded, false, isLeaf); paintRow(g, clip, insets, bounds, path, i, isExpanded, false, isLeaf); } } } /** * Ensures that the rows identified by beginRow through endRow are visible. * * @param beginRow * is the first row * @param endRow * is the last row */ protected void ensureRowsAreVisible(int beginRow, int endRow) { if (beginRow < endRow) { int temp = endRow; endRow = beginRow; beginRow = temp; } for (int i = beginRow; i < endRow; i++) { TreePath path = getPathForRow(tree, i); if (!tree.isVisible(path)) tree.makeVisible(path); } } /** * Sets the preferred minimum size. * * @param newSize * is the new preferred minimum size. */ public void setPreferredMinSize(Dimension newSize) { preferredMinSize = newSize; } /** * Gets the preferred minimum size. * * @returns the preferred minimum size. */ public Dimension getPreferredMinSize() { return preferredMinSize; } /** * Returns the preferred size to properly display the tree, this is a cover * method for getPreferredSize(c, false). * * @param c * the component whose preferred size is being queried; this argument * is often ignored but might be used if the UI object is stateless * and shared by multiple components * @return the preferred size */ public Dimension getPreferredSize(JComponent c) { return getPreferredSize(c, false); } /** * Returns the preferred size to represent the tree in c. If checkConsistancy * is true, checkConsistancy is messaged first. * * @param c * the component whose preferred size is being queried. * @param checkConsistancy * if true must check consistancy * @return the preferred size */ public Dimension getPreferredSize(JComponent c, boolean checkConsistancy) { // FIXME: checkConsistancy not implemented, c not used if(!validCachedPreferredSize) updateCachedPreferredSize(); return preferredSize; } /** * Returns the minimum size for this component. Which will be the min * preferred size or (0,0). * * @param c * the component whose min size is being queried. * @returns the preferred size or null */ public Dimension getMinimumSize(JComponent c) { Dimension min = getPreferredMinSize(); if (min == null) return new Dimension(); return min; } /** * Returns the maximum size for the component, which will be the preferred * size if the instance is currently in JTree or (0,0). * * @param c * the component whose preferred size is being queried * @return the max size or null */ public Dimension getMaximumSize(JComponent c) { if (c instanceof JTree) return ((JTree) c).getPreferredSize(); return new Dimension(); } /** * Messages to stop the editing session. If the UI the receiver is providing * the look and feel for returns true from * <code>getInvokesStopCellEditing</code>, stopCellEditing will be invoked * on the current editor. Then completeEditing will be messaged with false, * true, false to cancel any lingering editing. */ protected void completeEditing() { completeEditing(false, true, false); } /** * Stops the editing session. If messageStop is true, the editor is messaged * with stopEditing, if messageCancel is true the editor is messaged with * cancelEditing. If messageTree is true, the treeModel is messaged with * valueForPathChanged. * * @param messageStop * message to stop editing * @param messageCancel * message to cancel editing * @param messageTree * message to treeModel */ protected void completeEditing(boolean messageStop, boolean messageCancel, boolean messageTree) { if (messageStop) { getCellEditor().stopCellEditing(); stopEditingInCompleteEditing = true; } if (messageCancel) { getCellEditor().cancelCellEditing(); stopEditingInCompleteEditing = true; } if (messageTree) treeModel.valueForPathChanged(tree.getLeadSelectionPath(), newVal); } /** * Will start editing for node if there is a cellEditor and shouldSelectCall * returns true. This assumes that path is valid and visible. * * @param path * is the path to start editing * @param event * is the MouseEvent performed on the path * @return true if successful */ protected boolean startEditing(TreePath path, MouseEvent event) { int x; int y; if (event == null) { Rectangle bounds = getPathBounds(tree, path); x = bounds.x; y = bounds.y; } else { x = event.getX(); y = event.getY(); } updateCellEditor(); TreeCellEditor ed = getCellEditor(); if (ed != null && ed.shouldSelectCell(event) && ed.isCellEditable(event)) { editingPath = path; editingRow = tree.getRowForPath(editingPath); Object val = editingPath.getLastPathComponent(); cellEditor.addCellEditorListener(cellEditorListener); stopEditingInCompleteEditing = false; boolean expanded = tree.isExpanded(editingPath); isEditing = true; editingComponent = ed.getTreeCellEditorComponent(tree, val, true, expanded, isLeaf(editingRow), editingRow); editingComponent.getParent().setVisible(true); editingComponent.getParent().validate(); tree.add(editingComponent.getParent()); editingComponent.getParent().validate(); validCachedPreferredSize = false; tree.revalidate(); ((JTextField) editingComponent).requestFocusInWindow(false); editorTimer.start(); return true; } return false; } /** * If the <code>mouseX</code> and <code>mouseY</code> are in the expand or * collapse region of the row, this will toggle the row. * * @param path * the path we are concerned with * @param mouseX * is the cursor's x position * @param mouseY * is the cursor's y position */ protected void checkForClickInExpandControl(TreePath path, int mouseX, int mouseY) { if (isLocationInExpandControl(path, mouseX, mouseY)) toggleExpandState(path); } /** * Returns true if the <code>mouseX</code> and <code>mouseY</code> fall in * the area of row that is used to expand/collpse the node and the node at row * does not represent a leaf. * * @param path * the path we are concerned with * @param mouseX * is the cursor's x position * @param mouseY * is the cursor's y position * @return true if the <code>mouseX</code> and <code>mouseY</code> fall in * the area of row that is used to expand/collpse the node and the * node at row does not represent a leaf. */ protected boolean isLocationInExpandControl(TreePath path, int mouseX, int mouseY) { boolean cntlClick = false; int row = getRowForPath(tree, path); if (!isLeaf(row)) { Rectangle bounds = getPathBounds(tree, path); if (hasControlIcons() && (mouseX < bounds.x) && (mouseX > (bounds.x - getCurrentControlIcon(path).getIconWidth() - gap))) cntlClick = true; } return cntlClick; } /** * Messaged when the user clicks the particular row, this invokes * toggleExpandState. * * @param path * the path we are concerned with * @param mouseX * is the cursor's x position * @param mouseY * is the cursor's y position */ protected void handleExpandControlClick(TreePath path, int mouseX, int mouseY) { toggleExpandState(path); } /** * Expands path if it is not expanded, or collapses row if it is expanded. If * expanding a path and JTree scroll on expand, ensureRowsAreVisible is * invoked to scroll as many of the children to visible as possible (tries to * scroll to last visible descendant of path). * * @param path * the path we are concerned with */ protected void toggleExpandState(TreePath path) { if (tree.isExpanded(path)) tree.collapsePath(path); else tree.expandPath(path); updateCurrentVisiblePath(); } /** * Returning true signifies a mouse event on the node should toggle the * selection of only the row under the mouse. * * @param event * is the MouseEvent performed on the row. * @return true signifies a mouse event on the node should toggle the * selection of only the row under the mouse. */ protected boolean isToggleSelectionEvent(MouseEvent event) { return (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.SINGLE_TREE_SELECTION); } /** * Returning true signifies a mouse event on the node should select from the * anchor point. * * @param event * is the MouseEvent performed on the node. * @return true signifies a mouse event on the node should select from the * anchor point. */ protected boolean isMultiSelectEvent(MouseEvent event) { return (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.CONTIGUOUS_TREE_SELECTION); } /** * Returning true indicates the row under the mouse should be toggled based on * the event. This is invoked after checkForClickInExpandControl, implying the * location is not in the expand (toggle) control. * * @param event * is the MouseEvent performed on the row. * @return true indicates the row under the mouse should be toggled based on * the event. */ protected boolean isToggleEvent(MouseEvent event) { return true; } /** * Messaged to update the selection based on a MouseEvent over a particular * row. If the even is a toggle selection event, the row is either selected, * or deselected. If the event identifies a multi selection event, the * selection is updated from the anchor point. Otherwise, the row is selected, * and if the even specified a toggle event the row is expanded/collapsed. * * @param path * is the path selected for an event * @param event * is the MouseEvent performed on the path. */ protected void selectPathForEvent(TreePath path, MouseEvent event) { if (isToggleSelectionEvent(event)) { if (tree.isPathSelected(path)) tree.removeSelectionPath(path); else { tree.addSelectionPath(path); tree.setAnchorSelectionPath(path); } } else if (isMultiSelectEvent(event)) { TreePath anchor = tree.getAnchorSelectionPath(); if (anchor != null) { int aRow = getRowForPath(tree, anchor); tree.addSelectionInterval(aRow, getRowForPath(tree, path)); } else tree.addSelectionPath(path); } else tree.addSelectionPath(path); } /** * Returns true if the node at <code>row</code> is a leaf. * * @param row * is the row we are concerned with. * @return true if the node at <code>row</code> is a leaf. */ protected boolean isLeaf(int row) { TreePath pathForRow = getPathForRow(tree, row); if (pathForRow == null) return true; Object node = pathForRow.getLastPathComponent(); return treeModel.isLeaf(node); } /** * This class implements the actions that we want to happen when specific keys * are pressed for the JTree. The actionPerformed method is called when a key * that has been registered for the JTree is received. */ class TreeAction extends AbstractAction { /** * What to do when this action is called. * * @param e * the ActionEvent that caused this action. */ public void actionPerformed(ActionEvent e) { TreePath lead = tree.getLeadSelectionPath(); if (e.getActionCommand().equals("selectPreviousChangeLead") || e.getActionCommand().equals("selectPreviousExtendSelection")
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -