TableModelの変更全体でJTableの選択を保持
-
05-07-2019 - |
質問
TableModel <から
fireTableDataChanged()
または fireTableRowsUpdated()
を実行すると、 JTable
の選択がクリアされます/ code>。
これは予想されているのですか、それとも何か間違っていますか?モデルの更新時の選択のクリア/保持に関する JTable
(または他の関連クラス)のプロパティが表示されませんでした。
これがデフォルトの動作である場合、これを防ぐ良い方法はありますか?たぶん「ロック」する何らかの方法更新前に選択し、後でロック解除しますか?
開発者は、更新前に選択内容を保存し、再適用することを試みています。少し遅いです。
これは、Windows XP上のJava 1.4.2です。使用するベンダーコードに基づいて、そのバージョンに制限されています。
解決
選択を保存してから、再度適用する必要があります。
まず、選択したすべてのセルのリストを取得する必要があります。
次に、JTableに新しいデータを再ロードするときに、同じ選択をプログラムで再適用する必要があります。
もう1つ言いたいのは、各テーブルモデルのリロード後にテーブル内の行または列の数が増加または減少している場合、選択を保持することを気にしないでください。
ユーザーは、モデルの更新前に、「ダック」という値を持つ行2列1を選択できます。しかし、モデルの更新後、同じデータが行4、列1に発生し、元のセルの行2、列1に「Pig」などの新しいデータが含まれることがあります。ここで、モデルの更新前の選択を強制的に設定した場合、これはユーザーが望んでいたものではない可能性があります。
したがって、プログラムでセルを選択すると、両刃の剣になります。わからない場合は、それをしないでください。
他のヒント
次のように、テーブルの構造が変更されていない場合(つまり、列/行を追加/削除していない場合)、テーブルの選択を自動的に保持できます。
TableModelの独自の実装を作成した場合、単にfireTableDataChanged()メソッドをオーバーライドできます:
@Override
public void fireTableDataChanged() {
fireTableChanged(new TableModelEvent(this, //tableModel
0, //firstRow
getRowCount() - 1, //lastRow
TableModelEvent.ALL_COLUMNS, //column
TableModelEvent.UPDATE)); //changeType
}
これにより、テーブルの構造ではなくデータのみが変更された場合に、選択が維持されることが保証されます。これと、このメソッドがオーバーライドされない場合に呼び出されるものとの唯一の違いは、Integer.MAX_VALUEの代わりにgetRowCount()-1がlastRow引数に渡されることです。後者は、テーブル内のデータは変更されましたが、行数も同じである可能性があります。
アプリケーションでも同じ問題が発生しました。私の場合、テーブルのモデルはオブジェクトのリストであり、オブジェクトプロパティは列にマップされていました。その場合、リストが変更されたときに、選択したインデックスを取得し、リストを更新する前に選択したオブジェクトを保存しました。リストを変更した後、テーブルを更新する前に、選択したオブジェクトの位置を計算します。変更後もまだ存在する場合は、選択範囲を新しいインデックスに設定します。
オブジェクトがリスト内の位置を変更する可能性があるため、変更後にテーブルで選択したインデックスを設定するだけでは機能しません。
補足として、GlazedListsを使用すると、テーブルを扱うときに作業がはるかに簡単になることがわかりました。
これはデフォルトの動作です。 fireTableDataChanged()
を呼び出すと、まったく新しいモデルを設定したため、テーブル全体が最初から再構築されます。この場合、当然、選択は失われます。 fireTableRowsUpdated()
を呼び出すと、一般的なケースでは選択もクリアされます。唯一の方法は、選択を記憶してからこれを設定することです。残念ながら、選択がまだ有効であるという保証はありません。選択を復元する場合は注意してください。
参照用に、@ 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]);
正しく思い出せば、選択を保存して再適用することも私たちがやったことです...
同じ問題に直面していましたが、理由を検索しようとするとこの質問が出ましたが、Java SDKのバグのようです。 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4276786
作業中
一時的な回避策が利用可能です。このバグは修正済みリリースに対してテストされていないため、このバグが修正されたら削除する必要があります。
このJTableのサブクラスを使用します。
注:これは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);
}
}
}
注 Curtseyへの http://bugs.sun.com