如何在Swing Java中使JTable中的列不可见

49

我设计了一个GUI界面,其中使用了一个JTable表格,现在我需要将其中的2列设置为不可见。请问应该如何实现?

8个回答

73

TableColumnModel 中移除 TableColumn

TableColumnModel tcm = table.getColumnModel();
tcm.removeColumn( tcm.getColumn(...) );
如果您需要访问数据,则使用table.getModel().getValueAt(...)
如果需要更复杂的解决方案,允许用户根据需要隐藏/显示列,请参考表格列管理器

2
这是真正正确的做法 - 将宽度设置为0有点虚假。这样,您仍然可以在模型中使用数据;您只是隐藏了部分视图。 - M1EK
4
即使采用上述方法,数据仍然存在于模型中,这就是为什么可以像上面演示的那样访问它的原因。这就是MVC的工作方式。我们所做的只是改变视图。当您将宽度设置为0时,请尝试使用Tab键,在隐藏列处聚焦后,焦点会消失,直到您再次按下Tab键。这会让用户感到困惑。 - camickr
这个方法基本可行,但有一个问题使得这种方法无用。当你想知道你选择的列时,你会得到错误(偏移)的列索引。换句话说,执行table.getColumnModel().getSelectedColumns()将会给你一个错误的列。 - Dima
实际上我错了...使用column.getModelIndex()可以在模型中得到正确的位置。只是不要使用table.getSelectedColumn() - 这会给出错误的索引。 - Dima
3
@Dima 你需要理解“视图”和“模型”的区别。表格方法总是涉及到视图。JTable API有许多convertXXX方法可供使用。因此,你可以使用convertColumnIndexToModel(...)方法。 - camickr
@xmedeko 一个_真正_完整的解决方案是使用SwingX :-) - kleopatra

39

首先从视图中移除该列

 table.removeColumn(table.getColumnModel().getColumn(4));

然后从模型中检索数据。

table.getModel().getValueAt(table.getSelectedRow(),4);

需要注意的一点是,在检索数据时,必须从模型中检索而不是从表格中检索。


如何从模型中移除? - partho

22

我尝试了两种可能的解决方案,它们都有效,但在第一个解决方案中遇到了一些问题。

   table.removeColumn(table.getColumnModel().getColumn(4));
或者
   table.getColumnModel().getColumn(4).setMinWidth(0);
   table.getColumnModel().getColumn(4).setMaxWidth(0);
   table.getColumnModel().getColumn(4).setWidth(0);

在我最近的情况下,我更喜欢第二种解决方案,因为我添加了一个TableRowSorter

   TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model);
   table.setRowSorter(sorter);
使用table.removeColumn(table.getColumnModel().getColumn(4))会从视图/表中实际删除列,因此您不能使用table.getValueAt(row, 4) - 它返回ArrayIndexOutOfBounds。获取已删除列的值的唯一方法是调用table.getModel().getValueAt(table.getSelectedRow(),4)。由于TableRowSorter仅对表上的内容进行排序,而不对DefaultTableModel对象中的数据进行排序,所以问题出现在在排序记录后获取该值时 - 它将从未排序的DefaultModelObject检索数据。

因此我使用了第二种解决方案,然后使用table.getValueAt(table.getSelectedRow(),4);

我看到第二种方法的唯一问题是由@camickr提到的:"当您将宽度设置为0时,请尝试制表符,在隐藏的列命中之前,焦点消失,直到再次制表符。这将使用户困惑。"


7
使用“table.getModel().getValueAt(table.convertRowIndexToModel(row), 4)”代码。 - xmedeko

8

将最小、最大和“正常”宽度设置为0:

jTable.getColumn("ABC").setMinWidth(0); // Must be set before maxWidth!!
jTable.getColumn("ABC").setMaxWidth(0);
jTable.getColumn("ABC").setWidth(0);

注意:由于无法设置maxWidth小于minWidth,因此您需要首先更改minWidth。同样适用于width。(参见javadoc
第二种方法是扩展TableColumnModel并覆盖所有方法,以创建假象(对于JTable)使您的模型没有这两列。
因此,当您隐藏一列时,必须在表格询问列数时返回少一个,并且当它请求列X时,您可能需要添加+1到列索引(取决于它是否在隐藏列的左侧或右侧),等等。
让您的新表格模型将所有方法调用(使用校正后的索引等)转发到实际列模型,并在JTable中使用新表格模型。

1
您还必须设置最小和最大宽度。 - Aaron Digulla
为什么顺序很重要,我之前尝试了一下,没有使用相同的顺序,结果就无法工作。当我按照相同的顺序(宽度、最小值、最大值)进行操作时,它就可以正常工作了,所以为什么呢? - Mohammed Housseyn Taleb
1
有趣。看起来这些不是简单的设置器。我猜测监听器被安装以更新布局,而在Swing中布局通常是令人惊讶的。 - Aaron Digulla
1
@MohammedHousseynTaleb 感谢您的评论。我也按错误顺序执行了,现在查看了代码:this.maxWidth = Math.max(minWidth, maxWidth);现在应该很清楚了。如果将minWidth设置为10,并且您想将maxWidth设置为0,则会采用minWidth...实际上,在javadoc中也提到了这一点(但我也没有阅读)。 - Tomate_Salat

7

我曾经遇到同样的问题,因为我使用了TableColumnModel,所以removeColumn();无法解决我的问题,所以我使用了以下方法:

table.getColumnModel().getColumn(0).setWidth(0);
table.getColumnModel().getColumn(0).setMinWidth(0);
table.getColumnModel().getColumn(0).setMaxWidth(0); 

这对我来说很好用,它隐藏了第0列,但我仍然能够获取其中的值。


不确定为什么这些建议会重复多次。它最早是在7年前提出的,而且说实话那时候就是一个糟糕的建议。设置列宽并不能将列从表格中移除,只是隐藏了数据。用户仍然需要通过这一列进行切换,这很令人困惑。请不要这样做。 - camickr

-1

如果您从JTable中删除列,则该列仍然存在于TableModel中。

例如,要删除第一个ID列:

TableColumnModel tcm = table.getColumnModel();
tcm.removeColumn(tcm.getColumn(0));

如果您想访问已删除列的值,则必须通过TableModelgetValueAt函数访问它,而不是通过JTable。但是,您必须将rowIndex转换回模型中的rowIndex。

例如,如果您想访问所选行的第一列:

int modelRow = table.convertRowIndexToModel(table.getSelectedRow());
int value = (Integer)table.getModel().getValueAt(modelRow,0);

(1)已经说明过,你需要从模型中获取数据,而不是表格。 (2)行索引与列无关。即使列没有被移除,你仍然需要转换行索引。 - camickr

-3

我已经尝试了所有方法:它们都没有帮助。最好的方法是创建一个新的表模型,不包含您想要删除的列。以下是操作步骤:

table = (DefaultTableModel) <table name>.getModel();
DefaultTableModel table1 = new DefaultTableModel();
Vector v = table.getDataVector();
Vector v1 = newvector(v,<column index you want to delete>);

Vector newvector(Vector v,int j){
    Vector v1= new Vector();
    try{
        Vector v2;
        Object[] o = v.toArray();
        int i =0;
        while(i<o.length){
            v2 = (Vector) o[i];
            v2.remove(j);
            v1.add(v2);
            i++;
        }
    }
    catch(Exception e){
        JOptionPane.showMessageDialog(null,"Error in newvector \n"+e);
    }
    return v1;
}

Vector getColumnIdentifiers(int i) {
    Vector columnIdentifiers = new Vector();
    int j=0;
    while(j<i){
        columnIdentifiers.add(("c"+(j+1)));
        j++;
    }
    return columnIdentifiers;
}
table1.setDataVector(v1,getColumnIdentifiers((<column count>-1)));
<table name>.setModel(table1);

-4
您可以创建模型的子类,并覆盖 TableModel.getColumnCount 方法,如下所示:
int getColumnCount() {
    return super.getColumnCount()-2;
}

然后,最后两列将不会在JTable中显示。


但是我可以从它们那里获取数据吗? - om.
你只是在创造列不存在的假象,但它们仍然存在,因此应该能够获取数据。 - dharga
但是我应该如何从GUI中隐藏它们呢? - om.
我不确定我理解你的意思。你是指你的应用程序用户应该能够隐藏或显示什么? - Maurice Perry
嘿,我通过使用以下代码解决了那个问题:jtable.removeColumn(jtable.getColumnModel().getColumn());该列从GUI中隐藏了,并且我们还可以从中获取存储的值。 - om.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接