2013-09-23 85 views
0

我想在Jtable中刪除多行(每個例子,五十五),但我只能刪除一個(在我問你之前我使用多個區間選擇!),而我感覺Jtable凍結了一下。我的刪除按鈕:刪除多行凍結JTable

deleteButton.addActionListener(new java.awt.event.ActionListener() { 
public void actionPerformed(java.awt.event.ActionEvent e){          
SwingUtilities.invokeLater(new Runnable() { 
    public void run(){ 
int[] selectedRow = jTable.getSelectedRows(); 
for(int j=0; j<selectedRow.length; j++){ 
        Boolean state= (Boolean)jTable.getValueAt(selectedRow[j],10); 
        if(state==true){//deleta the row 
         User u=model.getUsers(selectedRow[j]); 
         new UserDao().delete(u); 
         model.remove(selectedRow[j]); 
         numberField.setText(String.valueOf(model.getRowCount())); 
        } 
       } 
        } 
    });    
} 
}); 

我刪除:

public void remove(int row) { 
this.userlist.remove(row); 
this.fireTableDataChanged(); 
} 

我做錯了嗎?

+1

如果凍結,將線程轉儲,看看什麼是真正阻止或發生 – Robin

+0

請編輯您的問題包括[SSCCE]( http://sscce.org/)顯示你的模型的remove()方法。 – trashgod

+0

它凍結略有鬆動。如果我選​​擇了五個複選框,然後按DEL按鈕,只有第一個選擇被刪除,其他人保持標記。上面的代碼中有一些錯誤嗎?如何在eclipse中進行線程轉儲,如果我沒有任何堆棧跟蹤?最好的祝願, – PaulHB

回答

2

讓我們在代碼仔細看看...

deleteButton.addActionListener(new java.awt.event.ActionListener() { 
    public void actionPerformed(java.awt.event.ActionEvent e){  
     // Don't know why you need to use invokeLater 
     // The event should be trigged within the EDT if the user 
     // clicked the button. This may introduce a small "pause" 
     // depending on what else is in the EDT... 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run(){ 
       // Get the indices of the selected rows...okay 
       int[] selectedRow = jTable.getSelectedRows(); 
       // Loop through the selected rows...good... 
       for(int j=0; j<selectedRow.length; j++){ 
        // Get the "state" of the row...okay 
        Boolean state= (Boolean)jTable.getValueAt(selectedRow[j],10); 
        // Long winded if, but okay... 
        if(state==true){//deleta the row 
         // Don't know what's going on here, 
         // But I assume you are trying to delete 
         // something from some kind of database 
         // THIS is likely to chew up some time... 
         User u=model.getUsers(selectedRow[j]); 
         new UserDao().delete(u); 
         // Uh oh... 
         // If you remove a row from the model, the list of indices you 
         // have is now invalid, as they no longer point 
         // to the correct rows in the model 
         model.remove(selectedRow[j]); 
         numberField.setText(String.valueOf(model.getRowCount())); 
        } 
       } 
      } 
     });    
    } 
}); 

所以。兩個問題。

  1. 您似乎在調用EDT的上下文中調用某種管理功能,「看上去」的功能會導致EDT在很短的時間內放緩/暫停。
  2. 你是依靠過時的信息...

一個更好的解決辦法是使用某種類型的後臺進程來執行用戶的刪除和模型中提供了一種方法來查找User對象本身並將其從模型中移除。這消除了在您下面更改索引的可能性。

A SwingWorker提供了一種方法,我們可以在後臺執行操作,關閉事件分派線程,同時在需要時提供重新同步所需操作(如修改表模型)到EDT的手段......

例如...

public class DeleteUsersWorker extends SwingWorker<List<User>, User> { 

    private UserTableModel model; 
    private List<User> users; 

    public DeleteUsersWorker(UserTableModel model, List<User> users) { 
     this.model = model; 
     this.users = users; 
    } 

    protected List<User> doInBackground() { 
     UserDao dao = new UserDao(); 
     for (User user : users) { 
      dao.delete(user); 
      publish(user); 
     } 
     return users; 
    } 

    protected void process(List<User> users) { 
     for (User user : users) { 
      model.remove(user); 
     } 
    } 
} 

而且actionPerformed方法的內容...

int[] selectedRow = jTable.getSelectedRows(); 
List<User> usersToBeRemoved = new ArrayList<>(selectedRow.length); 
for(int row : selectedRow){ 
    // Is state part of the User object?? 
    Boolean state = (Boolean)jTable.getValueAt(row,10); 
    if(state){ 
     usersToBeRemoved.add(model.getUsers(row)); 
    } 
} 
DeleteUsersWorker worker = new DeleteUsersWorker(model, users); 
worker.execute(); 

這可能需要添加一些額外的功能到表模型,以支持從模型中刪除User對象,但我沒有你的模型,所以很難提出建議...

看看Concurrency in Swing瞭解更多詳情...

一個更好的解決方案可能是在你的dao API上有一個監聽器,它可以提供關於更新的通知,這樣模型可以更新自身,但是再次,沒有足夠的上下文來做出決定; )

以評論形式更新TrashGod

您還應該注意,視圖索引並不總是直接映射到模型索引。這是在對錶格進行排序或過濾時發生的。雖然你可能會認爲你的表沒有(排序或過濾),但從來沒有做過這樣的假設是好的做法......

當從表中取一行索引時,應該調用JTable#convertRowIndexToModel(int),它會返回索引點在模型

看看Sorting and Filtering瞭解更多詳情...

更新用可運行的示例

import java.awt.BorderLayout; 
import java.awt.EventQueue; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.SwingWorker; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 
import javax.swing.table.AbstractTableModel; 

public class TableDeleteRowsTest { 

    public static void main(String[] args) { 
     new TableDeleteRowsTest(); 
    } 

    public TableDeleteRowsTest() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
       } 

       final UserTableModel model = new UserTableModel(
         new User("Kermit"), 
         new User("Fozzie"), 
         new User("Animal"), 
         new User("Miss Piggy"), 
         new User("Gonzo"), 
         new User("Beaker"), 
         new User("Crazy Harry"), 
         new User("Floyd Pepper"), 
         new User("Sweetums")); 

       final JTable table = new JTable(model); 

       JButton delete = new JButton("Delete"); 
       delete.addActionListener(new ActionListener() { 
        @Override 
        public void actionPerformed(ActionEvent e) { 
         int[] selectedRows = table.getSelectedRows(); 
         if (selectedRows.length > 0) { 
          List<User> users = new ArrayList<>(selectedRows.length); 
          for (int row : selectedRows) { 
           int modelRow = table.convertRowIndexToModel(row); 
           Boolean selected = (Boolean) model.getValueAt(modelRow, 1); 
           if (selected) { 
            users.add(model.getUser(modelRow)); 
           } 
          } 
          if (users.size() > 0) { 
           new DeleteUserWorker(users, model).execute(); 
          } 
         } 
        } 
       }); 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.setLayout(new BorderLayout()); 
       frame.add(new JScrollPane(table)); 
       frame.add(delete, BorderLayout.SOUTH); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class DeleteUserWorker extends SwingWorker<List<User>, User> { 

     private List<User> users; 
     private UserTableModel model; 

     public DeleteUserWorker(List<User> users, UserTableModel model) { 
      this.users = users; 
      this.model = model; 
     } 

     @Override 
     protected void process(List<User> chunks) { 
      for (User user : users) { 
       model.remove(user); 
      } 
     } 

     @Override 
     protected List<User> doInBackground() throws Exception { 
      for (User user : users) { 
       // Simulated delay 
       Thread.sleep(250); 
       publish(user); 
      } 
      return users; 
     } 

    } 

    public class UserTableModel extends AbstractTableModel { 

     private List<User> users; 
     private List<Boolean> selected; 

     public UserTableModel(User... users) { 
      this.users = new ArrayList<>(Arrays.asList(users)); 
      selected = new ArrayList<>(this.users.size()); 
      for (User user : this.users) { 
       selected.add(new Boolean(false)); 
      } 
     } 

     public User getUser(int row) { 
      return users.get(row); 
     } 

     @Override 
     public int getRowCount() { 
      return users.size(); 
     } 

     @Override 
     public int getColumnCount() { 
      return 2; 
     } 

     @Override 
     public String getColumnName(int column) { 
      String name = "?"; 
      switch (column) { 
       case 0: 
        name = "User"; 
        break; 
       case 1: 
        name = ""; 
        break; 
      } 
      return name; 
     } 

     @Override 
     public Class getColumnClass(int column) { 
      Class type = String.class; 
      switch (column) { 
       case 0: 
        type = String.class; 
        break; 
       case 1: 
        type = Boolean.class; 
        break; 
      } 
      return type; 
     } 

     @Override 
     public Object getValueAt(int rowIndex, int columnIndex) { 
      Object value = null; 
      switch (columnIndex) { 
       case 0: 
        value = users.get(rowIndex).getName(); 
        break; 
       case 1: 
        value = selected.get(rowIndex); 
        break; 
      } 
      return value; 
     } 

     @Override 
     public boolean isCellEditable(int rowIndex, int columnIndex) { 
      return columnIndex == 1; 
     } 

     @Override 
     public void setValueAt(Object aValue, int rowIndex, int columnIndex) { 
      switch (columnIndex) { 
       case 1: 
        if (aValue instanceof Boolean) { 
         selected.set(rowIndex, (Boolean) aValue); 
         fireTableCellUpdated(rowIndex, columnIndex); 
        } 
        break; 
      } 
     } 

     public void remove(User user) { 
      int index = users.indexOf(user); 
      if (index >= 0) { 
       selected.remove(index); 
       users.remove(user); 
       fireTableRowsDeleted(index, index); 
      } 
     } 
    } 

    public class User { 

     private String name; 

     public User(String name) { 
      this.name = name; 
     } 

     public String getName() { 
      return name; 
     } 
    } 
} 

與附加示例

上面的例子更新將僅刪除被標記和選定的行。要刪除所有標記的行,則需要更多的東西一樣......

JButton delete = new JButton("Delete"); 
delete.addActionListener(new ActionListener() { 
    @Override 
    public void actionPerformed(ActionEvent e) { 
     List<User> users = new ArrayList<>(selectedRows.length); 
     for (int row = 0; row < table.getRowCount(); row++) { 
      int modelRow = table.convertRowIndexToModel(row); 
      Boolean selected = (Boolean) model.getValueAt(modelRow, 1); 
      if (selected) { 
       users.add(model.getUser(modelRow)); 
      } 
     } 
     if (users.size() > 0) { 
      new DeleteUserWorker(users, model).execute(); 
     }    
    } 
}); 
+0

並根據需要[轉換視圖模型座標](http://docs.oracle.com/javase/tutorial/uiswing/components/table.html#sorting)。 – trashgod

+1

@trashgod是的,想到提到這一點,但我雖然可能只是增加了可憐的OP的困惑... – MadProgrammer

+0

MadProgrammer,我只是試着invokeLater看看是否發生了什麼,但沒有改變任何東西......你的方法看起來smooth.I只是沒有得到它你的model.remove(用戶)...我的用戶只是一個最後一個字段是一個布爾值的bean,因爲它在我的tablemodel,我得到每個用戶的複選框。我使用刪除(int位置)因爲我得到它/從列表中刪除它。最好的祝福。 – PaulHB