2013-09-23 86 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