2016-11-17 91 views
0

为JTable添加“复选框编辑器”的最佳方法是什么?到目前为止,我有一个使用自定义AbstractTableModel的JTable,它使用两个数据集合:一个是HashMap,为每行添加“false”值的复选框。第二个集合框架是简单的ArrayList与整数。此外,AbstractTableModel具有自定义方法来从ArrayList和AbstractTableModel中删除选定的行。问题是,如果我在表格中“检查”chceckBox,检查值保持在同一行。我认为问题是重写setValueAt。我的一段代码:JTable的“复选框编辑器”

package checkboxeditor; 

import java.awt.BorderLayout; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.table.AbstractTableModel; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.util.ArrayList; 
import java.util.HashMap; 
import javax.swing.JButton; 

public class CheckBoxEditor extends JPanel { 

    public CheckBoxEditor() { 
     super(new BorderLayout()); 

     MyTableModel myTableModel = new MyTableModel(); 
     JTable table = new JTable(myTableModel); 
     table.setFillsViewportHeight(true); 

     JButton deleteBtn = new JButton("Delete selected rows"); 
     deleteBtn.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent ae) { 
       int rowCount = table.getRowCount(); 
       for (int i = rowCount - 1; i >= 0; i--) { 
        boolean checked = (boolean) table.getValueAt(i, 0); 
        if (checked) { 
         myTableModel.removeRow((int) table.getValueAt(i, 1)); 
        } 
       } 
      } 
     }); 
     add(deleteBtn, BorderLayout.PAGE_START); 

     //Create the scroll pane and add the table to it. 
     JScrollPane scrollPane = new JScrollPane(table); 

     //Add the scroll pane to this panel. 
     add(scrollPane, BorderLayout.CENTER); 
    } 

    class MyTableModel extends AbstractTableModel { 

     // column names 
     private String[] columnNames = {"#", "Number"}; 
     // check boxes 
     HashMap<Integer, Boolean> checkBoxes = new HashMap(); 
     // data 
     ArrayList<Integer> data = new ArrayList(); 

     public MyTableModel() { 
      for (Integer i = 1; i < 6; i++) { 
       data.add(i); 
      } 

     } 

     public void removeRow(Integer numberToDelete) { 
      int index = data.indexOf(numberToDelete); 
      data.remove(numberToDelete); 
      fireTableRowsDeleted(index, index); 
     } 

     public int getColumnCount() { 
      return columnNames.length; 
     } 

     public int getRowCount() { 
      return data.size(); 
     } 

     public String getColumnName(int col) { 
      return columnNames[col]; 
     } 

     public Object getValueAt(int row, int col) { 
      switch (col) { 
       case 0: 
        Object value = checkBoxes.get(row); 
        return (value == null) ? false : value; 
       case 1: 
        return data.get(row); 
       default: 
        return ""; 
      } 
     } 

     /* 
     * JTable uses this method to determine the default renderer/ 
     * editor for each cell. If we didn't implement this method, 
     * then the last column would contain text ("true"/"false"), 
     * rather than a check box. 
     */ 
     public Class getColumnClass(int col) { 
      switch (col) { 
       case 0: 
        return Boolean.class; 
       default: 
        return Integer.class; 
      } 
     } 

     /* 
     * Don't need to implement this method unless your table's 
     * editable. 
     */ 
     public boolean isCellEditable(int row, int col) { 
      //Note that the data/cell address is constant, 
      //no matter where the cell appears onscreen. 
      return (col == 0); 
     } 

     /* 
     * Don't need to implement this method unless your table's 
     * data can change. 
     */ 
     public void setValueAt(Object value, int row, int col) { 
      if (col == 0) { 
       checkBoxes.put(row, (boolean) value); 
      } 
     } 

    } 

    /** 
    * Create the GUI and show it. For thread safety, this method should be 
    * invoked from the event-dispatching thread. 
    */ 
    private static void createAndShowGUI() { 
     //Create and set up the window. 
     JFrame frame = new JFrame("TableDemo"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     //Create and set up the content pane. 
     CheckBoxEditor newContentPane = new CheckBoxEditor(); 
     newContentPane.setOpaque(true); //content panes must be opaque 
     frame.setContentPane(newContentPane); 

     //Display the window. 
     frame.pack(); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     //Schedule a job for the event-dispatching thread: 
     //creating and showing this application's GUI. 
     javax.swing.SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       createAndShowGUI(); 
      } 
     }); 
    } 
} 
+0

'问题是,如果我“在表中检查”chceckBox,选中的值保持在同一行。“您能否进一步解释问题是什么?我在代码中看不到任何会影响复选框值的明显内容,并且在运行代码时,我没有在复选框中看到异常行为。 – copeg

+0

@copeg,问题是复选框的“checked”值总是放在行的索引上,而不是放在应该删除的值的行上。如果表格有5行,而我想用索引2删除数字3,则数值停留在索引2上。现在索引2上有下一个数字 - 数字4.这个数字共享行。 – Jan444444

回答

2

一个是HashMap的是增加与“假”值,每行复选框。第二个集合框架很简单ArrayList with Integers

不需要两个数据结构或创建自定义TableModel。可以使用DefaultTableModelDefaultTableModel允许您在每一行中存储任何类型的对象。您只需重写模型的getColumnClass(...)方法以返回适当的类,并且该表将为该列选择适当的渲染器/编辑器。喜欢的东西:

String[] columnNames = {"#", "Number"}; 
DefaultTableModel model = new DefaultTableModel(columnNames, 0) 
{ 
    // Returning the Class of each column will allow different 
    // renderers and editors to be used based on Class 

    public Class getColumnClass(int column) 
    { 
     return column == 0 ? Boolean.class : Integer.class; 
    } 
}; 

JTable table = new JTable(model); 

然后你就可以做类似的数据添加到表:

for (Integer i = 1; i < 6; i++) 
{ 
    Object[] row = {Boolean.FALSE, i}; 
    model.addRow(row); 
} 

DefaultTableModel已经支持从模型中删除行的方法。

+0

谢谢,它比abstracttablemodel更好。 – Jan444444

+0

另外我想问你,是否有任何规则或如何选择DefaultTableModel和AbstractTableModel? – Jan444444

+0

@ Jan444444,DefaultTableModel是一个具有数据存储和功能的全功能模型,你只能调整上面的一些方法。当您要显示的数据不是可以由DefaultTableModel处理的格式时,您可以使用自定义AbstractModel。假设你想在TableModel中显示自定义对象。查看[Row Table Model](https://tips4java.wordpress.com/2008/11/21/row-table-model/)以获取此方法的示例。 – camickr