JTreeTable 的动态列

Dynamic columns for JTreeTable

我正在构建一个 JTreeTable。我找到了一些入门代码并且已经走了很远。最后,我的目标是能够像层次列表一样在不同级别拥有不同的数据。

目前,我使用它处理不同级别的数据。但是,在将更改列作为下一个目标时,我 运行 遇到了困难。从我目前的立场来看,我还有 3 个里程碑:

我快要完成这个任务了,但又卡在了这 3 个中的第一个。

由于创建 JTreeTable 很复杂,因此最小示例利用了下图中列出的几个 class:

我很高兴 post 任何这些 classes 的代码,但我也不希望用无用的代码阻塞问题。首先让我展示一下我想要的功能。

第一张图是selected时的顶层,第二张图是selected时的第二层。请注意列的不同之处。这就是我希望在我的申请中发生的事情。

顶级 selected:

二级 selected:

所以我尝试解决这个问题的一种方法是在这段代码中更改列表 selection:

ListSelectionListener listener = (ListSelectionEvent e) -> {
        TreeTableModelAdapter adapter = (TreeTableModelAdapter) JTreeTable.this.getModel();
        //Need to see why this breaks.
        JTreeTable.this.getTableHeader().setColumnModel(adapter.getColumnModel());
    };
    this.getSelectionModel().addListSelectionListener(listener);

这段代码在JTreeTable 的初始化中。我也尝试在 TableHeader 和 table 上设置列模型。下面是当我 select 一行时发生的情况:

这些列在我身上消失了。使用以下方法在 TreeTableModelAdapter class 中创建列模型:

public TableColumnModel getColumnModel(){
     DefaultTableColumnModel model  = new DefaultTableColumnModel();
     for(int i=0;i<getColumnCount();i++){
         TableColumn column = new TableColumn();
         column.setIdentifier(getColumnName(i));
         model.addColumn(column);
     }
     return model;
 }

任何方向都会很有帮助。再次高兴 post 任何您认为有助于回答问题的代码。只需发表评论,我会立即添加。

我会添加我发现的里程碑,以防对其他人有帮助,但现在这个问题已经得到解答。

里程碑 1

我实际上能够解决第一个里程碑。关键是触发创建列模型的列,而不是创建新的列模型。以下是更改行选择时的代码:

//Change columns depending on row
ListSelectionListener listener = (ListSelectionEvent e) -> {
    createDefaultColumnsFromModel();
};
this.getSelectionModel().addListSelectionListener(listener);

此代码根据在 JTreeTableJTree 部分中选择的行创建列。 TreeTableModelAdapter 通过还将 JTree 中的选定行传递给 JTreeTableModel 来实现 getColumnCount()getColumnName() 方法,以便动态检索列及其名称基于 JTree 中的特定节点。对我来说,关键是触发那些再次被调用以更新 JTreeTable.

里程碑 2

事实证明,根据数据级别调整列宽比我原先预期的要困难得多。为了在列模型更改时保留单元格状态,我必须断开单元格的绘制。这是一个复杂的过程,因为这是在 BasicTableUI 内部完成的,并且获取单元格矩形的方法是私有的。所以我不得不 subclass 它,重载 paint() 方法并创建我自己的方法,这些方法在 paint 方法中被调用。有很多复制粘贴,这样我就可以正常调用私有方法。我只是重命名了它们并引用了这些方法。 ui class 的设计方式并不十分灵活。下面是我选择不同级别的 2 个图像,并且列在不同级别的宽度明显不同。

里程碑 3

我能够通过跟踪模型中的视图来完成这项工作。这对我来说似乎很脏,因为模型应该与视图分开。由于树列的 class 是唯一的,如果该列是视图中的第一列,我只返回正确的 class。

我在使用此技术时遇到的一个问题是,我得到了返回值不一致的意外行为。我试图通过覆盖 JTree.covertValueToText() 来解决这个问题。由于 JTree 只需要 1 个值,并且根据视图中列的顺序,此值可能会更改。因此,在覆盖此方法时,我检查了 JTree 列值的存储索引。这再次导致意外行为。如果找到修复程序,我会更新 post。