1

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

这是更新后的新成就表模型以反映某些答案的输入。

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 可以选择要显示的数据。TableModel 通过调用 model.replace(cells) 进行更新,然后再次运行上述表格创建代码。

在 GUI JTable 中选择一行并打印 table.getSelectedRow() 值时,即使我重新选择了第一个 JComboBox选项。我失踪有什么原因吗?我应该更改一些代码吗?

编辑:代码在尝试回答这个问题时发生了很大变化,所以这里是更新的代码。新的成就表模型在上面。

这将设置模型和表以正确查看并显示在 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);
4

8 回答 8

2

调用替换后,您不应该使用新的 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);
   }

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

于 2009-06-25T20:58:56.570 回答
2

好的,现在我有兴趣了

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

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

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

Object[][]无论如何,如果您用作数据,则不需要子类。

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

我用你的自定义TableModelDefaultTableModel

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

我希望这有帮助。

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.

替代文字

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

于 2009-06-25T21:56:49.137 回答
1

也许尝试使用

super.setDataVector(Vector dataVector, Vector ColumnNames);

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

来自 JavaDoc

用新的行向量 dataVector 替换当前的 dataVector 实例变量。每行在 dataVector 中表示为 Object 值的 Vector。columnIdentifiers 是新列的名称。columnIdentifiers 中的第一个名称映射到 dataVector 中的第 0 列。调整 dataVector 中的每一行以匹配 columnIdentifiers 中的列数,方法是如果 Vector 太长则截断该 Vector,或者如果它太短则添加空值。请注意,为 dataVector 传入空值会导致未指定的行为,这可能是一个异常。参数: dataVector - 新的数据向量 columnIdentifiers - 列的名称

于 2009-06-25T21:06:56.460 回答
1

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

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

于 2009-06-25T20:36:54.773 回答
0

当您重新排序 JTable 时,您需要跟踪 TableModel 中数据的原始索引,而不是 JTable 上的当前索引。从视觉上看,表可能已经发生了变化,但底层数据模型没有。

于 2009-06-25T20:35:03.857 回答
0

听起来像是在更改您的选择时丢失了。

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

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

可能您需要为此使用自 定义ListSelectionModel

于 2009-06-25T20:40:22.473 回答
0

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

final int selectedRowIndex = table.rowAtPoint(mouseEvent.getPoint());
final int modelRowIndex = table.convertRowIndexToModel(selectedRowIndex);
于 2012-10-01T09:24:07.770 回答
0

我想到的另一件事是,当您table= new JTable(model);更改变量“表”所指的表时,这可能不会自动导致新表被呈现。

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

于 2009-06-25T21:40:18.950 回答