jtreetable.java

来自「Semantic Web Ontology Editor」· Java 代码 · 共 571 行 · 第 1/2 页

JAVA
571
字号
		/**		 * TreeCellRenderer method. Overridden to update the visible row.		 */		public Component getTableCellRendererComponent(JTable table,				Object value, boolean isSelected, boolean hasFocus, int row,				int column) {			Color background;			Color foreground;			if (isSelected) {				background = table.getSelectionBackground();				foreground = table.getSelectionForeground();			} else {				background = table.getBackground();				foreground = table.getForeground();			}			highlightBorder = null;			if (realEditingRow() == row && getEditingColumn() == column) {				background = UIManager.getColor("Table.focusCellBackground");				foreground = UIManager.getColor("Table.focusCellForeground");			} else if (hasFocus) {				highlightBorder = UIManager						.getBorder("Table.focusCellHighlightBorder");				if (isCellEditable(row, column)) {					background = UIManager							.getColor("Table.focusCellBackground");					foreground = UIManager							.getColor("Table.focusCellForeground");				}			} else if (table.getShowHorizontalLines()					|| table.getShowVerticalLines()) {				highlightBorder = new LineBorder(table.getGridColor());			}			visibleRow = row;			setBackground(background);			TreeCellRenderer tcr = getCellRenderer();			if (tcr instanceof DefaultTreeCellRenderer) {				DefaultTreeCellRenderer dtcr = ((DefaultTreeCellRenderer) tcr);				if (isSelected) {					dtcr.setTextSelectionColor(foreground);					dtcr.setBackgroundSelectionColor(background);				} else {					dtcr.setTextNonSelectionColor(foreground);					dtcr.setBackgroundNonSelectionColor(background);				}			}			return this;		}	}	/**	 * An editor that can be used to edit the tree column. This extends	 * DefaultCellEditor and uses a JTextField (actually, TreeTableTextField) to	 * perform the actual editing.	 * <p>	 * To support editing of the tree column we can not make the tree editable.	 * The reason this doesn't work is that you can not use the same component	 * for editing and renderering. The table may have the need to paint cells,	 * while a cell is being edited. If the same component were used for the	 * rendering and editing the component would be moved around, and the	 * contents would change. When editing, this is undesirable, the contents of	 * the text field must stay the same, including the caret blinking, and	 * selections persisting. For this reason the editing is done via a	 * TableCellEditor.	 * <p>	 * Another interesting thing to be aware of is how tree positions its render	 * and editor. The render/editor is responsible for drawing the icon	 * indicating the type of node (leaf, branch...). The tree is responsible	 * for drawing any other indicators, perhaps an additional +/- sign, or	 * lines connecting the various nodes. So, the renderer is positioned based	 * on depth. On the other hand, table always makes its editor fill the	 * contents of the cell. To get the allusion that the table cell editor is	 * part of the tree, we don't want the table cell editor to fill the cell	 * bounds. We want it to be placed in the same manner as tree places it	 * editor, and have table message the tree to paint any decorations the tree	 * wants. Then, we would only have to worry about the editing part. The	 * approach taken here is to determine where tree would place the editor,	 * and to override the <code>reshape</code> method in the JTextField	 * component to nudge the textfield to the location tree would place it.	 * Since JTreeTable will paint the tree behind the editor everything should	 * just work. So, that is what we are doing here. Determining of the icon	 * position will only work if the TreeCellRenderer is an instance of	 * DefaultTreeCellRenderer. If you need custom TreeCellRenderers, that don't	 * descend from DefaultTreeCellRenderer, and you want to support editing in	 * JTreeTable, you will have to do something similiar.	 */	public class TreeTableCellEditor extends DefaultCellEditor {		public TreeTableCellEditor() {			super(new TreeTableTextField());		}		/**		 * Overriden to determine an offset that tree would place the editor at.		 * The offset is determined from the <code>getRowBounds</code> JTree		 * method, and additionaly from the icon DefaultTreeCellRenderer will		 * use.		 * <p>		 * The offset is then set on the TreeTableTextField component created in		 * the constructor, and returned.		 */		public Component getTableCellEditorComponent(JTable table,				Object value, boolean isSelected, int r, int c) {			Component component = super.getTableCellEditorComponent(table,					value, isSelected, r, c);			JTree t = getTree();			try {				boolean rv = t.isRootVisible();				int offsetRow = rv ? r : r - 1;				Rectangle bounds = t.getRowBounds(offsetRow);				int offset = bounds.x;				TreeCellRenderer tcr = t.getCellRenderer();				if (tcr instanceof DefaultTreeCellRenderer) {					Object node = t.getPathForRow(offsetRow).getLastPathComponent();					Icon icon;					if (t.getModel().isLeaf(node))						icon = ((DefaultTreeCellRenderer) tcr).getLeafIcon();					else if (tree.isExpanded(offsetRow))						icon = ((DefaultTreeCellRenderer) tcr).getOpenIcon();					else						icon = ((DefaultTreeCellRenderer) tcr).getClosedIcon();					if (icon != null) {						offset += ((DefaultTreeCellRenderer) tcr).getIconTextGap()								+ icon.getIconWidth();					}				}				((TreeTableTextField) getComponent()).offset = offset;			}			catch (Exception e) {}			return component;		}		/**		 * This is overriden to forward the event to the tree. This will return		 * true if the click count >= 3, or the event is null.		 */		public boolean isCellEditable(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) {					for (int counter = getColumnCount() - 1; counter >= 0; counter--) {						if (getColumnClass(counter) == TreeTableModel.class) {							MouseEvent newME = new MouseEvent(									JTreeTable.this.tree, me.getID(), me											.getWhen(), me.getModifiers(), me											.getX()											- getCellRect(0, counter, true).x,									me.getY(), me.getClickCount(), me											.isPopupTrigger());							JTreeTable.this.tree.dispatchEvent(newME);							break;						}					}				}				if (me.getClickCount() >= 3) {					return true;				}				return false;			}			if (e == null) {				return true;			}			return false;		}	}	/**	 * Component used by TreeTableCellEditor. The only thing this does is to	 * override the <code>reshape</code> method, and to ALWAYS make the x	 * location be <code>offset</code>.	 */	static class TreeTableTextField extends JTextField {		public int offset;		public void reshape(int x, int y, int w, int h) {			int newX = Math.max(x, offset);			super.reshape(newX, y, w - (newX - x), h);		}	}	/**	 * ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel to	 * listen for changes in the ListSelectionModel it maintains. Once a change	 * in the ListSelectionModel happens, the paths are updated in the	 * DefaultTreeSelectionModel.	 */	class ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel {		/** Set to true when we are updating the ListSelectionModel. */		protected boolean updatingListSelectionModel;		public ListToTreeSelectionModelWrapper() {			super();			getListSelectionModel().addListSelectionListener(					createListSelectionListener());		}		/**		 * Returns the list selection model. ListToTreeSelectionModelWrapper		 * listens for changes to this model and updates the selected paths		 * accordingly.		 */		ListSelectionModel getListSelectionModel() {			return listSelectionModel;		}		/**		 * This is overridden to set <code>updatingListSelectionModel</code>		 * and message super. This is the only place DefaultTreeSelectionModel		 * alters the ListSelectionModel.		 */		public void resetRowSelection() {			if (!updatingListSelectionModel) {				updatingListSelectionModel = true;				try {					super.resetRowSelection();				} finally {					updatingListSelectionModel = false;				}			}			// Notice how we don't message super if			// updatingListSelectionModel is true. If			// updatingListSelectionModel is true, it implies the			// ListSelectionModel has already been updated and the			// paths are the only thing that needs to be updated.		}		/**		 * Creates and returns an instance of ListSelectionHandler.		 */		protected ListSelectionListener createListSelectionListener() {			return new ListSelectionHandler();		}		/**		 * If <code>updatingListSelectionModel</code> is false, this will		 * reset the selected paths from the selected rows in the list selection		 * model.		 */		protected void updateSelectedPathsFromSelectedRows() {			if (!updatingListSelectionModel) {				updatingListSelectionModel = true;				try {					// This is way expensive, ListSelectionModel needs an					// enumerator for iterating.					int min = listSelectionModel.getMinSelectionIndex();					int max = listSelectionModel.getMaxSelectionIndex();					clearSelection();					if (min != -1 && max != -1) {						for (int counter = min; counter <= max; counter++) {							if (listSelectionModel.isSelectedIndex(counter)) {								TreePath selPath = tree.getPathForRow(counter);								if (selPath != null) {									addSelectionPath(selPath);								}							}						}					}				} finally {					updatingListSelectionModel = false;				}			}		}		/**		 * Class responsible for calling updateSelectedPathsFromSelectedRows		 * when the selection of the list changse.		 */		class ListSelectionHandler implements ListSelectionListener {			public void valueChanged(ListSelectionEvent e) {				updateSelectedPathsFromSelectedRows();			}		}	}}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?