java 跨 TableModel 更改保留 JTable 选择

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/254212/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 11:38:54  来源:igfitidea点击:

Preserve JTable selection across TableModel change

javaswingjtabletablemodel

提问by John M

We're seeing JTableselection get cleared when we do a fireTableDataChanged()or fireTableRowsUpdated()from the TableModel.

我们看到JTable,当我们做一个选择被清除fireTableDataChanged()fireTableRowsUpdated()TableModel

Is this expected, or are we doing something wrong? I didn't see any property on the JTable(or other related classes) about clearing/preserving selection on model updates.

这是预期的,还是我们做错了什么?我没有看到JTable有关清除/保留模型更新选择的(或其他相关类)的任何属性。

If this is default behavior, is there a good way to prevent this? Maybe some way to "lock" the selection before the update and unlock after?

如果这是默认行为,是否有防止这种情况的好方法?也许某种方法可以在更新之前“锁定”选择并在之后解锁?

The developer has been experimenting with saving the selection before the update and re-applying it. It's a little slow.

开发人员一直在尝试在更新之前保存选择并重新应用它。它有点慢。

This is Java 1.4.2 on Windows XP, if that matters. We're limited to that version based on some vendor code we use.

如果这很重要,这是 Windows XP 上的 Java 1.4.2。根据我们使用的某些供应商代码,我们仅限于该版本。

采纳答案by Swapnonil Mukherjee

You need to preserve the selection and then re-apply it.

您需要保留选择,然后重新应用它。

First of all you will need to get a list of all the selected cells.

首先,您需要获取所有选定单元格的列表。

Then when you re-load the JTable with the new data you need to programmatically re-apply those same selections.

然后,当您使用新数据重新加载 JTable 时,您需要以编程方式重新应用那些相同的选择。

The other point I want to make is, if the number or rows or columns in your table are increasing or decreasing after each table model reload, then please don't bother preserving the selection.

我想说明的另一点是,如果您的表格中的行数或列数在每个表格模型重新加载后增加或减少,那么请不要费心保留选择。

The user could have selected row 2 column 1 having a value say "Duck", before model updation. But after model updation that same data can now occur in row 4 column 1, and your original cell row 2 column 1 could have new data such as "Pig". Now if you forcibly set the selection to what it was before the model updation, this may not be what the user wanted.

在模型更新之前,用户可能已经选择了第 2 行第 1 列,其值为“Duck”。但是在模型更新后,相同的数据现在可以出现在第 4 行第 1 列中,而您的原始单元格第 2 行第 1 列可能会有新数据,例如“猪”。现在,如果强行将选择设置为模型更新之前的状态,这可能不是用户想要的。

So programmatically selecting cells could be a double edged sword. Don't do it, if you are not sure.

因此,以编程方式选择单元格可能是一把双刃剑。如果您不确定,请不要这样做。

回答by Peter Berg

You can automatically preserve a table's selection if the STRUCTURE of that table hasn't changed (i.e. if you haven't add/removed any columns/rows) as follows.

如果表的 STRUCTURE 没有改变(即如果您没有添加/删除任何列/行),您可以自动保留表的选择,如下所示。

If you've written your own implementation of TableModel, you can simply override the fireTableDataChanged() method:

如果您已经编写了自己的 TableModel 实现,则可以简单地覆盖 fireTableDataChanged() 方法:

@Override
public void fireTableDataChanged() {
    fireTableChanged(new TableModelEvent(this, //tableModel
        0, //firstRow
        getRowCount() - 1, //lastRow 
        TableModelEvent.ALL_COLUMNS, //column 
        TableModelEvent.UPDATE)); //changeType
}

and this should ensure that your selection is maintained provided that only the data and not the structure of the table has changed. The only difference between this, and what would be called if this method weren't overridden is that getRowCount() - 1 is passed for the lastRow argument instead of Integer.MAX_VALUE, the latter of which acts a signifier that not only has all the data in the table changed but that the number of rows may have as well.

这应该确保您的选择得到维护,前提是只有数据而不是表的结构发生了变化。这之间的唯一区别,如果这个方法没有被覆盖,将会调用什么是 getRowCount() - 1 传递给 lastRow 参数而不是 Integer.MAX_VALUE,后者充当一个能指,不仅具有所有表中的数据发生了变化,但行数也可能发生了变化。

回答by Exceptyon

for reference, as @Swapnonil Mukherjee stated, this did the trick with a table with selectable rows:

作为参考,正如@Swapnonil Mukherjee 所说,这对带有可选行的表起到了作用:

// preserve selection calling fireTableDataChanged()
final int[] sel = table.getSelectedRows();

fireTableDataChanged();

for (int i=0; i<sel.length; i++)
    table.getSelectionModel().addSelectionInterval(sel[i], sel[i]);

回答by Rastislav Komara

This is default behavior. If you call fireTableDataChanged()the entire table is rebuild from scratch as you set entirely new model. In this case the selection is, naturally, lost. If you call fireTableRowsUpdated()the selection is also cleared in general cases. The only way is to remember selection and then set this. Unfortunately there is no guarantee that the selection will be still valid. Be careful if restoring selection.

这是默认行为。如果您调用fireTableDataChanged()整个表是从头开始重建为您设置全新的模型。在这种情况下,选择自然会丢失。如果您调用fireTableRowsUpdated()该选择,在一般情况下也会被清除。唯一的方法是记住选择,然后设置它。不幸的是,不能保证选择仍然有效。恢复选择时要小心。

回答by Mario Ortegón

I had the same issue in an application. In my case the model in the table was a list of objects, where the object properties where mapped to columns. In that case, when the list was modified, I retrieved the selected index and stored the object that was selected before updating the list. After the list is modified and before the table is updated, I would calculate the position of the selected object. If it was still present after the modification, then I would set the selection to the new index.

我在应用程序中遇到了同样的问题。在我的例子中,表中的模型是一个对象列表,其中对象属性映射到列。在这种情况下,当列表被修改时,我检索了选定的索引并存储了在更新列表之前选择的对象。在修改列表之后和更新表格之前,我会计算所选对象的位置。如果修改后它仍然存在,那么我会将选择设置为新索引。

Just setting the selected index in the table after the modification will not work, because the object may change position in the list.

修改后只在表格中设置选定的索引是行不通的,因为对象可能会改变列表中的位置。

As a side note, I found that working with GlazedLists makes life much easier when dealing with tables.

作为旁注,我发现在处理表格时使用 GlazedLists 可以让生活变得更轻松。

回答by PhiLho

If I recall correctly, saving selection and re-applying it is what we have done too...

如果我没记错的话,保存选择并重新应用它也是我们所做的......

回答by Ram Dutt Shukla

I was facing same issue and when tried to search the reason I got this question but it seems a bug in Java SDK. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4276786

我遇到了同样的问题,当我试图搜索我得到这个问题的原因时,它似乎是 Java SDK 中的一个错误。http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4276786

WORK AROUND

解决

A temporary work-around is available. It should be removed once this bug is fixed as it's suitability has NOT been tested against fixed releases.

可以使用临时解决方法。一旦这个错误被修复,它应该被删除,因为它的适用性尚未针对固定版本进行测试。

Use this subclass of JTable.

使用 JTable 的这个子类。

Note: This is for the MetalLookAndFeel. If using other look and feels, the inner FixedTableUI subclass will have to extend the TableUI subclass for that look and feel.

注意:这是用于 MetalLookAndFeel。如果使用其他外观,则内部 FixedTableUI 子类必须为该外观扩展 TableUI 子类。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.event.*;
import javax.swing.plaf.basic.*;

public class FixedTable extends JTable {

  private boolean isControlDownInDrag;

  public FixedTable(TableModel model) {
      super(model);
      setUI(new FixedTableUI());
  }

  private class FixedTableUI extends BasicTableUI {
      private MouseInputHandler handler = new MouseInputHandler() {
          public void mouseDragged(MouseEvent e) {
              if (e.isControlDown()) {
                  isControlDownInDrag = true;
              }
              super.mouseDragged(e);
          }

          public void mousePressed(MouseEvent e) {
              isControlDownInDrag = false;
              super.mousePressed(e);
          }

          public void mouseReleased(MouseEvent e) {
              isControlDownInDrag = false;
              super.mouseReleased(e);
          }
      };

      protected MouseInputListener createMouseInputListener() {
          return handler;
      }
  }

  public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
      if (isControlDownInDrag) {
          ListSelectionModel rsm = getSelectionModel();
          ListSelectionModel csm = getColumnModel().getSelectionModel();

          int anchorRow = rsm.getAnchorSelectionIndex();
          int anchorCol = csm.getAnchorSelectionIndex();

          boolean anchorSelected = isCellSelected(anchorRow, anchorCol);

          if (anchorSelected) {
              rsm.addSelectionInterval(anchorRow, rowIndex);
              csm.addSelectionInterval(anchorCol, columnIndex);
          } else {
              rsm.removeSelectionInterval(anchorRow, rowIndex);
              csm.removeSelectionInterval(anchorCol, columnIndex);
          }

          if (getAutoscrolls()) {
              Rectangle cellRect = getCellRect(rowIndex, columnIndex, false);
              if (cellRect != null) {
                  scrollRectToVisible(cellRect);
              }
          }
      } else {
          super.changeSelection(rowIndex, columnIndex, toggle, extend);
      }
  }
}

NoteCurtsey to http://bugs.sun.com

Curtsey 记录到http://bugs.sun.com