📄 jxtreetable.java
字号:
model.setValueAt(value, nodeForRow(row), column); } protected Object nodeForRow(int row) { return tree.getPathForRow(row).getLastPathComponent(); } /** * Invokes fireTableDataChanged after all the pending events have been * processed. SwingUtilities.invokeLater is used to handle this. */ private void delayedFireTableDataChanged() { SwingUtilities.invokeLater(new Runnable() { public void run() { fireTableDataChanged(); } }); } /** * Invokes fireTableDataChanged after all the pending events have been * processed. SwingUtilities.invokeLater is used to handle this. */ private void delayedFireTableDataChanged(final TreeModelEvent tme, final int typeChange) { SwingUtilities.invokeLater(new Runnable() { public void run() { int indices[] = tme.getChildIndices(); TreePath path = tme.getTreePath(); if (indices != null) { if (tree.isExpanded(path)) { // Dont bother to update if the parent // node is collapsed int startingRow = tree.getRowForPath(path)+1; int min = Integer.MAX_VALUE; int max = Integer.MIN_VALUE; for (int i=0;i<indices.length;i++) { if (indices[i] < min) { min = indices[i]; } if (indices[i] > max) { max = indices[i]; } } switch (typeChange) { case 0 : fireTableRowsUpdated(startingRow + min, startingRow+max); break; case 1: fireTableRowsInserted(startingRow + min, startingRow+max); break; case 2: fireTableRowsDeleted(startingRow + min, startingRow+max); break; } } else { // not expanded - but change might effect appearance of parent // Issue #82-swingx int row = tree.getRowForPath(path); fireTableRowsUpdated(row, row); } } else { // case where the event is fired to identify root. fireTableDataChanged(); } } }); } private TreeTableModel model; // immutable private final JTree tree; // immutable private JXTreeTable treeTable = null; // logically immutable } static class TreeTableCellRenderer extends JXTree implements TableCellRenderer { // Force user to specify TreeTableModel instead of more general TreeModel public TreeTableCellRenderer(TreeTableModel model) { super(model); putClientProperty("JTree.lineStyle", "None"); setRootVisible(false); // superclass default is "true" setShowsRootHandles(true); // superclass default is "false" /** @todo Support truncated text directly in DefaultTreeCellRenderer. */ setOverwriteRendererIcons(true); setCellRenderer(new ClippedTreeCellRenderer()); } /** * Immutably binds this TreeTableModelAdapter to the specified JXTreeTable. * For internal use by JXTreeTable only. * * @param treeTable the JXTreeTable instance that this renderer is bound to */ public final void bind(JXTreeTable treeTable) { // Suppress potentially subversive invocation! // Prevent clearing out the deck for possible hijack attempt later! if (treeTable == null) { throw new IllegalArgumentException("null treeTable"); } if (this.treeTable == null) { this.treeTable = treeTable; } else { throw new IllegalArgumentException("renderer already bound"); } } /** * updateUI is overridden to set the colors of the Tree's renderer * to match that of the table. */ public void updateUI() { super.updateUI(); // Make the tree's cell renderer use the table's cell selection // colors. TreeCellRenderer tcr = getCellRenderer(); if (tcr instanceof DefaultTreeCellRenderer) { DefaultTreeCellRenderer dtcr = ((DefaultTreeCellRenderer) tcr); // For 1.1 uncomment this, 1.2 has a bug that will cause an // exception to be thrown if the border selection color is null. dtcr.setBorderSelectionColor(null); dtcr.setTextSelectionColor( UIManager.getColor("Table.selectionForeground")); dtcr.setBackgroundSelectionColor( UIManager.getColor("Table.selectionBackground")); } } /** * Sets the row height of the tree, and forwards the row height to * the table. */ public void setRowHeight(int rowHeight) { super.setRowHeight(rowHeight); if (rowHeight > 0) { // JW: setting the largeModel property is suggested in // #25-swingx. // backing out: leads to NPEs and icons not showing// setLargeModel(true); if (treeTable != null) { // Reconcile semantic differences between JTable and JTree final int tableRowMargin = treeTable.getRowMargin(); assert tableRowMargin >= 0; final int tableRowHeight = rowHeight - (tableRowMargin << 1); if (treeTable.getRowHeight() != tableRowHeight) { treeTable.adminSetRowHeight(tableRowHeight); } } } // else {// setLargeModel(false);// } } /** * This is overridden to set the height to match that of the JTable. */ public void setBounds(int x, int y, int w, int h) { if (treeTable != null) { y = 0; // It is not enough to set the height to treeTable.getHeight() h = treeTable.getRowCount() * this.getRowHeight(); } super.setBounds(x, y, w, h); } /** * Sublcassed to translate the graphics such that the last visible row * will be drawn at 0,0. */ public void paint(Graphics g) { int rowMargin = treeTable.getRowMargin(); // MUST account for rowMargin for precise positioning. // Offset by (rowMargin * 3)/2, and remember to offset by an // additional pixel if rowMargin is odd! int margins = rowMargin + (rowMargin >> 1) + (rowMargin % 2); int translationOffset = margins + visibleRow * getRowHeight(); g.translate(0, -translationOffset); hierarchicalColumnWidth = getWidth(); super.paint(g); // Draw the Table border if we have focus. if (highlightBorder != null) { // #170: border not drawn correctly // JW: position the border to be drawn in translated area // still not satifying in all cases... // RG: Now it satisfies (at least for the row margins) // Still need to make similar adjustments for column margins... highlightBorder.paintBorder(this, g, 0, translationOffset, getWidth(), // uhhh getRowHeight() + 1 - 2 * (margins) getRowHeight() - (rowMargin << 1) - rowMargin); // RG: // subtract // (rowMargin // * 3) } } public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { assert table == treeTable; if (isSelected) { setBackground(table.getSelectionBackground()); setForeground(table.getSelectionForeground()); } else { setBackground(table.getBackground()); setForeground(table.getForeground()); } highlightBorder = null; if (treeTable != null) { if (treeTable.realEditingRow() == row && treeTable.getEditingColumn() == column) { } else if (hasFocus) { highlightBorder = UIManager.getBorder( "Table.focusCellHighlightBorder"); } } visibleRow = row; return this; } private class ClippedTreeCellRenderer extends DefaultTreeCellRenderer { public void paint(Graphics g) { String fullText = super.getText(); // getText() calls tree.convertValueToText(); // tree.convertValueToText() should call treeModel.convertValueToText(), if possible String shortText = SwingUtilities.layoutCompoundLabel( this, g.getFontMetrics(), fullText, getIcon(), getVerticalAlignment(), getHorizontalAlignment(), getVerticalTextPosition(), getHorizontalTextPosition(), getItemRect(itemRect), iconRect, textRect, getIconTextGap()); /** @todo setText is more heavyweight than we want in this * situation. Make JLabel.text protected instead of private. */ setText(shortText); // temporarily truncate text super.paint(g); setText(fullText); // restore full text } private Rectangle getItemRect(Rectangle itemRect) { getBounds(itemRect); itemRect.width = hierarchicalColumnWidth - itemRect.x; return itemRect; } // Rectangles filled in by SwingUtilities.layoutCompoundLabel(); private final Rectangle iconRect = new Rectangle(); private final Rectangle textRect = new Rectangle(); // Rectangle filled in by this.getItemRect(); private final Rectangle itemRect = new Rectangle(); } /** Border to draw around the tree, if this is non-null, it will * be painted. */ protected Border highlightBorder = null; protected JXTreeTable treeTable = null; protected int visibleRow = 0; // A JXTreeTable may not have more than one hierarchical column private int hierarchicalColumnWidth = 0; } /** * Returns the adapter that knows how to access the component data model. * The component data adapter is used by filters, sorters, and highlighters. * * @return the adapter that knows how to access the component data model */ protected ComponentAdapter getComponentAdapter() { if (dataAdapter == null) { dataAdapter = new TreeTableDataAdapter(this); } // MUST ALWAYS ACCESS dataAdapter through accessor method!!! return dataAdapter; } private final static Dimension spacing = new Dimension(0, 2); protected static class TreeTableDataAdapter extends JXTable.TableAdapter { private final JXTreeTable table; /** * Constructs a <code>TreeTableDataAdapter</code> for the specified * target component. * * @param component the target component */ public TreeTableDataAdapter(JXTreeTable component) { super(component); table = component; } public JXTreeTable getTreeTable() { return table; } public boolean isExpanded() { return super.isExpanded(); /** @todo implement this method */ } public boolean hasFocus() { boolean focus = super.hasFocus(); /** @todo implement this method */ return focus; } public boolean isLeaf() { return super.isLeaf(); /** @todo implement this method */ } /** * * @return true if the cell identified by this adapter displays hierarchical * nodes; false otherwise */ public boolean isHierarchical() { return table.isHierarchical(column); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -