简体   繁体   English

JTable无法正确返回所选行

[英]JTable not returning selected row correctly

I am working with an extension of the DefaultTableModel as follows: 我正在使用DefaultTableModel的扩展,如下所示:

This is the NEW AchievementTableModel after updating it to reflect input from some answers. 这是更新后的NEW 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();
}

My GUI is a JTable that has the following properties: 我的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);

I have a JComboBox that selects which data to display. 我有一个JComboBox,可以选择要显示的数据。 The TableModel is updated with a call to model.replace(cells) and then runs through the above table creation code again. 通过调用model.replace(cells)更新TableModel,然后再次运行上述表创建代码。

When selecting a row in the GUI JTable, and printing the table.getSelectedRow() value, I ALWAYS get -1 after changing the table data with a model.replace(cells) call from the first selection, even if I reselect the first JComboBox option. 当在GUI JTable中选择一行并打印table.getSelectedRow()值时,即使从第一个选择中选择了model.replace(cells)调用来更改表数据后,即使我重新选择了第一个JComboBox,我也总是得到-1选项。 Is there a reason for this that I'm missing? 有没有我想念的原因? Should I change some code? 我应该更改一些代码吗?

EDIT: The code has changed a lot over trying to answer this question so here is the updated code. 编辑:在试图回答这个问题的代码已经发生了很大的变化,所以这里是更新的代码。 The new AchievementTableModel is above. 上面是新的AchievementTableModel。

This sets up the model and table to be viewed correctly and displayed in a ScrollPane 这会将模型和表格设置为正确查看并显示在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);

you shouldnt reinitialize your table with a new JTable after you call replace. 您不应在调用replace之后使用新的JTable重新初始化表。 the fireTableDataChanged() method will alert your existing table that it should repaint. fireTableDataChanged()方法将提醒您现有的表应重新绘制。 what is happening is that you are looking at the table that you put into the panel, but you are changing the variable to a different instance of JTable. 发生的情况是,您正在查看放入面板中的表,但是将变量更改为JTable的其他实例。 When you query that new, but not visible table, it will give you -1 for the selected row count. 当查询该新的但不可见的表时,它将为您提供-1的所选行数。 it might be helpful if you edit your post to display what is going on in that area of the code. 如果您编辑帖子以显示该代码区域中正在发生的事情,这可能会有所帮助。

2nd edit: 第二次编辑:

instead of this: 代替这个:

  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);

do this instead: 改为这样做:

 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);
   }

you dont need to add the table to a new scrollpane and re-add it to the panel on each model change. 您无需将表添加到新的滚动窗格,并在每次模型更改时将其重新添加到面板。

Ok, now I'm interested 好,现在我很感兴趣

It looks like you have to really really clean up your code because there are a lot of reference all around. 看起来您必须真正清理一下代码,因为周围有很多参考。

The reason you are not seeing the table with a selected index is because each time you create a new JTable the method where you print the selected record still points to the original. 之所以看不到具有选定索引的表,是因为每次创建新的JTable ,用于打印选定记录的方法仍指向原始索引。 Since you're displaying now a "newly" created table the old one prints -1 . 由于您现在显示的是“新创建”的表格,因此旧表格将显示-1

The reason you get empty table when using the DefaultTableModel is because the vectors are null ( perhaps obtained from the combo ) and thus both the data and the headers disappear from the table. 使用DefaultTableModel时获得空表的原因是因为向量为null (可能是从combo获得的),因此数据和标头都从表中消失了。

You don't need a subclass if you're using Object[][] as data anyway. 如果您仍将Object[][]用作数据,则不需要子类。

So here is a somehow simpler test class that you can see to correct yours. 因此,这里有一个更简单的测试类,您可以看到它来更正您的类。

I test it with both, your custom TableModel and the DefaultTableModel 我用您的自定义TableModelDefaultTableModel

This has nothing to do with your custom table model but the way you're using your references. 这与您的自定义表模型无关,而与您使用引用的方式有关。

I hope this helps. 我希望这有帮助。

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 );
    }

}

Your subclass unchanged. 您的子类保持不变。

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();
    }
}

Try it and see how it doesn't lose the table reference and always print the correct selectedRow . 尝试一下,看看它不会丢失表引用,并始终打印正确的selectedRow

替代文字

Compare it with your code and fix it from there. 将其与您的代码进行比较,然后从那里进行修复。

When it swaps out the data its removing the selection (since the index is now different), you'll need recalculate the selection and set it programmatically. 当它换出数据时,将删除选择(由于索引现在不同),因此您需要重新计算选择并以编程方式进行设置。

I'll point out that in my experience, this is why I tend to extend AbstractTableModel or out right implement my own TableModel interface from the ground up. 我将指出,根据我的经验,这就是为什么我倾向于扩展AbstractTableModel或完全从头实现我自己的TableModel接口的原因。 Modifying the backing data reference as here, always causes a million problems IMHO. 像此处那样修改后备数据引用,总是会引起一百万个问题,恕我直言。

Maybe try using 也许尝试使用

super.setDataVector(Vector dataVector, Vector ColumnNames); super.setDataVector(Vector dataVector,Vector ColumnNames);

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

From JavaDoc 从JavaDoc

Replaces the current dataVector instance variable with the new Vector of rows, dataVector. 用新的行向量dataVector替换当前的dataVector实例变量。 Each row is represented in dataVector as a Vector of Object values. 每行在dataVector中表示为Object值的Vector。 columnIdentifiers are the names of the new columns. columnIdentifiers是新列的名称。 The first name in columnIdentifiers is mapped to column 0 in dataVector. columnIdentifiers中的名字映射到dataVector中的第0列。 Each row in dataVector is adjusted to match the number of columns in columnIdentifiers either by truncating the Vector if it is too long, or adding null values if it is too short. 调整dataVector中的每一行以匹配columnIdentifiers中的列数,方法是:如果Vector太长则将其截断,如果它太短则将添加空值。 Note that passing in a null value for dataVector results in unspecified behavior, an possibly an exception. 请注意,为dataVector传递null值会导致未指定的行为,这可能是异常。 Parameters: dataVector - the new data vector columnIdentifiers - the names of the columns 参数:dataVector-新的数据向量columnIdentifiers-列的名称

When you reorder a JTable you need to keep track of the original indexes in the TableModel for your data, not the current indexes on the JTable. 对JTable重新排序时,需要跟踪TableModel中数据的原始索引,而不是JTable上的当前索引。 Visually the table may have shifted but the underlying data model has not. 从视觉上看,表可能已移动,但基础数据模型尚未移动。

Sounds like when changing your selection is lost. 听起来好像在更改选择时丢失了。

Does "getSelectedRow()" return anything "BEFORE" you change the model? 在更改模型之前,“ getSelectedRow()”是否会返回任何内容?

If so, then hold that index, change the model and then set that index again. 如果是这样,则保持该索引,更改模型,然后再次设置该索引。

Probably you need to use a custom ListSelectionModel for that 可能您需要为此使用自定义ListSelectionModel

Another thing I thought of, when you do table= new JTable(model); 我想到的另一件事,当您执行table= new JTable(model); you are changing the table that the variable 'table' is referring to, however that may not automatically cause the new table to be rendered. 您正在更改变量“表”所引用的表,但是可能不会自动导致呈现新表。

If you table is contained within a ScrollPane, you may need to call ScrollPane.setViewportView(table); 如果表包含在ScrollPane中,则可能需要调用ScrollPane.setViewportView(table);

I had the same problem of getting a -1 always for getSelectedRow(). 我也遇到同样的问题,始终为getSelectedRow()获得-1。 The problem could have got solved by now. 该问题现在可能已经解决。 Nonetheless, posting the code which fixed my problem: 尽管如此,发布解决了我的问题的代码:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM