简体   繁体   中英

Selection lost with mouse drag and concurrent update in JTable

In my JTable I have already implemented the selection-preserving logic during updates. Unfortunately I think I have come across some kind of bug. The JTable is updated by a background thread that fetches new data and adds/modifies/removes it from the table model.

The problem shows itself only when an update is performed while the user is dragging the mouse to select rows in the table. What puzzles me the most is that:

  • if I start from a row and move the mouse upward to select the preceding rows, everything works perfectly: the selection is preserved across updates and the user action continues correctly
  • if I start from a row and move the mouse downward to select the following rows, it breaks: when the update fires, the current selection is lost and the new selection starts from the row that is under the pointer when the update fires.

Any clues as why this might be happening?


This is a trimmed down version of the code I'm talking about.

I am using a manually synchronized TreeSet to update the data in background threads (see update ). When I'm done, I invoke atomicSwapData that creates the array that will be used by getValueAt .

In updateTable you can see how I implemented the selection-preserving logic I was talking about before. As you can see I tried using the EventQueue.invokeLater method but the problem still appears. Please note that all methods may be called by any thread, not just the EDT.

class MyDataModel extends AbstractTableModel {
    TreeSet<MyDataItem> ht = new TreeSet<MyDataItem>();
    MyDataItem[] _ht = MyDataItem.emptyArray();

    public Object getValueAt(int row, int col) {
        MyDataItem qdi;
        synchronized (_ht) {
            qdi = _ht[row];
        }
        // return one of the members of qdi, based on col
    }

    public void update(String qm, Collection<MyDataItem> toAdd) {
        HashSet<MyDataItem> toDrop = new HashSet<MyDataItem>();
        synchronized (ht) { 
            // do something with ht
        }
        swapData();
    }

    private void swapData() {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                synchronized(_ht) {
                    MyDataItem[] tmp = ht.toArray(MyDataItem.emptyArray());
                    synchronized(tmp) {
                        _ht = tmp;
                    }
                } 
            }
        });
        updateTable();
    }

    private void updateTable() {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                synchronized (_ht) {
                    int[] rowIndices = table.getSelectedRows();
                    fireTableDataChanged();
                    for (int row: rowIndices)
                        table.addRowSelectionInterval(row, row);
                }
            }
        });
    }
}

For reference, this example continually updates the TableModel from a background thread using EventQueue.invokeLater() . It does not exhibit the anomaly you describe.

standard painting for a jtable is from top to bottom this might be a reason why it breaks in one direction but not the other.

You will have to be abit more clear and define your 'breaks'

Does it just paints the selection wrong ? then you should be able to fix it by forcing your table to do a full repaint after the update fires

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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