JTreeTable 的动态列
Dynamic columns for JTreeTable
我正在构建一个 JTreeTable。我找到了一些入门代码并且已经走了很远。最后,我的目标是能够像层次列表一样在不同级别拥有不同的数据。
目前,我使用它处理不同级别的数据。但是,在将更改列作为下一个目标时,我 运行 遇到了困难。从我目前的立场来看,我还有 3 个里程碑:
- 显示不同级别的不同列集
- 能够针对不同级别调整列宽
- 确保 table 的 JTree 部分始终保持在左侧
我快要完成这个任务了,但又卡在了这 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);
此代码根据在 JTreeTable
的 JTree
部分中选择的行创建列。 TreeTableModelAdapter
通过还将 JTree
中的选定行传递给 JTreeTableModel
来实现 getColumnCount()
和 getColumnName()
方法,以便动态检索列及其名称基于 JTree
中的特定节点。对我来说,关键是触发那些再次被调用以更新 JTreeTable
.
里程碑 2
事实证明,根据数据级别调整列宽比我原先预期的要困难得多。为了在列模型更改时保留单元格状态,我必须断开单元格的绘制。这是一个复杂的过程,因为这是在 BasicTableUI
内部完成的,并且获取单元格矩形的方法是私有的。所以我不得不 subclass 它,重载 paint()
方法并创建我自己的方法,这些方法在 paint 方法中被调用。有很多复制粘贴,这样我就可以正常调用私有方法。我只是重命名了它们并引用了这些方法。 ui class 的设计方式并不十分灵活。下面是我选择不同级别的 2 个图像,并且列在不同级别的宽度明显不同。
里程碑 3
我能够通过跟踪模型中的视图来完成这项工作。这对我来说似乎很脏,因为模型应该与视图分开。由于树列的 class 是唯一的,如果该列是视图中的第一列,我只返回正确的 class。
我在使用此技术时遇到的一个问题是,我得到了返回值不一致的意外行为。我试图通过覆盖 JTree.covertValueToText()
来解决这个问题。由于 JTree 只需要 1 个值,并且根据视图中列的顺序,此值可能会更改。因此,在覆盖此方法时,我检查了 JTree 列值的存储索引。这再次导致意外行为。如果找到修复程序,我会更新 post。
我正在构建一个 JTreeTable。我找到了一些入门代码并且已经走了很远。最后,我的目标是能够像层次列表一样在不同级别拥有不同的数据。
目前,我使用它处理不同级别的数据。但是,在将更改列作为下一个目标时,我 运行 遇到了困难。从我目前的立场来看,我还有 3 个里程碑:
- 显示不同级别的不同列集
- 能够针对不同级别调整列宽
- 确保 table 的 JTree 部分始终保持在左侧
我快要完成这个任务了,但又卡在了这 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);
此代码根据在 JTreeTable
的 JTree
部分中选择的行创建列。 TreeTableModelAdapter
通过还将 JTree
中的选定行传递给 JTreeTableModel
来实现 getColumnCount()
和 getColumnName()
方法,以便动态检索列及其名称基于 JTree
中的特定节点。对我来说,关键是触发那些再次被调用以更新 JTreeTable
.
里程碑 2
事实证明,根据数据级别调整列宽比我原先预期的要困难得多。为了在列模型更改时保留单元格状态,我必须断开单元格的绘制。这是一个复杂的过程,因为这是在 BasicTableUI
内部完成的,并且获取单元格矩形的方法是私有的。所以我不得不 subclass 它,重载 paint()
方法并创建我自己的方法,这些方法在 paint 方法中被调用。有很多复制粘贴,这样我就可以正常调用私有方法。我只是重命名了它们并引用了这些方法。 ui class 的设计方式并不十分灵活。下面是我选择不同级别的 2 个图像,并且列在不同级别的宽度明显不同。
里程碑 3
我能够通过跟踪模型中的视图来完成这项工作。这对我来说似乎很脏,因为模型应该与视图分开。由于树列的 class 是唯一的,如果该列是视图中的第一列,我只返回正确的 class。
我在使用此技术时遇到的一个问题是,我得到了返回值不一致的意外行为。我试图通过覆盖 JTree.covertValueToText()
来解决这个问题。由于 JTree 只需要 1 个值,并且根据视图中列的顺序,此值可能会更改。因此,在覆盖此方法时,我检查了 JTree 列值的存储索引。这再次导致意外行为。如果找到修复程序,我会更新 post。