2015-10-12 18 views
4

這個問題是非常具體的。下面的代碼是一個從Oracle JTable教程中提取的例子,其中添加了Select All複選框的代碼,用於選擇和取消選擇最後一列中的所有複選框。我分配的程序使用了一個非常類似的設置。這是一個工作示例,但有一個問題我無法弄清楚如何解決。如何獲得JTable複選框單元格更新與外部選擇所有按鈕助記符

當您選擇/專注於表格最後一列中的一個單元格並按下Alt + A(全選複選框的助記符)時,處於焦點的單元格不會呈現/更新列中的其他單元格。根本的問題是:列是可編輯的,似乎當按下一個字符鍵時,它會隨着單元格的更新能力而變化。如果您使單元格不可編輯,並在焦點位置使用助記符時,它可以正常工作,但不能用鼠標單擊它。

我希望能夠使用鼠標單擊任何複選框單元格或全選按鈕,並且還可以隨時使用助記鍵來選擇全部按鈕。

如何使複選框單元格在使用助記符進行全選時更新,如果焦點位於複選框列中的單元格上?

以下是完整的示例程序。

/* 
* Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. 
* 
* Redistribution and use in source and binary forms, with or without 
* modification, are permitted provided that the following conditions 
* are met: 
* 
* - Redistributions of source code must retain the above copyright 
*  notice, this list of conditions and the following disclaimer. 
* 
* - Redistributions in binary form must reproduce the above copyright 
*  notice, this list of conditions and the following disclaimer in the 
*  documentation and/or other materials provided with the distribution. 
* 
* - Neither the name of Oracle or the names of its 
*  contributors may be used to endorse or promote products derived 
*  from this software without specific prior written permission. 
* 
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/ 



/* 
* TableDemo.java requires no other files. 
*/ 

import javax.swing.JCheckBox; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.table.AbstractTableModel; 
import javax.swing.table.TableModel; 

import java.awt.BorderLayout; 
import java.awt.Dimension; 
import java.awt.GridLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.KeyEvent; 

/** 
* TableDemo is just like SimpleTableDemo, except that it 
* uses a custom TableModel. 
*/ 
public class TestJTable extends JPanel { 

    private static final long serialVersionUID = 1L; 

    public static JTable table; 

    private boolean DEBUG = false; 

    public JPanel tablePanel; 

    public TestJTable() { 
     super(new GridLayout(1,0)); 

     table = new JTable(new MyTableModel()); 
     table.setPreferredScrollableViewportSize(new Dimension(500, 70)); 
     table.setFillsViewportHeight(true); 

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

     JPanel selectAllCheckBoxPanel = new CreateSelectAllCheckBox(); 

     tablePanel = new JPanel(); 
     tablePanel.setLayout(new BorderLayout()); 
     tablePanel.add(selectAllCheckBoxPanel, BorderLayout.PAGE_START); 
     tablePanel.add(scrollPane, BorderLayout.PAGE_END); 

     add(tablePanel); 
    } 

    class MyTableModel extends AbstractTableModel { 

     private static final long serialVersionUID = 1L; 

     private String[] columnNames = {"First Name", 
             "Last Name", 
             "Sport", 
             "# of Years", 
             "Vegetarian"}; 
     private Object[][] data = { 
     {"Kathy", "Smith", 
     "Snowboarding", new Integer(5), new Boolean(false)}, 
     {"John", "Doe", 
     "Rowing", new Integer(3), new Boolean(true)}, 
     {"Sue", "Black", 
     "Knitting", new Integer(2), new Boolean(false)}, 
     {"Jane", "White", 
     "Speed reading", new Integer(20), new Boolean(true)}, 
     {"Joe", "Brown", 
     "Pool", new Integer(10), new Boolean(false)} 
     }; 

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

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

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

     public Object getValueAt(int row, int col) { 
      return data[row][col]; 
     } 

     /* 
     * 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 c) { 
      return getValueAt(0, c).getClass(); 
     } 

     /* 
     * 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. 
      if (col < 2) { 
       return false; 
      } else { 
       return true; 
      } 
     } 

     /* 
     * Don't need to implement this method unless your table's 
     * data can change. 
     */ 
     public void setValueAt(Object value, int row, int col) { 
      if (DEBUG) { 
       System.out.println("Setting value at " + row + "," + col 
            + " to " + value 
            + " (an instance of " 
            + value.getClass() + ")"); 
      } 

      data[row][col] = value; 
      fireTableCellUpdated(row, col); 

      if (DEBUG) { 
       System.out.println("New value of data:"); 
       printDebugData(); 
      } 
     } 

     private void printDebugData() { 
      int numRows = getRowCount(); 
      int numCols = getColumnCount(); 

      for (int i=0; i < numRows; i++) { 
       System.out.print(" row " + i + ":"); 
       for (int j=0; j < numCols; j++) { 
        System.out.print(" " + data[i][j]); 
       } 
       System.out.println(); 
      } 
      System.out.println("--------------------------"); 
     } 
    } 

    /** 
    * 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. 
     TestJTable newContentPane = new TestJTable(); 
     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) { 
     javax.swing.SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       createAndShowGUI(); 
      } 
     }); 
    } 
} 

/** 
* code to create the Select All check box at top of table. 
*/ 
class CreateSelectAllCheckBox extends JPanel { 

    private static final long serialVersionUID = 1L; 

    public static JCheckBox selectAllCheckBox; 

    public CreateSelectAllCheckBox() { 

     selectAllCheckBox = new JCheckBox("Select All"); 
     selectAllCheckBox.setFocusable(true); 
     selectAllCheckBox.setEnabled(true); 
     selectAllCheckBox.setSelected(false); 
     selectAllCheckBox.setOpaque(true); 
     selectAllCheckBox.setMnemonic(KeyEvent.VK_A); 

     selectAllCheckBox.addActionListener(new SelectAllActionListener()); 


     this.setLayout(new BorderLayout()); 

     this.add(selectAllCheckBox, BorderLayout.PAGE_START); 
    } 
} 

/** 
* Listener for Select All check box. Will select all or unselect all check boxes in column 5 when toggled. 
*/ 
class SelectAllActionListener implements ActionListener { 

    private static JTable table = TestJTable.table; 

    public void actionPerformed(ActionEvent e) { 

     if (CreateSelectAllCheckBox.selectAllCheckBox.isSelected()){ 
      TableModel model = table.getModel(); 

      for (int row = 0; row < model.getRowCount(); row++) { 
       model.setValueAt(Boolean.valueOf(true), row, 4); 
      } 

     } 
     if (!CreateSelectAllCheckBox.selectAllCheckBox.isSelected()){ 
      TableModel model = table.getModel(); 

      for (int row = 0; row < model.getRowCount(); row++) { 
       model.setValueAt(Boolean.valueOf(false), row, 4); 
      } 
     } 
    } 
} 

編輯下面 - 問題解決了,Listener類改變爲下面的代碼。額外的代碼是在設置值之前調用cancelCellEditing()。它不會停止單元在被監聽器設置後仍然可編輯。謝謝Dodd10x的代碼:)

/** 
* Listener for Select All check box. Will select all or unselect all check boxes in column 5 when toggled. 
*/ 
class SelectAllActionListener implements ActionListener { 

    private static JTable table = TestJTable.table; 

    public void actionPerformed(ActionEvent e) { 

     TableCellEditor editor = table.getCellEditor(); 
     if (editor != null) { 
      editor.cancelCellEditing(); 
     } 

     if (CreateSelectAllCheckBox.selectAllCheckBox.isSelected()){ 
      TableModel model = table.getModel(); 

      for (int row = 0; row < model.getRowCount(); row++) { 
       model.setValueAt(Boolean.valueOf(true), row, 4); 
      } 

     } 
     if (!CreateSelectAllCheckBox.selectAllCheckBox.isSelected()){ 
      TableModel model = table.getModel(); 

      for (int row = 0; row < model.getRowCount(); row++) { 
       model.setValueAt(Boolean.valueOf(false), row, 4); 
      } 
     } 

    } 
} 
+0

你必須停止編程CellEditor的,[我敢肯定,這裏是同一個問題(http://stackoverflow.com/a/17946486/714968) – mKorbel

回答

3

您選擇的單元格處於編輯狀態,所以它不會被更新。在select/deselect all命令中,您需要先獲取當前選中的單元格並告訴它停止編輯。

TableCellEditor editor = getCellEditor(); 
if (editor != null) { 
    editor.cancelCellEditing(); 
} 
+0

將cancelCellEditing!= stopCellEditing與真/假以編程方式,因爲在XxxTableModel中可能存在錯誤並取消不了, – mKorbel

+1

stopCellEditing將接受當前的更改。 cancelCellEditing不。由於他希望將相同的真/假值應用於每個單元格,只要在設置值之前調用它就不重要。 – Dodd10x

+0

這工作完美!謝謝! –

相關問題