📄 jtreetable.java
字号:
/*
* Sun Microsystems grants you ("Licensee") a non-exclusive, royalty
* free, license to use, modify and redistribute this software in
* source and binary code form, provided that i) this copyright notice
* and license appear on all copies of the software; and ii) Licensee
* does not utilize the software in a manner which is disparaging to
* Sun Microsystems.
*
* The software media is distributed on an "As Is" basis, without
* warranty. Neither the authors, the software developers nor Sun
* Microsystems make any representation, or warranty, either express
* or implied, with respect to the software programs, their quality,
* accuracy, or fitness for a specific purpose. Therefore, neither the
* authors, the software developers nor Sun Microsystems shall have
* any liability to you or any other person or entity with respect to
* any liability, loss, or damage caused or alleged to have been
* caused directly or indirectly by programs contained on the
* media. This includes, but is not limited to, interruption of
* service, loss of data, loss of classroom time, loss of consulting
* or anticipatory *profits, or consequential damages from the use of
* these programs.
*/
package org.rapla.components.treetable;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;
import javax.swing.tree.*;
import javax.swing.event.*;
/**
* Original version Philip Milne and Scott Violet
* Modified by Christopher Kohlhaas to support editing and keyboard handling.
*/
public class JTreeTable extends JTable {
private static final long serialVersionUID = 1L;
private RendererTree tree = new RendererTree();
private TreeTableEditor treeCellEditor;
private TableToolTipRenderer toolTipRenderer = null;
private int focusedRow = -1;
public JTreeTable(TreeTableModel model) {
super();
setTreeTableModel( model );
// Force the JTable and JTree to share their row selection models.
ListToTreeSelectionModelWrapper selectionWrapper = new
ListToTreeSelectionModelWrapper();
setSelectionModel(selectionWrapper.getListSelectionModel());
setShowGrid( false);
// No intercell spacing
setIntercellSpacing(new Dimension(1, 0));
setShowVerticalLines(true);
tree.setEditable(false);
tree.setSelectionModel(selectionWrapper);
tree.setShowsRootHandles(true);
tree.setRootVisible(false);
setDefaultRenderer( TreeTableModel.class, tree );
setTreeCellEditor(null);
// And update the height of the trees row to match that of
// the table.
if (tree.getRowHeight() < 1) {
// Metal looks better like this.
setRowHeight(22);
}
}
public void setToolTipRenderer(TableToolTipRenderer renderer) {
toolTipRenderer = renderer;
}
public TableToolTipRenderer getToolTipRenderer() {
return toolTipRenderer;
}
public String getToolTipText(MouseEvent evt) {
if (toolTipRenderer == null)
return super.getToolTipText(evt);
Point p = new Point(evt.getX(),evt.getY());
int column = columnAtPoint(p);
int row = rowAtPoint(p);
if (row >=0 && column>=0)
return toolTipRenderer.getToolTipText(this,row,column);
else
return super.getToolTipText(evt);
}
/**
* Overridden to message super and forward the method to the tree.
* Since the tree is not actually in the component hierarchy it will
* never receive this unless we forward it in this manner.
*/
public void updateUI() {
super.updateUI();
if(tree != null) {
tree.updateUI();
}
// Use the tree's default foreground and background colors in the
// table.
LookAndFeel.installColorsAndFont(this, "Tree.background",
"Tree.foreground", "Tree.font");
}
/** Set a custom TreeCellEditor. The default one is a TextField.*/
public void setTreeCellEditor(TreeTableEditor editor) {
treeCellEditor = editor;
setDefaultEditor( TreeTableModel.class, new DelegationgTreeCellEditor(treeCellEditor) );
}
/** Returns the tree that is being shared between the model.
If you set a different TreeCellRenderer for this tree it should
inherit from DefaultTreeCellRenderer. Otherwise the selection-color
and focus color will not be set correctly.
*/
public JTree getTree() {
return tree;
}
/** overridden to support keyboard expand/collapse for the tree.*/
protected boolean processKeyBinding(KeyStroke ks,
KeyEvent e,
int condition,
boolean pressed)
{
if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
{
if (tree != null && !isEditing() && getSelectedColumn() == getTreeColumnNumber()) {
if (e.getID() == KeyEvent.KEY_PRESSED && (e.getKeyCode() == KeyEvent.VK_ENTER || e.getKeyChar() =='+')) {
int row = getSelectedRow();
if (row >= 0) {
if (tree.isExpanded(row)) {
tree.collapseRow(row);
} else {
tree.expandPath(tree.getPathForRow(row));
}
}
return true;
}
/* Uncomment this if you don't want to start tree-cell-editing
on a non navigation key stroke.
if (e.getKeyCode() != e.VK_TAB && e.getKeyCode() != e.VK_F2
&& e.getKeyCode() != e.VK_DOWN && e.getKeyCode() != e.VK_UP
&& e.getKeyCode() != e.VK_LEFT && e.getKeyCode() != e.VK_RIGHT
&& e.getKeyCode() != e.VK_PAGE_UP && e.getKeyCode() != e.VK_PAGE_DOWN
)
return true;
*/
}
}
return super.processKeyBinding(ks,e,condition,pressed);
}
public void setTreeTableModel(TreeTableModel model) {
tree.setModel(model);
super.setModel(new TreeTableModelAdapter(model));
}
/**
* 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; overriding setBounds() below
* 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.
*/
public int getEditingRow() {
int column = getEditingColumn();
if( getColumnClass(column) == TreeTableModel.class )
return -1;
return editingRow;
}
/**
* Returns the actual row that is editing as <code>getEditingRow</code>
* will always return -1.
*/
private int realEditingRow() {
return editingRow;
}
/** Overridden to pass the new rowHeight to the tree. */
public void setRowHeight(int rowHeight) {
super.setRowHeight(rowHeight);
if (tree != null && tree.getRowHeight() != rowHeight)
tree.setRowHeight( rowHeight );
}
private int getTreeColumnNumber() {
for (int counter = getColumnCount() - 1; counter >= 0;counter--)
if (getColumnClass(counter) == TreeTableModel.class)
return counter;
return -1;
}
/** <code>isCellEditable</code> returns true for the Tree-Column, even if it is not editable.
<code>isCellRealEditable</code> returns true only if the underlying TreeTableModel-Cell is
editable.
*/
private boolean isCellRealEditable(int row,int column) {
TreePath treePath = tree.getPathForRow(row);
if (treePath == null)
return false;
return (((TreeTableModel)tree.getModel()).isCellEditable(treePath.getLastPathComponent()
,column));
}
class RendererTree extends JTree implements TableCellRenderer {
private static final long serialVersionUID = 1L;
protected int rowToPaint;
Color borderColor = Color.gray;
/** Border to draw around the tree, if this is non-null, it will
* be painted. */
protected Border highlightBorder;
public RendererTree() {
super();
}
public void setRowHeight(int rowHeight) {
if (rowHeight > 0) {
super.setRowHeight(rowHeight);
if (JTreeTable.this != null &&
JTreeTable.this.getRowHeight() != rowHeight) {
JTreeTable.this.setRowHeight(getRowHeight());
}
}
}
// Move and resize the tree to the table position
public void setBounds( int x, int y, int w, int h ) {
super.setBounds( x, 0, w, JTreeTable.this.getHeight() );
}
public void paintEditorBackground(Graphics g,int row) {
tree.rowToPaint = row;
g.translate( 0, -row * getRowHeight());
Rectangle rect = g.getClipBounds();
if (rect.width >0 && rect.height >0)
super.paintComponent(g);
g.translate( 0, row * getRowHeight());
}
// start painting at the rowToPaint
public void paint( Graphics g ) {
int row = rowToPaint;
g.translate( 0, -rowToPaint * getRowHeight() );
super.paint(g);
int x = 0;
TreePath path = getPathForRow(row);
Object value = path.getLastPathComponent();
boolean isSelected = tree.isRowSelected(row);
x = tree.getRowBounds(row).x;
if (treeCellEditor != null) {
x += treeCellEditor.getGap(tree,value,isSelected,row);
} else {
TreeCellRenderer tcr = getCellRenderer();
if (tcr instanceof DefaultTreeCellRenderer) {
DefaultTreeCellRenderer dtcr = ((DefaultTreeCellRenderer)tcr);
// super.paint must have been called before
x += dtcr.getIconTextGap() + dtcr.getIcon().getIconWidth();
}
}
// Draw the Table border if we have focus.
if (highlightBorder != null) {
highlightBorder.paintBorder(this, g, x, rowToPaint *
getRowHeight(), getWidth() -x,
getRowHeight() );
} // Paint the selection rectangle
}
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row, int column) {
Color background;
Color foreground;
if (hasFocus)
focusedRow = row;
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 (isCellRealEditable(row,convertColumnIndexToModel(column))) {
background = UIManager.getColor
("Table.focusCellBackground");
foreground = UIManager.getColor
("Table.focusCellForeground");
}
}
this.rowToPaint = 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;
}
}
class DelegationgTreeCellEditor implements TableCellEditor
{
TreeTableEditor delegate;
JComponent lastComp = null;
int textOffset = 0;
MouseListener mouseListener = new MouseAdapter() {
public void mouseClicked(MouseEvent evt)
{
if (lastComp == null)
return;
if (delegate == null)
return;
if (evt.getY() < 0 || evt.getY()>lastComp.getHeight())
delegate.stopCellEditing();
// User clicked left from the text
if (textOffset > 0 && evt.getX()< textOffset )
delegate.stopCellEditing();
}
};
public DelegationgTreeCellEditor(TreeTableEditor delegate) {
this.delegate = delegate;
}
public void addCellEditorListener(CellEditorListener listener) {
delegate.addCellEditorListener(listener);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -