我有一个JTable显示由Glazed List支持的数据。表格选择在非常特定的条件下丢失。必须更新所选行,以便更改排序的列,以便所选行移动到新位置。
我相信我遇到过这个GlazedList错误,但我找不到解决方法:https://java.net/jira/browse/GLAZEDLISTS-194
我创建了一些演示此问题的源代码:
public class SelectionLost {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run() {
/*
* Create and set up the table.
*/
final JTable table = new JTable();
final EventList<DisplayElement> data = new BasicEventList<>();
ObservableElementList<DisplayElement> observeData =
new ObservableElementList<>(data, new DisplayConnector());
final SortedList<DisplayElement> sortedData =
new SortedList<>(observeData);
sortedData.setMode(SortedList.STRICT_SORT_ORDER);
//populate our list with some data.
data.add(new DisplayElement("a", "a"));
data.add(new DisplayElement("b", "b"));
data.add(new DisplayElement("c", "c"));
data.add(new DisplayElement("d", "d"));
//Set up the table models.
AdvancedTableModel<DisplayElement> model
= GlazedListsSwing.eventTableModelWithThreadProxyList(sortedData, new DisplayTableFormat());
table.setModel(model);
final AdvancedListSelectionModel<DisplayElement> select
= GlazedListsSwing.eventSelectionModelWithThreadProxyList(sortedData);
table.setSelectionModel(select);
TableComparatorChooser<DisplayElement> tc = TableComparatorChooser.install(
table, sortedData, TableComparatorChooser.MULTIPLE_COLUMN_MOUSE_WITH_UNDO);
//sort on the first column
tc.appendComparator(0, 0, false);
//select the first row
table.getSelectionModel().setSelectionInterval(0, 0);
/*
* Create UI elements
*/
JFrame frame = new JFrame();
JPanel panel = new JPanel(new BorderLayout());
frame.add(panel);
JScrollPane scroll = new JScrollPane(table);
panel.add(scroll);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final Random r = new Random();
/*
* Create a timer which will change the elements data. When the selected
* element's data is changed so that it moves into a new index position,
* the selection is lost.
*/
TimerTask tt = new TimerTask() {
@Override
public void run() {
data.getReadWriteLock().writeLock().lock();
try{
int row = r.nextInt(data.size());
int col = r.nextInt(2);
Character c = (char)(r.nextInt(26)+'a');
DisplayElement d = data.get(row);
if(col == 0)
d.setFirst(c.toString());
else
d.setSecond(c.toString());
}
finally{
data.getReadWriteLock().writeLock().unlock();
}
}
};
java.util.Timer t = new java.util.Timer();
t.schedule(tt, 250, 250);
}
});
}
/*
* These are the data elements stored in the table
*/
public static class DisplayElement implements Comparable<DisplayElement>{
private String first, second;
private PropertyChangeSupport pcs = new PropertyChangeSupport(this);
public DisplayElement(String first, String second) {
this.first = first;
this.second = second;
}
public String getFirst() {
return first;
}
public void setFirst(String first) {
this.first = first;
pcs.firePropertyChange("first", null, null);
}
public String getSecond() {
return second;
}
public void setSecond(String second) {
this.second = second;
pcs.firePropertyChange("second", null, null);
}
@Override
public int compareTo(DisplayElement o) {
int comp = first.compareTo(o.first);
if(comp != 0)
return comp;
return second.compareTo(o.second);
}
public void addPropertyChangeListener(PropertyChangeListener l){
pcs.addPropertyChangeListener(l);
}
public void removePropertyChangeListener(PropertyChangeListener l ){
pcs.removePropertyChangeListener(l);
}
}
/*
* Table format for glazed lists
*/
public static class DisplayTableFormat implements AdvancedTableFormat<DisplayElement>, WritableTableFormat<DisplayElement>{
@Override
public int getColumnCount() {
return 2;
}
@Override
public String getColumnName(int i) {
if(i == 0 )
return "first";
else
return "second";
}
@Override
public Object getColumnValue(DisplayElement e, int i) {
if(i == 0)
return e.first;
else
return e.second;
}
@Override
public Class getColumnClass(int i) {
return String.class;
}
@Override
public Comparator getColumnComparator(int i) {
return GlazedLists.comparableComparator();
}
@Override
public boolean isEditable(DisplayElement e, int i) {
return true;
}
@Override
public DisplayElement setColumnValue(DisplayElement e, Object o, int i) {
if(i == 0)
e.first = (String) o;
else
e.second = (String)o;
return e;
}
};
/*
* Connector for observable lists.
*/
public static class DisplayConnector implements ObservableElementList.Connector<DisplayElement>{
ObservableElementList<? extends DisplayElement> list;
PropertyChangeListener myListener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
list.elementChanged(evt.getSource());
}
};
@Override
public EventListener installListener(DisplayElement e) {
e.addPropertyChangeListener(myListener);
return myListener;
}
@Override
public void uninstallListener(DisplayElement e, EventListener el) {
e.removePropertyChangeListener(myListener);
}
@Override
public void setObservableElementList(ObservableElementList<? extends DisplayElement> oel) {
list = oel;
}
}
}
答案 0 :(得分:0)
经过多次修复,我终于找到了解决问题的方法。我创建了一个恢复选择的监听器。唯一的缺点是用户不能再选择&#34;取消选择&#34;按CTRL键并单击它。如果有人能想出更好的解决方案,我会很高兴看到它。我发现这个有点hacky。
/*
* This listener fixes the problem where we would lose selection.
* Note that it prevents the user from "unselecting" a row.
*/
public static class GlazedListBug194Listener <T> implements ListSelectionListener {
private T lastSelectedElement;
private final JTable table;
private final AdvancedTableModel<T> model;
private final AdvancedListSelectionModel<T> select;
public GlazedListBug194Listener(JTable table,
AdvancedTableModel<T> model,
AdvancedListSelectionModel<T> select) {
this.table = table;
this.model = model;
this.select = select;
}
@Override
public void valueChanged(ListSelectionEvent e) {
int selectedRow = table.convertRowIndexToModel(table.getSelectedRow());
if(selectedRow < 0){
if(table.getRowCount() == 0){
//table was cleared
lastSelectedElement = null;
}
else{
//restore selection
for(int i = 0; i < table.getRowCount(); i++){
if(model.getElementAt(i) == lastSelectedElement){
select.setSelectionInterval(i, i);
break;
}
}
}
}
else{
lastSelectedElement = model.getElementAt(selectedRow);
}
}
}