📄 jxtreetable.java
字号:
/* * $Id: JXTreeTable.java,v 1.24 2005/10/12 11:26:54 kleopatra Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */package org.jdesktop.swingx;import java.awt.Component;import java.awt.Dimension;import java.awt.Graphics;import java.awt.Point;import java.awt.Rectangle;import java.awt.event.ActionEvent;import java.awt.event.InputEvent;import java.awt.event.MouseEvent;import java.beans.PropertyChangeEvent;import java.beans.PropertyChangeListener;import java.util.Enumeration;import java.util.EventObject;import javax.swing.ActionMap;import javax.swing.Icon;import javax.swing.JTable;import javax.swing.JTree;import javax.swing.ListSelectionModel;import javax.swing.SwingUtilities;import javax.swing.UIManager;import javax.swing.border.Border;import javax.swing.event.ListSelectionEvent;import javax.swing.event.ListSelectionListener;import javax.swing.event.TreeExpansionEvent;import javax.swing.event.TreeExpansionListener;import javax.swing.event.TreeModelEvent;import javax.swing.event.TreeModelListener;import javax.swing.event.TreeSelectionListener;import javax.swing.event.TreeWillExpandListener;import javax.swing.plaf.UIResource;import javax.swing.plaf.basic.BasicTreeUI;import javax.swing.table.AbstractTableModel;import javax.swing.table.TableCellRenderer;import javax.swing.table.TableModel;import javax.swing.tree.DefaultTreeCellRenderer;import javax.swing.tree.DefaultTreeSelectionModel;import javax.swing.tree.TreeCellRenderer;import javax.swing.tree.TreePath;import javax.swing.tree.TreeSelectionModel;import org.jdesktop.swingx.JXTree.DelegatingRenderer;import org.jdesktop.swingx.decorator.ComponentAdapter;import org.jdesktop.swingx.treetable.AbstractTreeTableModel;import org.jdesktop.swingx.treetable.DefaultTreeTableModel;import org.jdesktop.swingx.treetable.TreeTableCellEditor;import org.jdesktop.swingx.treetable.TreeTableModel;/** * <p><code>JXTreeTable</code> is a specialized {@link javax.swing.JTable table} * consisting of a single column in which to display hierarchical data, and any * number of other columns in which to display regular data. The interface for * the data model used by a <code>JXTreeTable</code> is * {@link org.jdesktop.swingx.treetable.TreeTableModel}. It extends the * {@link javax.swing.tree.TreeModel} interface to allow access to cell data by * column indices within each node of the tree hierarchy.</p> * * <p>The most straightforward way create and use a <code>JXTreeTable</code>, is to * first create a suitable data model for it, and pass that to a * <code>JXTreeTable</code> constructor, as shown below: * <pre> * TreeTableModel treeTableModel = new FileSystemModel(); // any TreeTableModel * JXTreeTable treeTable = new JXTreeTable(treeTableModel); * JScrollPane scrollpane = new JScrollPane(treeTable); * </pre> * See {@link javax.swing.JTable} for an explanation of why putting the treetable * inside a scroll pane is necessary.</p> * * <p>A single treetable model instance may be shared among more than one * <code>JXTreeTable</code> instances. To access the treetable model, always call * {@link #getTreeTableModel() getTreeTableModel} and * {@link #setTreeTableModel(org.jdesktop.swingx.treetable.TreeTableModel) setTreeTableModel}. * <code>JXTreeTable</code> wraps the supplied treetable model inside a private * adapter class to adapt it to a {@link javax.swing.table.TableModel}. Although * the model adapter is accessible through the {@link #getModel() getModel} method, you * should avoid accessing and manipulating it in any way. In particular, each * model adapter instance is tightly bound to a single table instance, and any * attempt to share it with another table (for example, by calling * {@link #setModel(javax.swing.table.TableModel) setModel}) * will throw an <code>IllegalArgumentException</code>! * * @author Philip Milne * @author Scott Violet * @author Ramesh Gupta */public class JXTreeTable extends JXTable { /** * Renderer used to render cells within the * {@link #isHierarchical(int) hierarchical} column. * renderer extends JXTree and implements TableCellRenderer */ private TreeTableCellRenderer renderer; /** * Constructs a JXTreeTable using a * {@link org.jdesktop.swingx.treetable.DefaultTreeTableModel}. */ public JXTreeTable() { this(new DefaultTreeTableModel()); } /** * Constructs a JXTreeTable using the specified * {@link org.jdesktop.swingx.treetable.TreeTableModel}. * * @param treeModel model for the JXTreeTable */ public JXTreeTable(TreeTableModel treeModel) { // Implementation note: // Make sure that the SAME instance of treeModel is passed to the // constructor for TreeTableCellRenderer as is passed in the first // argument to the following chained constructor for this JXTreeTable: this(treeModel, new JXTreeTable.TreeTableCellRenderer(treeModel)); } /** * Constructs a <code>JXTreeTable</code> using the specified * {@link org.jdesktop.swing.treetable.TreeTableModel} and * {@link org.jdesktop.swing.treetable.TreeTableCellRenderer}. The renderer * must have been constructed using the same instance of * {@link org.jdesktop.swing.treetable.TreeTableModel} as passed to this * constructor. * * @param treeModel model for the JXTreeTable * @param renderer cell renderer for the tree portion of this JXTreeTable instance. * @throws IllegalArgumentException if an attempt is made to instantiate * JXTreeTable and TreeTableCellRenderer with different instances of TreeTableModel. */ private JXTreeTable(TreeTableModel treeModel, TreeTableCellRenderer renderer) { // To avoid unnecessary object creation, such as the construction of a // DefaultTableModel, it is better to invoke super(TreeTableModelAdapter) // directly, instead of first invoking super() followed by a call to // setTreeTableModel(TreeTableModel). // Adapt tree model to table model before invoking super() super(new TreeTableModelAdapter(treeModel, renderer)); // Enforce referential integrity; bail on fail if (treeModel != renderer.getModel()) { // do not use assert here! throw new IllegalArgumentException("Mismatched TreeTableModel"); } // renderer-related initialization -- also called from setTreeTableModel() init(renderer); // private method initActions(); // disable sorting super.setSortable(false); // Install the default editor. setDefaultEditor(AbstractTreeTableModel.hierarchicalColumnClass, new TreeTableCellEditor(renderer)); // No grid. setShowGrid(false); // superclass default is "true" // Default intercell spacing setIntercellSpacing(spacing); // for both row margin and column margin // JTable supports row margins and intercell spacing, but JTree doesn't. // We must reconcile the differences in the semantics of rowHeight as // understood by JTable and JTree by overriding both setRowHeight() and // setRowMargin(); adminSetRowHeight(getRowHeight()); setRowMargin(getRowMargin()); // call overridden setRowMargin() } private void initActions() { // Register the actions that this class can handle. ActionMap map = getActionMap(); map.put("expand-all", new Actions("expand-all")); map.put("collapse-all", new Actions("collapse-all")); } /** * A small class which dispatches actions. * TODO: Is there a way that we can make this static? */ private class Actions extends UIAction { Actions(String name) { super(name); } public void actionPerformed(ActionEvent evt) { if ("expand-all".equals(getName())) { expandAll(); } else if ("collapse-all".equals(getName())) { collapseAll(); } } } /** * overridden to do nothing. * * TreeTable is not sortable by default, because * Sorters/Filters currently don't work properly. * */ public void setSortable(boolean sortable) { // no-op } /** * <p>Sets whether the table draws horizontal lines between cells. It draws * the lines if <code>show</code> is true; otherwise it doesn't. By default, * a table draws the lines.</p> * * <p>If you want the lines to be drawn, make sure that the row margin or * horizontal intercell spacing is greater than zero.</p> * * @param show true, if horizontal lines should be drawn; false, if lines * should not be drawn * @see javax.swing.JTable#getShowHorizontalLines() getShowHorizontalLines * @see #setRowMargin(int) setRowMargin * @see javax.swing.JTable#setIntercellSpacing(java.awt.Dimension) setIntercellSpacing */ public void setShowHorizontalLines(boolean show) { super.setShowHorizontalLines(show); } /** * <p>Sets whether the table draws vertical lines between cells. It draws * the lines if <code>show</code> is true; otherwise it doesn't. By default, * a table draws the lines.</p> * * <p>If you want the lines to be drawn, make sure that the column margin or * vertical intercell spacing is greater than zero.</p> * * @param show true, if vertical lines should be drawn; false, if lines * should not be drawn * @see javax.swing.JTable#getShowVerticalLines() getShowVerticalLines * @see #setColumnMargin(int) setColumnMargin * @see javax.swing.JTable#setIntercellSpacing(java.awt.Dimension) setIntercellSpacing */ public void setShowVerticalLines(boolean show) { super.setShowVerticalLines(show); } /** * Overriden to invoke repaint for the particular location if * the column contains the tree. This is done as the tree editor does * not fill the bounds of the cell, we need the renderer to paint * the tree in the background, and then draw the editor over it. * You should not need to call this method directly. * * {@inheritDoc} */ public boolean editCellAt(int row, int column, EventObject e) { expandOrCollapseNode(e); // RG: Fix Issue 49! boolean canEdit = super.editCellAt(row, column, e); if (canEdit && isHierarchical(column)) { repaint(getCellRect(row, column, false)); } return canEdit; } private void expandOrCollapseNode(EventObject e) { if (e instanceof MouseEvent) { MouseEvent me = (MouseEvent) e; // If the modifiers are not 0 (or the left mouse button), // tree may try and toggle the selection, and table // will then try and toggle, resulting in the // selection remaining the same. To avoid this, we // only dispatch when the modifiers are 0 (or the left mouse // button). if (me.getModifiers() == 0 || me.getModifiers() == InputEvent.BUTTON1_MASK) { final int count = getColumnCount(); for (int i = count - 1; i >= 0; i--) { if (isHierarchical(i)) { int savedHeight = renderer.getRowHeight(); renderer.setRowHeight(getRowHeight()); MouseEvent pressed = new MouseEvent (renderer, me.getID(), me.getWhen(), me.getModifiers(), me.getX() - getCellRect(0, i, false).x, me.getY(), me.getClickCount(), me.isPopupTrigger()); renderer.dispatchEvent(pressed); // For Mac OS X, we need to dispatch a MOUSE_RELEASED as well MouseEvent released = new MouseEvent (renderer, java.awt.event.MouseEvent.MOUSE_RELEASED, pressed.getWhen(), pressed.getModifiers(), pressed.getX(), pressed.getY(), pressed.getClickCount(), pressed.isPopupTrigger()); renderer.dispatchEvent(released); renderer.setRowHeight(savedHeight); break; } } } } } /** * Overridden to provide a workaround for BasicTableUI anomaly. Make sure * the UI never tries to resize the editor. The UI currently uses different * techniques to paint the renderers and editors. So, overriding setBounds() * is not the right thing to do for an editor. Returning -1 for the * editing row in this case, ensures the editor is never painted. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -