TreeTable

Aus Byte-Welt Wiki
Zur Navigation springenZur Suche springen

Hier ist eine einfache Implementation einer TreeTable (gem. Alexandru Toth), die ein gemeinsames Model für JTree und JTable benutzt. Es ist dann kein Problem mehr, dynamisch neue Zeilen hinzuzufügen:

<code=java>package treetable;

import java.awt.Color; import javax.swing.*; import javax.swing.table.*;

/** JTable that has different renderers depending on the classes in TreeModel */ public class Table extends JTable {

   void registerRenderers() {
       setDefaultRenderer(Color.class, new TableColorRenderer(Color.WHITE));
   }
   public Table() {
       super();
       registerRenderers();
   }
   public Table(TableModel dm) {
       super(dm);
       registerRenderers();
   }
   public Table(TableModel dm, TableColumnModel cm) {
       super(dm, cm);
       registerRenderers();
   }
   @Override
   public TableCellRenderer getCellRenderer(int row, int column) {
       Object value = getModel().getValueAt(row, column);
       /** enable to have custom renderers depending on class of cell */
       TableCellRenderer tcr = getDefaultRenderer(value.getClass());
       return tcr;
   }

}</code=java>

<code=java>package treetable;

import javax.swing.*; import javax.swing.event.*; import javax.swing.tree.*; import javax.swing.table.*; import java.util.Vector;

public class TableAdapter extends AbstractTableModel {

   private JTree tree;
   private JTable table;
   private int[] sel_rows;
   private ListSelectionListener selectionListener;
   public TableAdapter(JTree t) {
       tree = t;
       tree.addTreeExpansionListener(new TreeExpansionListener() {
           public void treeExpanded(TreeExpansionEvent event) {
               fireTableDataChanged();
               select();
           }
           public void treeCollapsed(TreeExpansionEvent event) {
               fireTableDataChanged();
               select();
           }
       });
   }
   public void addTable(JTable t) {
       table = t;
       tree.addTreeSelectionListener(new TreeSelectionListener() {
           public void valueChanged(TreeSelectionEvent e) {
               sel_rows = tree.getSelectionRows();
               select();
           }
       });
       selectionListener = new ListSelectionListener() {
           public void valueChanged(ListSelectionEvent e) {
               int row = table.getSelectedRow();
               tree.setSelectionRow(row);
           }
       };
       table.getSelectionModel().addListSelectionListener(selectionListener);
   }
   private void select() {
       if (sel_rows != null) {
           table.getSelectionModel().setSelectionInterval(sel_rows[0], sel_rows[0]);
       }
   }
   //assumes all nodes have same number of items as root node
   public int getColumnCount() {
       DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
       TableNode n = (TableNode) root.getUserObject();
       return n.getDataRow().size();
   }
   public int getRowCount() {
       return tree.getRowCount();
   }
   @Override
   public String getColumnName(int col) {
       return new String("col" + col);
   }
   public Object getValueAt(int row, int col) {
       TreePath tPath = tree.getPathForRow(row);
       Object[] oPath = tPath.getPath();
       int len = oPath.length;
       DefaultMutableTreeNode node = (DefaultMutableTreeNode) oPath[len - 1];
       TableNode treeNode = (TableNode) node.getUserObject();
       Vector dataRow = treeNode.getDataRow();
       return dataRow.elementAt(col);
   }
   @Override
   public void setValueAt(Object value, int row, int col) {
       TreePath tPath = tree.getPathForRow(row);
       Object[] oPath = tPath.getPath();
       int len = oPath.length;
       DefaultMutableTreeNode node = (DefaultMutableTreeNode) oPath[len - 1];
       TableNode treeNode = (TableNode) node.getUserObject();
       Vector dataRow = treeNode.getDataRow();
       dataRow.setElementAt(value, col);
   }
   @Override
   public Class getColumnClass(int c) {
       DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
       TableNode n = (TableNode) root.getUserObject();
       return n.getDataRow().elementAt(c).getClass();
   }
   @Override
   public boolean isCellEditable(int rowIndex, int columnIndex) {
       return true;
   }

}</code=java>

<code=java>package treetable;

import java.awt.*; import javax.swing.*; import javax.swing.table.*; import javax.swing.border.*;

public class TableColorRenderer extends JLabel implements TableCellRenderer {

   Border unselectedBorder = null;
   Border selectedBorder = null;
   boolean isBordered = true;
   public TableColorRenderer(Color color) {
       super();
       setOpaque(true);
       setBackground(color);
   }
   public Component getTableCellRendererComponent(
           JTable table, Object value,
           boolean isSelected, boolean hasFocus,
           int row, int column) {
       if (isSelected) {
           if (selectedBorder == null) {
               selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
                       table.getSelectionBackground());
           }
           setBorder(selectedBorder);
       } else {
           if (unselectedBorder == null) {
               unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
                       table.getBackground());
           }
           setBorder(unselectedBorder);
       }
       if (value.getClass() == Color.class) {
           setBackground((Color) value);
       } else {
           setBackground(Color.WHITE);
       }
       return this;
   }

}</code=java>

<code=java>package treetable;

import java.util.*;

public class TableNode {

   private String label;
   private Vector dataRow;
   public TableNode(String s, Object x, Object y) {
       label = s;
       dataRow = new Vector();
       dataRow.add(x);
       dataRow.add(y);
   }
   @Override
   public String toString() {
       return label;
   }
   public Vector getDataRow() {
       return dataRow;
   }

}</code=java>

<code=java>package treetable;

import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.tree.*; import javax.swing.table.*;

public class TreeTable extends JFrame {

   private JTableHeader tableHeader;
   private JTree tree;
   private TableAdapter adapter;
   private Table table;
   private JButton btAdd;
   private DefaultMutableTreeNode root;
   private JSplitPane splitPane;
   private Color selectionColor;
   private Rectangle selectedRowBounds;
   public TreeTable() {
       super("Tree Table Demo");
       setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       tree = new JTree(createTree()) {
           //Override paintComponent of JTree:
           @Override
           public void paintComponent(final Graphics g) {
               if (selectedRowBounds != null) {
                   //Set selection Color:
                   g.setColor(selectionColor);
                   //Draw selection rectangle using the width of JTree:
                   g.fillRect(0, (int) selectedRowBounds.getY(), getWidth(), (int) selectedRowBounds.getHeight());
               }
               super.paintComponent(g);
           }
       };
       adapter = new TableAdapter(tree);
       table = new Table(adapter);
       customizeTable(table);
       customizeTree(tree, table);
       customizeSplipane(tree, table);
       //
       JScrollPane scrollPane = new JScrollPane(splitPane);
       getContentPane().add(scrollPane, BorderLayout.CENTER);
       JPanel header = new JPanel(null);
       tableHeader = table.getTableHeader();
       header.add(tableHeader);
       header.setPreferredSize(new Dimension(0, 16));
       getContentPane().add(header, BorderLayout.NORTH);
       setSize(400, 300);
       setLocationRelativeTo(null);
       btAdd = new JButton();
       add(btAdd, BorderLayout.SOUTH);
       btAdd.setAction(new AbstractAction("Add") {
           public void actionPerformed(ActionEvent e) {
               DefaultMutableTreeNode n = new DefaultMutableTreeNode(new TableNode("NEW", new Integer(5), Color.GREEN));
               DefaultMutableTreeNode parent = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
               if (parent != null) {
                   parent.add(n);
                   ((DefaultTreeModel) tree.getModel()).nodeStructureChanged(parent);
                   table.repaint();
                   validate();
               }
           }
       });
   }
   private DefaultMutableTreeNode createTree() {
       // create root node and add more nodes
       root = new DefaultMutableTreeNode(new TableNode("World", new Integer(10), Color.YELLOW));
       DefaultMutableTreeNode n = new DefaultMutableTreeNode(new TableNode("Europe", new Integer(5), Color.GREEN));
       root.add(n);
       DefaultMutableTreeNode n1 = new DefaultMutableTreeNode(new TableNode("Finland", new Integer(1), Color.ORANGE));
       n.add(n1);
       n1 = new DefaultMutableTreeNode(new TableNode("Romania", new Integer(1), Color.RED));
       n.add(n1);
       n1 = new DefaultMutableTreeNode(new TableNode("Germany", new Integer(3), Color.BLUE));
       n.add(n1);
       n = new DefaultMutableTreeNode(new TableNode("America", new Integer(4), Color.WHITE));
       root.add(n);
       n = new DefaultMutableTreeNode(new TableNode("Asia", new Integer(1), Color.MAGENTA));
       root.add(n);
       return root;
   }
   private void customizeTable(final JTable table) {
       table.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
       //connect Selection listeners
       adapter.addTable(table);
       table.setRowHeight(18);
       table.addComponentListener(new ComponentAdapter() {
           @Override
           public void componentResized(ComponentEvent e) {
               Point loc = table.getLocationOnScreen();
               tableHeader.setBounds(new Rectangle(loc.x - getLocation().x - 3, 0, 3000, 18));
           }
       });
   }
   private void customizeTree(final JTree tree, final JTable table) {
       tree.setRowHeight(table.getRowHeight());
       tree.setFocusable(false);
       selectionColor = table.getSelectionBackground();
       tree.putClientProperty("JTree.lineStyle", "Horizontal");
       tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
       tree.setOpaque(false);
       //Adapt the default selection colors:
       DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) tree.getCellRenderer();
       renderer.setBorderSelectionColor(Color.WHITE);
       renderer.setBackgroundSelectionColor(new Color(0, 0, 0, 0));
       //Add the TreeSelectionListener:
       TreeSelectionModel selectionModel = tree.getSelectionModel();
       selectionModel.addTreeSelectionListener(new TreeSelectionListener() {
           public void valueChanged(final TreeSelectionEvent e) {
               paintSelectionRect();
           }
       });
       //Add the TreeExpansionListener:
       tree.addTreeExpansionListener(new TreeExpansionListener() {
           public void treeCollapsed(final TreeExpansionEvent event) {
               paintSelectionRect();
           }
           public void treeExpanded(final TreeExpansionEvent event) {
               paintSelectionRect();
           }
       });
       //Add MouseListener if you want to listen to whole line width:
       tree.addMouseListener(new MouseAdapter() {
           @Override
           public void mousePressed(final MouseEvent e) {
               int row = tree.getClosestRowForLocation(e.getX(), e.getY());
               if (e.getClickCount() == 2) {
                   if (tree.isCollapsed(row)) {
                       tree.expandRow(row);
                   } else {
                       tree.collapseRow(row);
                   }
               } else {
                   tree.setSelectionRow(row);
               }
           }
       });
   }
   private void customizeSplipane(final JTree tree, final JTable table) {
       splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, tree, table);
       splitPane.setDividerLocation(150);
       splitPane.setBackground(Color.WHITE);
       splitPane.setContinuousLayout(true);
   }
   //This method is called in valueChanged, treeCollapsed and treeExpanded
   //to paint the selection rectangle:
   private void paintSelectionRect() {
       //Get selected row bounds:
       int[] rows = tree.getSelectionRows();
       if (rows == null) {
           selectedRowBounds = null;
           return;
       }
       selectedRowBounds = tree.getRowBounds(rows[0]);
       //Repaint the JTree:
       tree.repaint();
   }
   public static void main(final String[] args) {
       Runnable gui = new Runnable() {
           @Override
           public void run() {
               try {
                   UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
               } catch (Exception ex) {
                   ex.printStackTrace();
               }
               new TreeTable().setVisible(true);
           }
       };
       //GUI must start on EventDispatchThread:
       SwingUtilities.invokeLater(gui);
   }

}</code=java>