2014-10-01 5 views
1

RowSorter를 사용하여 정렬되고 필터링 된 JTable이 있으며 실시간 방식으로 업데이트됩니다. 사용자가 마우스 (클릭 + 행 위로 끌기) 또는 키보드 (Shift + 아래쪽 화살표 여러 번)를 사용하여 선택 간격을 만들려고 할 때 문제가 있습니다.정렬 테이블의 JTable 선택 간격 문제

테이블 모델 업데이트 이벤트가 발생하면 선택 간격 시작 및 끝이 손상됩니다. 테이블이 정렬되고 둘 이상의 선택된 행이있는 경우 선택 모델은 모든 테이블 모델 업데이트에서 선택을 다시 지우는 여러 목록 선택 이벤트를 발생시키는 것을 발견했습니다.

한 번에 여러 행을 선택하면 모두 정상입니다. 사용자가 선택한 항목이 선택된 상태로 유지됩니다. 그러나 사용자가 마우스를 여러 행에 걸쳐 클릭 한 채 드래그하여 선택 간격을 만들려고하면 표 모델 업데이트 이벤트가 발생할 때까지 행이 올바르게 선택됩니다. 그런 다음 선택 항목은 현재 선택된 행에서 빌드를 시작합니다.

작은 데모 응용 프로그램을 첨부했습니다. 마우스를 사용하여 여러 행을 선택해보십시오. 선택이 손상 될 때마다 ....

이것은 Java 클래스에서 버그 (또는 원하지 않는 동작) 인 것 같습니다. 누군가가 창의적인 솔루션/해결 방법을 제공 할 수 있기를 바랍니다. 나는 윈도우 7에 JDK7를 사용하여 코드를 실행

public class TableTest extends JFrame { 
    private static final long serialVersionUID = 1L; 

    public TableTest() { 
     super("Table Selection Problem"); 
     setBounds(50, 50, 800, 600); 
     setDefaultCloseOperation(EXIT_ON_CLOSE); 

     // Create a table model 
     final DefaultTableModel tableModel = new DefaultTableModel(40,10); 

     // Create table row sorter sorted on column 1 
     TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(tableModel); 
     sorter.setSortsOnUpdates(true); 
     sorter.setSortKeys(Arrays.asList(new RowSorter.SortKey(1,SortOrder.DESCENDING))); 

     // Create a table and bind the sorter 
     JTable table = new JTable(tableModel); 
     table.setRowSorter(sorter); 

     // Bind a list selection listener, this doesn't do anything besides showing the selection change(s) on every table model update 
     table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { 
      @Override 
      public void valueChanged(ListSelectionEvent e) { 
       System.out.println(e); 
      } 
     }); 


     // place the table in the frame 
     getContentPane().add(new JScrollPane(table), BorderLayout.CENTER); 

     // Simulate some application events that trigger a table update... 
     new Thread() { 
      public void run() { 
       try { 
        final Random r = new Random(); 
        for(int x = 0; x < 1000; x++) { 
         // update a table cell (not even an add or delete) 
         SwingUtilities.invokeLater(new Runnable() { 
          public void run() { 
           tableModel.setValueAt(r.nextInt(1000), r.nextInt(40), r.nextInt(10)); 
          } 
         }); 
         // wait 1 second before next table update 
         Thread.sleep(1000); 
        } 
       } catch(Throwable t) { 
        t.printStackTrace(); 
       } 
      } 
     }.start();  
    } 


    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       (new TableTest()).setVisible(true);      
      } 
     });  
    } 
} 
+0

문제가 발생하지 않았습니다. 관점에서 보았을 때 선택은 일종의 정렬이었습니다. 즉 행 1-5를 선택하고 그 앞에 새로운 행이 삽입되면 해당 행이 아래로 이동합니다. 새로운 행이 그들 사이의 어딘가에 삽입된다면, 선택은 데이터가 아니라 행 (높은 레벨의 관점)을 기반으로하기 때문에 나의 기대가 될 것입니다. – MadProgrammer

+0

이것이 코드가 작동하는 방식입니다. 선택 간격을 확장하면서 테이블 모델을 업데이트합니다. 내 테스트 응용 프로그램을 실행하면 매초마다 테이블 모델 업데이트가 전송됩니다. 표의 행 2를 클릭하고 마우스를 위/아래로 드래그하여 행을 선택하십시오. 2를 누르십시오. 7을 누르고 나서 행을 2부터 4까지 선택하고 다시 2를 선택하여 행 2에서 10을 선택하십시오. 테이블 모델 업데이트는 선택 프로세스 중에 발생합니다. 앵커 선택 (행 2)이 휴지통으로 바뀌고 이제는 마우스가있는 곳 (업데이트가 발생했을 때)부터 어디로 이동했는지 선택이 확대되기 시작합니다. –

+0

좋아요, 어쩌면 당신은 목록 선택 업데이트가 진행되는 동안 업데이트가 목록 선택이 완료 될 때까지 대기하도록 예를 들어 어떤 식 으로든 업데이트를 격리해야 할 수도 있습니다 ... – MadProgrammer

답변

2

은 내가 setSortsOnUpdates(...)이 테이블의 데이터에 문제를 일으키는 것으로 나타났다. 즉, 나는 코드를 잠시 동안 실행시키고 열 1에 아무 값도 표시되지 않는 것을 보았습니다. 그래서 프레임의 너비를 늘렸고 갑자기 값이 정렬 된 순서로 나타났습니다. 그래서 어떤 이유로 데이터가 변경 되더라도 테이블이 다시 그려지지 않았습니다. setSortsOnUpdates(...)에 댓글을 달았을 때 TableModel에 대한 변경 사항이 즉시 나타났습니다. 나는 그 문제가 뭔지 전혀 모른다.

그렇다면 데이터가 변경 될 때 수동으로 정렬을 호출하는 방식을 변경했습니다. 그러나 ListSelectionListener가 조정되지 않은 경우에만 정렬을 수행했습니다.

import java.awt.*; 
import java.awt.event.*; 
import java.util.Random; 
import java.util.Arrays; 
import javax.swing.*; 
import javax.swing.table.*; 
import javax.swing.event.*; 

    public class TableTest5 extends JFrame { 
    private static final long serialVersionUID = 1L; 

    private boolean isAdjusting = false; 
    private boolean isModelChanged = false; 
    TableRowSorter<TableModel> sorter; 
    final Random r = new Random(); 

    public TableTest5() { 
     super("Table Selection Problem"); 
     setBounds(50, 50, 800, 600); 
     setDefaultCloseOperation(EXIT_ON_CLOSE); 

     // Create a table model 
     final DefaultTableModel tableModel = new DefaultTableModel(30,3); 

     // Create table row sorter sorted on column 1 
//  TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(tableModel); 
     sorter = new TableRowSorter<TableModel>(tableModel); 
     sorter.setSortsOnUpdates(true); 
     sorter.setSortKeys(Arrays.asList(new RowSorter.SortKey(1,SortOrder.DESCENDING))); 

     // Create a table and bind the sorter 
     JTable table = new JTable(tableModel); 
     table.setRowSorter(sorter); 

     // Bind a list selection listener, this doesn't do anything besides showing the selection change(s) on every table model update 
     table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { 
      @Override 
      public void valueChanged(ListSelectionEvent e) { 
       isAdjusting = e.getValueIsAdjusting(); 

       if (!isAdjusting && isModelChanged) 
       { 
        isModelChanged = false; 
        sorter.sort(); 
       } 
      } 
     }); 


     // place the table in the frame 
     getContentPane().add(new JScrollPane(table), BorderLayout.CENTER); 

     // Simulate some application events that trigger a table update... 
     new Thread() { 
      public void run() { 
       try { 
        //final Random r = new Random(); 
        for(int x = 0; x < 1000; x++) { 
         // update a table cell (not even an add or delete) 
         SwingUtilities.invokeLater(new Runnable() { 
          public void run() { 

           int value = r.nextInt(1000); 
           int row = r.nextInt(30); 
           int column = r.nextInt(5); 
           System.out.println(value + " : " + row + " : " + column); 
           tableModel.setValueAt(value, row, column); 

           if (!isAdjusting) 
            sorter.sort(); 
           else 
            isModelChanged = true; 
          } 
         }); 
         // wait 1 second before next table update 
         Thread.sleep(1000); 
        } 
       } catch(Throwable t) { 
        t.printStackTrace(); 
       } 
      } 
     }.start(); 

    } 


    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       (new TableTest5()).setVisible(true); 
      } 
     }); 
    } 
} 

당신의 TableModel 변경 수동 정렬을 호출을 수신하기 위해 TableModelListener 사용을 고려할 수 있습니다 여기에 코드입니다.

+0

이 예제에서는 문제를 해결하는 것처럼 보입니다 - 행을 추가하거나 제거하면 행을) 테이블 모델에서 다시 같은 문제가있을 것이다. 이 방법은 키보드 선택 (SHIFT + 아래 화살표)에는 작동하지 않습니다. –