java - JTable 单元格中的 JTree,很少有问题

标签 java swing jtable jtree listselectionlistener

对,我有一个 JTable,其中一列是 JTree,它看起来像这样

enter image description here

当我单击 JTree 单元格时,我希望它展开/折叠 JTree 并适当调整表行的高度。我似乎无法让它工作,有几个问题

a) JTree 的路径似乎默认是展开的 b) 单击 JTree 不会展开/折叠 JTree 或调整表格行的高度。

这是代码

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.util.Arrays;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTree;
import javax.swing.WindowConstants;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;

public class TestTableCellSelection {

  private String[] columnNames = {"JobID", "Status"};  
  private DefaultTableModel tableModel = new DefaultTableModel(null, columnNames) {
    private static final long serialVersionUID = 1L;

    @Override
    public Class<?> getColumnClass(int column) {
      return getValueAt(0, column).getClass();
    }

    @Override
    public boolean isCellEditable(int row, int col) {
      return false;
    }
  };

  private JTable table = new JTable(tableModel);

  public static void main(String... args) {
    EventQueue.invokeLater(new Runnable() {

      @Override
      public void run() {
        createAndShowGUI();
      }
    });
  }

  public static void createAndShowGUI() {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.getContentPane().add(new TestTableCellSelection().makeUI());
    frame.setSize(635, 566);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }

  private Component makeUI() {
    TableColumn statusColumn = table.getColumnModel().getColumn(1);
    statusColumn.setCellRenderer(new JTableJTreeRenderer());

    //Setup row/column selection listeners
    table.setRowSelectionAllowed(true);
    TableCellSelectionListener cellSelectionListener = new TableCellSelectionListener(table);
    //table.getSelectionModel().addListSelectionListener(cellSelectionListener);
    table.getColumnModel().getSelectionModel().addListSelectionListener(cellSelectionListener);

    EventQueue.invokeLater(new Runnable() {

      @Override
      public void run() {
        startTask(new Object[][]{{"000001"}, {"complete"}});
        startTask(new Object[][]{{"000002"}, {"processing","rendering pdf"}});
        startTask(new Object[][]{{"000003"}, {"processing","rendering pdf","rendering afp"}});
        startTask(new Object[][]{{"000004"}, {"processing","rendering pdf","rendering afp","rendering postscript"}});
        startTask(new Object[][]{{"000005"}, {"processing","normalsing","enhancing","sorting","rendering"}});
      }
    });
    JPanel p = new JPanel(new BorderLayout());
    p.add(new JScrollPane(table));
    return p;
  }

  private void startTask(Object[][] row) {    
    final String jobID = (String) row[0][0];

    final DefaultMutableTreeNode statusRoot = new DefaultMutableTreeNode((String)row[1][0]);

    final DefaultTreeModel statusTreeModel = new DefaultTreeModel(statusRoot);

    final JTree statusTree = new JTree(statusTreeModel);

    if(row[1].length > 1) {
      initStatusTree(statusRoot, Arrays.copyOfRange(row[1], 1, row[1].length, String[].class)); 
    }

    tableModel.addRow(new Object[]{jobID, statusTree});    
  }

  private void initStatusTree(DefaultMutableTreeNode root, String[] statusList) {
    for(String s: statusList) {
      root.add(new DefaultMutableTreeNode(s));
    }
  }

}


class TableCellSelectionListener implements ListSelectionListener {

  private JTable _t;

  public TableCellSelectionListener(JTable t) {
    _t = t;
  }

  @Override
  public void valueChanged(ListSelectionEvent arg0) {
    int rowSelected = _t.getSelectedRow();
    int colSelected = _t.getSelectedColumn();
    if(rowSelected > -1 && colSelected > -1) {
      System.out.println("Row selected: " +rowSelected);
      System.out.println("Column selected: " +colSelected);
      TableCellRenderer renderer = _t.getCellRenderer(rowSelected, colSelected);
      Object obj = _t.getValueAt(rowSelected, colSelected);
      Component c = renderer.getTableCellRendererComponent(_t, obj, false, false, rowSelected, colSelected);    
      if(c instanceof JTree) {
        TreePath path = ((JTree)c).getPathForRow(0);
        System.out.println("Path expanded: " +((JTree) c).isExpanded(path));
        if(((JTree) c).isExpanded(path)) {
          ((JTree)c).collapsePath(path);
          ((JTree) c).fireTreeCollapsed(path);
        } else {
          ((JTree)c).expandPath(path);
          ((JTree) c).fireTreeExpanded(path);
        }
        System.out.println("Path expanded: " +((JTree) c).isExpanded(path));
        _t.setRowHeight(rowSelected, c.getPreferredSize().height+50);
        ((DefaultTableModel)_t.getModel()).fireTableDataChanged();
      }
    }
  }

}

@SuppressWarnings("serial")
class JTableJTreeRenderer extends DefaultTableCellRenderer {

  private JTree tree = new JTree();
  private TreeCellRenderer renderer = new DefaultTreeCellRenderer();

  public JTableJTreeRenderer() {
    tree.setCellRenderer(renderer);
  }

  @Override
  public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {    
    tree.setModel(((JTree) value).getModel());
    table.setRowHeight(row, tree.getPreferredSize().height+50);
    return tree;
  }

}

从下面的println代码中可以看出

if(rowSelected > -1 && colSelected > -1) {
  System.out.println("Row selected: " +rowSelected);
  System.out.println("Column selected: " +colSelected);
  TableCellRenderer renderer = _t.getCellRenderer(rowSelected, colSelected);
  Object obj = _t.getValueAt(rowSelected, colSelected);
  Component c = renderer.getTableCellRendererComponent(_t, obj, false, false, rowSelected, colSelected);    
  if(c instanceof JTree) {
    TreePath path = ((JTree)c).getPathForRow(0);
    System.out.println("Path expanded: " +((JTree) c).isExpanded(path));
    if(((JTree) c).isExpanded(path)) {
      ((JTree)c).collapsePath(path);
      ((JTree) c).fireTreeCollapsed(path);
    } else {
      ((JTree)c).expandPath(path);
      ((JTree) c).fireTreeExpanded(path);
    }
    System.out.println("Path expanded: " +((JTree) c).isExpanded(path));
    _t.setRowHeight(rowSelected, c.getPreferredSize().height+50);
    ((DefaultTableModel)_t.getModel()).fireTableDataChanged();
  }
}

点击特定单元格两次的结果如下

Row selected: 2
Column selected: 1
Path expanded: true
Path expanded: false
Row selected: 2
Column selected: 1
Path expanded: true
Path expanded: false

正如您所看到的,路径恢复到之前的状态。有什么想法吗?

最佳答案

好吧,问题似乎出在渲染器本身,这是解决方案

      @Override
  public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    //Using the Renderers JTree was the mistake    
    //tree.setModel(((JTree) value).getModel());
    tree = (JTree)value;
    table.setRowHeight(row, tree.getPreferredSize().height+50);    
    return tree;
  }

关于java - JTable 单元格中的 JTree,很少有问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20998127/

相关文章:

java - 为什么 ArrayList 的构造函数 (ArrayList(int initialCapacity)) 调用其父类(super class)的默认构造函数?

java - 我如何停止重复调用 java paint() 替换最后一个?

java - Java JList格式与JTable的功能

jquery - jtable "Add new record"css 不显示

java - JTable 的 getSelectedColumn 不适用于更改模型

java - 在实时阶段在 VM 中启动 JVM 工具接口(interface)代理

java - 将对象添加到集合并按对象属性排序的有效方法。

java - JFrame 与 Main 中的其他类组合时无法打开

带有自定义标题栏的 java swing 应用程序?

java - 我可以在 Java 的构造函数中调用方法吗?