JTable 未正确返回所选行

发布于 2024-07-25 10:19:19 字数 2046 浏览 6 评论 0原文

我正在使用 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,在使用第一个选择中的 model.replace(cells) 调用更改表数据后,我总是得到 -1选项。 我失踪了有什么原因吗? 我应该更改一些代码吗?

编辑:代码在尝试回答这个问题时发生了很大的变化,所以这里是更新的代码。 新的 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);

I am working with an extension of the DefaultTableModel as follows:

This is the NEW AchievementTableModel after updating it to reflect input from some answers.

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:

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. The TableModel is updated with a call to model.replace(cells) and then runs through the above table creation code again.

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. 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.

This sets up the model and table to be viewed correctly and displayed in a 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);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

℉服软 2024-08-01 10:19:20

我遇到了同样的问题,getSelectedRow() 总是得到 -1。 问题现在本来可以解决了。 尽管如此,发布解决我的问题的代码:

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

I had the same problem of getting a -1 always for getSelectedRow(). 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);
凝望流年 2024-08-01 10:19:19

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

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

you shouldnt reinitialize your table with a new JTable after you call replace. the fireTableDataChanged() method will alert your existing table that it should repaint. 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. When you query that new, but not visible table, it will give you -1 for the selected row count. 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.

如若梦似彩虹 2024-08-01 10:19:19

好吧,现在我感兴趣了,

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

您看不到具有选定索引的表的原因是,每次创建新的 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

alt text

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

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. Since you're displaying now a "newly" created table the old one prints -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.

You don't need a subclass if you're using Object[][] as data anyway.

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

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.

alt text

Compare it with your code and fix it from there.

冷清清 2024-08-01 10:19:19

也许尝试使用

super.setDataVector(Vector dataVector, Vector ColumnNames);

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

来自 JavaDoc

替换当前的 dataVector
带有新 Vector 的实例变量
行数,数据向量。 每行是
在 dataVector 中表示为 Vector
对象值。 列标识符
是新列的名称。 这
columnIdentifiers 中的名字是
映射到 dataVector 中的第 0 列。 每个
dataVector 中的行调整为匹配
中的列数
列标识符可以通过截断
如果 Vector 太长,或者
如果太短则添加空值。
请注意,为
dataVector 结果未指定
行为,可能是一个例外。
参数: dataVector - 新数据
向量列标识符 - 名称
列数

Maybe try using

super.setDataVector(Vector dataVector, Vector ColumnNames);

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

From JavaDoc

Replaces the current dataVector
instance variable with the new Vector
of rows, dataVector. Each row is
represented in dataVector as a Vector
of Object values. columnIdentifiers
are the names of the new columns. The
first name in columnIdentifiers is
mapped to column 0 in dataVector. 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.
Note that passing in a null value for
dataVector results in unspecified
behavior, an possibly an exception.
Parameters: dataVector - the new data
vector columnIdentifiers - the names
of the columns

二智少女猫性小仙女 2024-08-01 10:19:19

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

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

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. Modifying the backing data reference as here, always causes a million problems IMHO.

我乃一代侩神 2024-08-01 10:19:19

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

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. Visually the table may have shifted but the underlying data model has not.

余厌 2024-08-01 10:19:19

听起来好像更改选择时丢失了。

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

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

可能您需要使用自定义 ListSelectionModel为了那个原因

Sounds like when changing your selection is lost.

Does "getSelectedRow()" return anything "BEFORE" you change the model?

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

世俗缘 2024-08-01 10:19:19

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

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

Another thing I thought of, when you do 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);

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文