2016-01-06 497 views
3

我試圖在JTable的單元格內實現點擊顏色更改按鈕。我已經知道顏色是在onClick上改變的,但我沒有得到的是,背景顏色如何保持按鈕切換到的顏色。任何時候,我通過點擊另一個單元格或桌子內部的按鈕再次變爲白色,從而釋放焦點。我認爲這與渲染器有關,也許你可以支持我。切換JTable中按鈕的顏色

signalTable = new JTable(); 
    signalTable.setModel(new DefaultTableModel(
     new Object[][] { 
      {"AAA", "A_SIGNAL", null, null, null, null, null, null, null, null, "Example", Boolean.TRUE}, 
     }, 
     new String[] { 
      "ID", "Message Identifier", "0", "1", "2", "3", "4", "5", "6", "7", "Description", "" 
     } 
    ) { 
     Class[] columnTypes = new Class[] { 
      String.class, String.class, JButton.class, JButton.class, JButton.class, JButton.class, JButton.class, JButton.class, JButton.class, JButton.class, String.class, Boolean.class 
     }; 
     public Class getColumnClass(int columnIndex) { 
      return columnTypes[columnIndex]; 
     } 
    }); 
    TableColorRenderer renderer = new TableColorRenderer(); 
    signalTable.getColumn("0").setCellRenderer(renderer); 
    signalTable.getColumn("1").setCellRenderer(renderer); 
    signalTable.getColumn("2").setCellRenderer(renderer); 
    signalTable.getColumn("3").setCellRenderer(renderer); 
    signalTable.getColumn("4").setCellRenderer(renderer); 
    signalTable.getColumn("5").setCellRenderer(renderer); 
    signalTable.getColumn("6").setCellRenderer(renderer); 
    signalTable.getColumn("7").setCellRenderer(renderer); 
    signalTable.getColumn("0").setCellEditor(new ButtonEditor(new JCheckBox())); 
    signalTable.getColumn("1").setCellEditor(new ButtonEditor(new JCheckBox())); 
    signalTable.getColumn("2").setCellEditor(new ButtonEditor(new JCheckBox())); 
    signalTable.getColumn("3").setCellEditor(new ButtonEditor(new JCheckBox())); 
    signalTable.getColumn("4").setCellEditor(new ButtonEditor(new JCheckBox())); 
    signalTable.getColumn("5").setCellEditor(new ButtonEditor(new JCheckBox())); 
    signalTable.getColumn("6").setCellEditor(new ButtonEditor(new JCheckBox())); 
    signalTable.getColumn("7").setCellEditor(new ButtonEditor(new JCheckBox())); 

ButtonEditor.java:

public class ButtonEditor extends DefaultCellEditor 
{ 
    protected JButton button; 

    public ButtonEditor(JCheckBox checkBox) 
    { 
     super(checkBox); 
     button = new JButton(); 
     button.setOpaque(true); 
     button.addActionListener(new ActionListener() 
     { 
      public void actionPerformed(ActionEvent e) 
      { 
       button.setBackground(Color.GREEN); 
       button.repaint(); 
      } 
     }); 
    } 

    public Component getTableCellEditorComponent(JTable table, Object value, 
     boolean isSelected, int row, int column) 
    { 
     return button; 
    } 

} 

TableColorRenderer.java:

public class TableColorRenderer extends JLabel implements TableCellRenderer 
{ 
    @Override 
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) 
    { 
     return this; 
    } 

When clicked on invisible Button

After clicked in another row

+0

爲什麼會出現約JButton的說明和代碼顯示JCheckBox的 – mKorbel

+0

1.閱讀甲骨文教程如何使用表,存儲在模型JCheckBox的代表AbstractButton.isSelected布爾值,2。有沒有理由使用自定義(和錯誤的)渲染器和編輯器(缺少stopCellEditing,並將布爾值存儲在XxxTableModel中),然後Renderer沒有存儲任何值,在Renderer – mKorbel

回答

2

你clearl y誤解了編輯和渲染器的角色。編輯器允許用戶編輯單元格的狀態,渲染器呈現單元格的狀態。

他們通過使用TableModel來做到這一點。首先查看Concepts: Editors and RenderersUsing Other Editors瞭解更多詳情。

要開始與你正在做錯誤的事情......

signalTable.setModel(new DefaultTableModel(
    new Object[][] { 
     {"AAA", "A_SIGNAL", null, null, null, null, null, null, null, null, "Example", Boolean.TRUE}, 
    }, 
    new String[] { 
     "ID", "Message Identifier", "0", "1", "2", "3", "4", "5", "6", "7", "Description", "" 
    } 
) { 
    Class[] columnTypes = new Class[] { 
     String.class, String.class, JButton.class, JButton.class, JButton.class, JButton.class, JButton.class, JButton.class, JButton.class, JButton.class, String.class, Boolean.class 
    }; 
    public Class getColumnClass(int columnIndex) { 
     return columnTypes[columnIndex]; 
    } 
}); 

的「顏色」單元的單元值應truefalse(也可以是其他任何「開」 /「關」值你想要的,只要編輯器和渲染器知道如何對付他們,但在這個例子中,我使用boolean S)

columnType S表示這些細胞也應Boolean.class

signalTable.setModel(new DefaultTableModel(
     new Object[][]{ 
      {"AAA", "A_SIGNAL", false, false, false, false, false, false, false, false, "Example", Boolean.TRUE},}, 
     new String[]{ 
      "ID", "Message Identifier", "0", "1", "2", "3", "4", "5", "6", "7", "Description", "" 
     } 
) { 
    Class[] columnTypes = new Class[]{ 
     String.class, String.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, String.class, Boolean.class 
    }; 

    public Class getColumnClass(int columnIndex) { 
     return columnTypes[columnIndex]; 
    } 
}); 

所以,現在,如果你什麼也沒做,你會在這些單元中有JCheckBox,但那不是我們想要的。

public class ButtonEditor extends DefaultCellEditor 
{ 
    protected JButton button; 

    public ButtonEditor(JCheckBox checkBox) 
    { 
     super(checkBox); 
     button = new JButton(); 
     button.setOpaque(true); 
     button.addActionListener(new ActionListener() 
     { 
      public void actionPerformed(ActionEvent e) 
      { 
       button.setBackground(Color.GREEN); 
       button.repaint(); 
      } 
     }); 
    } 

    public Component getTableCellEditorComponent(JTable table, Object value, 
     boolean isSelected, int row, int column) 
    { 
     return button; 
    } 

} 

在這裏,你忽略它傳遞給你的編輯器JCheckBox,並創建自己的,但有兩個問題。 DefaultCellEditorJCheckBox獲取單元格值,而不是其他某個狀態(因此始終爲false),並且您從不配置button以表示請求時單元格的當前狀態。

因爲我不想處理其他組件,所以我會做一些有點不同的事情。

public class ButtonEditor extends AbstractCellEditor implements TableCellEditor { 

    private JLabel editor; 

    public ButtonEditor() { 
     editor = new JLabel(); 
     editor.setBackground(Color.GREEN); 

     editor.addMouseListener(new MouseAdapter() { 
      @Override 
      public void mouseClicked(MouseEvent e) { 
       editor.setOpaque(!editor.isOpaque()); 
       stopCellEditing(); 
      } 
     }); 
    } 

    @Override 
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { 
     if (value instanceof Boolean) { 
      boolean result = (boolean) value; 
      editor.setOpaque(!result); 
     } 
     return editor; 
    } 

    @Override 
    public Object getCellEditorValue() { 
     return editor.isOpaque(); 
    } 

    @Override 
    public boolean isCellEditable(EventObject e) { 
     return true; 
    } 

} 

這僅僅是一個JLabel點擊它時,會切換它的不透明狀態。我們也利用這個狀態,以確定單元格的值時,編輯器「停止」

public class TableColorRenderer extends JLabel implements TableCellRenderer 
{ 
    @Override 
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) 
    { 
     return this; 
    } 
} 

坦白地說,這是一個有點用處,它從來不做事與單元格的值

public class TableColorRenderer extends JLabel implements TableCellRenderer { 

    public TableColorRenderer() { 
     setBackground(Color.GREEN); 
    } 

    @Override 
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 
     if (value instanceof Boolean) { 
      boolean result = (boolean) value; 
      setOpaque(result); 
     } else { 
      setOpaque(false); 
     } 
     return this; 
    } 
} 

再次,非常簡單。我們檢查細胞(如傳遞給我們)的值,並相應地改變opaque狀態

而且,因爲從來沒有人相信我,一個可運行的例子

Editor

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Component; 
import java.awt.EventQueue; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.util.EventObject; 
import javax.swing.AbstractCellEditor; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 
import javax.swing.table.DefaultTableModel; 
import javax.swing.table.TableCellEditor; 
import javax.swing.table.TableCellRenderer; 

public class Example { 

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

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

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.add(new TestPane()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class TestPane extends JPanel { 

     private final JTable signalTable; 

     public TestPane() { 
      signalTable = new JTable(); 
    signalTable.setModel(new DefaultTableModel(
      new Object[][]{ 
       {"AAA", "A_SIGNAL", false, false, false, false, false, false, false, false, "Example", Boolean.TRUE},}, 
      new String[]{ 
       "ID", "Message Identifier", "0", "1", "2", "3", "4", "5", "6", "7", "Description", "" 
      } 
    ) { 
     Class[] columnTypes = new Class[]{ 
      String.class, String.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, String.class, Boolean.class 
     }; 

     public Class getColumnClass(int columnIndex) { 
      return columnTypes[columnIndex]; 
     } 
    }); 
      TableColorRenderer renderer = new TableColorRenderer(); 
      signalTable.getColumn("0").setCellRenderer(renderer); 
      signalTable.getColumn("1").setCellRenderer(renderer); 
      signalTable.getColumn("2").setCellRenderer(renderer); 
      signalTable.getColumn("3").setCellRenderer(renderer); 
      signalTable.getColumn("4").setCellRenderer(renderer); 
      signalTable.getColumn("5").setCellRenderer(renderer); 
      signalTable.getColumn("6").setCellRenderer(renderer); 
      signalTable.getColumn("7").setCellRenderer(renderer); 
      signalTable.getColumn("0").setCellEditor(new ButtonEditor()); 
      signalTable.getColumn("1").setCellEditor(new ButtonEditor()); 
      signalTable.getColumn("2").setCellEditor(new ButtonEditor()); 
      signalTable.getColumn("3").setCellEditor(new ButtonEditor()); 
      signalTable.getColumn("4").setCellEditor(new ButtonEditor()); 
      signalTable.getColumn("5").setCellEditor(new ButtonEditor()); 
      signalTable.getColumn("6").setCellEditor(new ButtonEditor()); 
      signalTable.getColumn("7").setCellEditor(new ButtonEditor()); 

      setLayout(new BorderLayout()); 
      add(new JScrollPane(signalTable)); 
     } 

    } 

    public class ButtonEditor extends AbstractCellEditor implements TableCellEditor { 

     private JLabel editor; 

     public ButtonEditor() { 
      editor = new JLabel(); 
      editor.setBackground(Color.GREEN); 

      editor.addMouseListener(new MouseAdapter() { 
       @Override 
       public void mouseClicked(MouseEvent e) { 
        editor.setOpaque(!editor.isOpaque()); 
        stopCellEditing(); 
       } 
      }); 
     } 

     @Override 
     public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { 
      if (value instanceof Boolean) { 
       boolean result = (boolean) value; 
       editor.setOpaque(!result); 
      } 
      return editor; 
     } 

     @Override 
     public Object getCellEditorValue() { 
      return editor.isOpaque(); 
     } 

     @Override 
     public boolean isCellEditable(EventObject e) { 
      return true; 
     } 

    } 

    public class TableColorRenderer extends JLabel implements TableCellRenderer { 

     public TableColorRenderer() { 
      setBackground(Color.GREEN); 
     } 

     @Override 
     public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 
      if (value instanceof Boolean) { 
       boolean result = (boolean) value; 
       setOpaque(result); 
      } 
      return this; 
     } 
    } 
} 
+0

謝謝你們也是SubOptimal。你幫我找到了解決方案。 – Thorgas

1

下面爲一個小演示應用程序在單元中使用JButton。按鈕文本是爲了展示MadProgrammer解釋的邏輯。按鈕文本是edit btn.或RESP。 render btn.。因此可以看到實際顯示哪個按鈕。單擊單元格時會顯示編輯按鈕。

import static java.lang.Boolean.FALSE; 
import static java.lang.Boolean.TRUE; 
import javax.swing.GroupLayout; 
import javax.swing.GroupLayout.Alignment; 
import static javax.swing.GroupLayout.PREFERRED_SIZE; 
import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.SwingUtilities; 
import javax.swing.UIManager; 
import javax.swing.UIManager.LookAndFeelInfo; 
import javax.swing.table.DefaultTableModel; 

public class FrameDemo extends JFrame { 

    public FrameDemo() { 
     initComponents(); 
    } 

    private void initComponents() { 
     setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 

     JTable signalTable = new JTable(); 
     signalTable.setModel(new DefaultTableModel(
       new Object[][]{ 
        {"AAA", "A_SIGNAL", FALSE, FALSE, FALSE, TRUE}, 
        {"BBB", "B_SIGNAL", FALSE, FALSE, FALSE, TRUE}, 
        {"CCC", "C_SIGNAL", FALSE, FALSE, FALSE, TRUE}, 
        {"DDD", "C_SIGNAL", FALSE, FALSE, FALSE, TRUE} 
       }, 
       new String[]{"ID", "Message Identifier", "0", "1", "2", ""} 
     )); 

     CellButton cellButton = new CellButton(); 
     signalTable.getColumn("0").setCellRenderer(cellButton); 
     signalTable.getColumn("0").setCellEditor(cellButton); 
     signalTable.getColumn("1").setCellRenderer(cellButton); 
     signalTable.getColumn("1").setCellEditor(cellButton); 
     signalTable.getColumn("2").setCellRenderer(cellButton); 
     signalTable.getColumn("2").setCellEditor(cellButton); 

     JScrollPane scrollPane = new javax.swing.JScrollPane(); 
     scrollPane.setViewportView(signalTable); 

     GroupLayout layout = new GroupLayout(getContentPane()); 

     getContentPane().setLayout(layout); 
     layout.setHorizontalGroup(
       layout.createParallelGroup(Alignment.LEADING) 
       .addGroup(Alignment.TRAILING, layout.createSequentialGroup() 
         .addContainerGap(10, Short.MAX_VALUE) 
         .addComponent(scrollPane, PREFERRED_SIZE, 700, 
          PREFERRED_SIZE) 
         .addContainerGap()) 
     ); 
     layout.setVerticalGroup(
       layout.createParallelGroup(Alignment.LEADING) 
       .addGroup(Alignment.TRAILING, layout.createSequentialGroup() 
         .addContainerGap(10, Short.MAX_VALUE) 
         .addComponent(scrollPane, PREFERRED_SIZE, 275, 
          PREFERRED_SIZE) 
         .addContainerGap()) 
     ); 
     pack(); 
    } 

    public static void main(String args[]) { 
     for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { 
      if ("Nimbus".equals(info.getName())) { 
       try { 
        UIManager.setLookAndFeel(info.getClassName()); 
       } catch (Exception ex) { 
        System.err.println("use default L&F"); 
       } 
       break; 
      } 
     } 

     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       new FrameDemo().setVisible(true); 
      } 
     }); 
    } 
} 

單元格編輯器和渲染器的類。

import java.awt.Color; 
import static java.awt.Color.BLACK; 
import static java.awt.Color.GREEN; 
import java.awt.Component; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import static java.lang.Boolean.FALSE; 
import static java.lang.Boolean.TRUE; 
import javax.swing.*; 
import javax.swing.border.Border; 
import javax.swing.table.TableCellEditor; 
import javax.swing.table.TableCellRenderer; 

public class CellButton extends AbstractCellEditor 
     implements TableCellEditor, TableCellRenderer { 

    private final JButton editButton = new JButton("edit btn."); 
    private final JButton renderButton = new JButton("render btn."); 
    private final Border focusBorder = BorderFactory.createLineBorder(BLACK); 
    private final Border defaultBorder; 
    private final Color inactiveColor; 
    private Boolean state = FALSE; 

    public CellButton() { 
     defaultBorder = renderButton.getBorder(); 
     inactiveColor = renderButton.getBackground(); 
     editButton.addMouseListener(new MouseAdapter() { 
      @Override 
      public void mouseExited(MouseEvent e) { 
       cancelCellEditing(); 
      } 
     }); 

     editButton.addActionListener((e) -> {stopCellEditing();}); 
    } 

    @Override 
    public Component getTableCellEditorComponent(JTable table, Object value, 
      boolean isSelected, int row, int column) { 
     state = FALSE.equals(value); 
     editButton.setBackground(state ? GREEN : inactiveColor); 
     table.setValueAt(state, row, column); 
     return editButton; 
    } 

    @Override 
    public Object getCellEditorValue() { 
     return state; 
    } 

    @Override 
    public Component getTableCellRendererComponent(JTable table, Object value, 
      boolean isSelected, boolean hasFocus, int row, int column) { 
     renderButton.setBorder(hasFocus ? focusBorder : defaultBorder); 
     renderButton.setBackground(TRUE.equals(value) ? GREEN : inactiveColor); 
     return renderButton; 
    } 
} 

該按鈕可以用鼠標或鍵盤來切換。

enter image description here