JTable无法正确返回所选行

时间:2009-06-25 20:32:13

标签: java user-interface jtable selection

我正在使用DefaultTableModel的扩展,如下所示:

这是更新后的新AchievementTableModel,以反映某些答案的输入。

public AchievementTableModel(Object[][] c, Object[] co) {
    super(c,co);
}
public boolean isCellEditable(int r, int c) {return false;}
public void replace(Object[][] c, Object[] co) {
    setDataVector(convertToVector(c), convertToVector(co));
    fireTableDataChanged();
}

我的GUI是一个具有以下属性的JTable:

if(table==null)
    table = new JTable(model);
else
    table.setModel(model);
table.setFillsViewportHeight(true);
table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
table.getTableHeader().setReorderingAllowed(false);
table.getTableHeader().setResizingAllowed(false);
table.setSelectionMode(DefaultListSelectionModel.SINGLE_SELECTION);
table.getColumnModel().setColumnSelectionAllowed(false);

我有一个JComboBox,可以选择要显示的数据。通过调用model.replace(cells)更新TableModel,然后再次运行上面的表创建代码。

当在GUI JTable中选择一行并打印table.getSelectedRow()值时,即使我重新选择,在使用来自第一个选择的model.replace(cells)调用更改表数据后,我总是得到-1第一个JComboBox选项。这是否有理由让我失踪?我应该更改一些代码吗?

编辑:代码在尝试回答此问题时发生了很大变化,因此这里是更新后的代码。新的AchievementTableModel就在上面。

这将设置要正确查看的模型和表格并显示在ScrollPane

if(model==null)
    model = new AchievementTableModel(cells, columns);
else
    model.replace(cells, columns);
if(table==null) {
    table = new JTable(model);
    table.setFillsViewportHeight(true);
    table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
    table.getTableHeader().setReorderingAllowed(false);
    table.setSelectionMode(DefaultListSelectionModel.SINGLE_SELECTION);
    table.getColumnModel().setColumnSelectionAllowed(false);
    table.getTableHeader().setResizingAllowed(false);
} else
    table.setModel(model);

column = table.getColumn(columns[0]);
column.setPreferredWidth(25);
column = table.getColumn(columns[1]);
column.setPreferredWidth(225);
column = table.getColumn(columns[2]);
column.setPreferredWidth(40);
table.doLayout();

add(new JScrollPane(table), BorderLayout.CENTER);

8 个答案:

答案 0 :(得分:2)

在调用replace后,您不应该使用新的JTable重新初始化您的表。 fireTableDataChanged()方法将提醒您现有的表应该重绘它。发生的事情是你正在查看放入面板的表,但是你正在将变量更改为不同的JTable实例。当您查询新的但不可见的表时,它将为您提供所选行数的-1。如果您编辑帖子以显示代码区域内的内容,则可能会有所帮助。

第二次修改:

而不是:

  if(model==null)
    model = new AchievementTableModel(cells, columns);
  else
    model.replace(cells, columns);
  if(table==null) {
    table = new JTable(model);
    table.setFillsViewportHeight(true);
    table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
    table.getTableHeader().setReorderingAllowed(false);
    table.setSelectionMode(DefaultListSelectionModel.SINGLE_SELECTION);
    table.getColumnModel().setColumnSelectionAllowed(false);
    table.getTableHeader().setResizingAllowed(false);
  } else
    table.setModel(model);

  column = table.getColumn(columns[0]);
  column.setPreferredWidth(25);
  column = table.getColumn(columns[1]);
  column.setPreferredWidth(225);
  column = table.getColumn(columns[2]);
  column.setPreferredWidth(40);
  table.doLayout();

  add(new JScrollPane(table), BorderLayout.CENTER);

改为:

 if(model==null) {
    model = new AchievementTableModel(cells, columns);
 } else {
    model.setDataVector(cells, columns);
 }
 if(table==null) {
    table = new JTable(model);
    table.setFillsViewportHeight(true);
    table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
    table.getTableHeader().setReorderingAllowed(false);
    table.setSelectionMode(DefaultListSelectionModel.SINGLE_SELECTION);
    table.getColumnModel().setColumnSelectionAllowed(false);
    table.getTableHeader().setResizingAllowed(false);

    column = table.getColumn(columns[0]);
    column.setPreferredWidth(25);
    column = table.getColumn(columns[1]);
    column.setPreferredWidth(225);
    column = table.getColumn(columns[2]);
    column.setPreferredWidth(40);
    table.doLayout();

    add(new JScrollPane(table), BorderLayout.CENTER);
   } else {
    table.setModel(model);
   }

您不需要将表格添加到新的滚动窗格中,并在每次模型更改时将其重新添加到面板中。

答案 1 :(得分:2)

好的,现在我很感兴趣

看起来你必须真正清理你的代码,因为周围有很多引用。

您没有看到具有所选索引的表的原因是因为每次创建新的JTable时,打印所选记录的方法仍指向原始记录。由于您现在正在显示“新”创建的表格,因此旧表格会打印-1

使用DefaultTableModel时获得空表的原因是因为向量是null(可能是从组合中获得的),因此数据和标题都会从表中消失。

如果您正在使用Object[][]作为数据,则不需要子类。

所以这是一个更简单的测试类,你可以看到它来纠正你的。

我使用您的自定义 TableModel DefaultTableModel

进行测试

这与您的自定义表格模型无关,而与您使用引用的方式无关。

我希望这会有所帮助。

import javax.swing.*;
import java.awt.*;
import javax.swing.table.*;
import java.util.*;
import java.awt.event.*;
public class Test { 

    private DefaultTableModel tableModel = null;
    //private AchievementTableModel tableModel = null;
    private Object []   headers = new Object[]{"Name", "Last Name"};
    private Object [][] data;
    private Object [][] dataA = new Object[][]{{"Oscar","Reyes"},{"John","Doe"}};
    private Object [][] dataB = new Object[][]{{"Color","Green"},{"Thing","Car"}};
    private JTable table;


    public static void main( String [] args ) { 
        Test test = new Test();
        test.main();
    }
    public void main() { 
        // Create the frame
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

        // Create the unique table.
        table = new JTable();
        frame.add(new JScrollPane( table ));

        // Add two buttons
        frame.add( new JPanel(){{ 
            // swap table model button ( simulates combo )
            add(new JButton("Change Table model"){{
                addActionListener( new ActionListener() { 
                    public void actionPerformed( ActionEvent e ) { 
                        if( tableModel == null ) { 
                            data = dataA;
                            tableModel = new DefaultTableModel( data, headers );
                            //tableModel = new AchievementTableModel( data, headers );
                            table.setModel( tableModel );
                        } else { 
                            data = data == dataA ? dataB : dataA;
                            tableModel.setDataVector( data, headers );
                            //tableModel.replace( data ); // not needed DefaultTableModel already has it.

                        }
                    }
                });
            }});
            // and print selectedRow button
            add( new JButton("Print selected row"){{
                addActionListener( new ActionListener() { 
                    public void actionPerformed( ActionEvent e ) { 
                        System.out.println(table.getSelectedRow());
                    }
                });
            }});

        }}, BorderLayout.SOUTH);

        // show the frame
        frame.pack();
        frame.setVisible( true );
    }

}

您的子类未更改。

class AchievementTableModel extends DefaultTableModel {

    public AchievementTableModel(Object[][] c, Object[] co) {
        super.dataVector = super.convertToVector(c);
        super.columnIdentifiers = super.convertToVector(co);
    }
    public int getColumnCount() {return super.columnIdentifiers.size();}
    public int getRowCount() {return super.dataVector.size();}
    public String getColumnName(int c) {return (String)super.columnIdentifiers.get(c);}
    @SuppressWarnings("unchecked")
    public Object getValueAt(int r, int c) {return ((Vector<Object>)super.dataVector.get(r)).get(c);}
    public boolean isCellEditable(int r, int c) {return false;}
    public void replace(Object[][] c) {
        super.dataVector = super.convertToVector(c);
        super.fireTableDataChanged();
    }
}

尝试一下,看看它如何不会丢失表格参考,并始终打印正确的selectedRow

alt text

将它与您的代码进行比较并从那里修复它。

答案 2 :(得分:1)

当它交换数据时,它删除了选择(因为索引现在不同),你需要重新计算选择并以编程方式设置它。

我会指出,根据我的经验,这就是为什么我倾向于扩展AbstractTableModel或者从头开始实现我自己的TableModel接口。像这里修改后备数据引用,总会导致一百万个问题恕我直言。

答案 3 :(得分:1)

也许尝试使用

super.setDataVector(Vector dataVector,Vector ColumnNames);

javax.​swing.​table.​DefaultTableModel
public void setDataVector(Vector dataVector, Vector columnIdentifiers)
  

来自JavaDoc

     

替换当前的dataVector   带有新Vector的实例变量   行,dataVector。每一行都是   在dataVector中表示为Vector   对象值。 columnIdentifiers   是新列的名称。该   columnIdentifiers中的名字是   映射到dataVector中的第0列。每   dataVector中的行被调整为匹配   中的列数   columnIdentifiers要么截断   Vector如果太长,或者   如果太短,则添加空值。   请注意,传入null值   dataVector导致未指定   行为,可能是一个例外。   参数:dataVector - 新数据   vector columnIdentifiers - 名称   列

答案 4 :(得分:0)

重新排序JTable时,需要跟踪TableModel中数据的原始索引,而不是JTable上的当前索引。在视觉上,表可能已经移位,但基础数据模型没有。

答案 5 :(得分:0)

听到更改您的选择时丢失了。

“getSelectedRow()”是否会在更改模型后“返回”之前返回任何内容?

如果是,则保持该索引,更改模型,然后再次设置该索引。

您可能需要为该

使用自定义ListSelectionModel

答案 6 :(得分:0)

我想到的另一件事是,当你执行table= new JTable(model);时,你正在更改变量'table'所引用的表,但是这可能不会自动导致新表被渲染。

如果您的表包含在ScrollPane中,则可能需要调用ScrollPane.setViewportView(table);

答案 7 :(得分:0)

我有同样的问题,总是为getSelectedRow()得到-1。这个问题现在可以解决了。尽管如此,发布修复我的问题的代码:

final int selectedRowIndex = table.rowAtPoint(mouseEvent.getPoint());
final int modelRowIndex = table.convertRowIndexToModel(selectedRowIndex);