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 + -
显示快捷键?