2012-04-27 2 views
20

Вот скриншот того, что я хочу сделать:Создание кликабельным JButton внутри JTable

enter image description here

Что там происходит это JButton правильно показывает, но ничего не происходит, когда я нажимаю на него. После некоторого поиска я обнаружил, что Object возвращаемый table.getValueAt() является строка вместо JButton ...

Вот код:

tblResult = new JTable(data,cols) { 
    public TableCellRenderer getCellRenderer(int row, int column) { 
     return new ClientsTableRenderer(); 
    } 
}; 

Я использую это для заполнения во время выполнения JTable: (tblResult теперь Clients.rblResult)

SwingUtilities.invokeLater(new Runnable() { 
    public void run() { 

     DefaultTableModel aModel = new DefaultTableModel() { 
      //setting the jtable read only 
      @Override 
      public boolean isCellEditable(int row, int column) { 
       return false; 
      }    
     }; 


    String[] cols = {"N°","Société", "TVA", "CP", "Ville", ""}; 
    aModel.setColumnIdentifiers(cols); 

    Object[] temp = new Object[6]; 
    for(int i=0;i<result.length;i++) { 

     temp[0] = result[i].custNumber; 
     temp[1] = result[i].name; 
     temp[2] = result[i].tva; 
     temp[3] = result[i].cp; 
     temp[4] = result[i].city; 
     temp[5] = "Consulter"; 

     aModel.addRow(temp); 

    } 

    Clients.tblResult.setModel(aModel); 

    Clients.tblResult.addMouseListener(new JTableButtonMouseListener(Clients.tblResult)); 
    }} 
); 

Здесь ClientsTableRenderer класс

public class ClientsTableRenderer extends JPanel implements TableCellRenderer { 
    @Override 
    public Component getTableCellRendererComponent(final JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 
     setBackground(Color.WHITE); 
     if(column < 5) { 
      JLabel label = new JLabel(value.toString()); 
      JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER,0,9)); 
      panel.setBackground(Color.WHITE); 
      panel.add(label); 
      this.add(panel); 
     } else { 

      JButton button = new JButton(value.toString()); 
      button.addActionListener(new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent arg0) { 
        System.out.println("Clicked !"); 
       } 
      }); 
      JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER,0,3)); 
      panel.setBackground(Color.WHITE); 
      panel.add(button); 
      this.add(panel); 
     } 


     return this; 
    } 


} 

И, наконец, то JTableButtonMouseListener():

public class JTableButtonMouseListener extends MouseAdapter { 
     private final JTable table; 

     public JTableButtonMouseListener(JTable table) { 
     this.table = table; 
     } 

     @Override public void mouseClicked(MouseEvent e) { 
     int column = table.getColumnModel().getColumnIndexAtX(e.getX()); 
     int row = e.getY()/table.getRowHeight(); 
     System.out.println("Col :"+column + "row:"+row); 

     if (row < table.getRowCount() && row >= 0 && column < table.getColumnCount() && column >= 0) { 
      Object value = table.getValueAt(row, column); 
      System.out.println("Value :"+value.getClass().getName()); 
      if (value instanceof JButton) { 
      ((JButton)value).doClick(); 
      } 

     } 
     } 
    } 

Я любезно новичок в Java, помощь будет очень признателен :)

Заранее спасибо!

+0

value.getClass()? Он также возвращает «java.lang.String» – noli

+0

CellRenderer используются только для «рисования» таблицы, они не заданы как «Живые компоненты». getValueAt возвращает значение TableModel, а не компонент, поэтому он, вероятно, вернет «Consulter» –

+0

Вот что я подумал. Однако есть ли способ исправить это? – noli

ответ

9

Проблема в том, что JButton больше не существует при окрашивании в стол. Эти компоненты используются только для создания «штампа» при рендеринге таблицы. Фактической кнопки нет.

Существует способ, позволяющий вам нажимать на кнопку, и по-прежнему сохраняют таблицу не редактируемой, но это далеко не правильный код. Просто быстрый набросок возможного решения (у меня нет времени на данный момент, чтобы дать полный пример кода)

  • прикрепить слушатель мыши к столу
  • при получении мышей, определить клеток, в которых мыши произошли
  • задать таблицу рендерер для компонента для этой ячейки
  • использовать расположение мыши, чтобы определить, присутствует ли в компоненте из предыдущего шага кнопки в конкретном месте
  • если это так, сделайте щелчок по кнопке api (метод doClick)

И это даже не грязная часть кода. Так как ваш рендерер (надеюсь) не возвращает новый JButton каждый раз, вы должны в своем ActionListener, который прикреплен к JButton, отслеживать, для какого компонента действительно произошел щелчок. Возможным решением является сохранение ссылки на значение модели таблицы, для которой вы в последний раз создали JButton (поэтому в методе getCellRendererComponent отслеживать строку/столбец), но я не уверен, что это лучший подход.

Как сказано, возможное решение, но далекое от элегантного.

Самый простой способ это просто сделать, что один столбец для редактирования и использовать редактор, как указано в других ответах

+0

Спасибо за ваше время. ну, это не так сексуально, как ожидалось, но это может быть решение. – noli

+0

Я могу попытаться добавить код, если найду время в выходные. Я знаю, что вышеупомянутое решение работает для 'JTree', поскольку я использовал его там – Robin

7

Попробуйте это:

import java.awt.Color; 
import java.awt.Component; 
import java.awt.EventQueue; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

import javax.swing.DefaultCellEditor; 
import javax.swing.JButton; 
import javax.swing.JCheckBox; 
import javax.swing.JFrame; 
import javax.swing.JOptionPane; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.UIManager; 
import javax.swing.table.DefaultTableModel; 
import javax.swing.table.TableCellRenderer; 
import javax.swing.table.TableModel; 

public class TableWithButtonDemo 
{ 
    private JFrame frame = new JFrame("Table Demo"); 
    private String[] columnNames = { "String", "Integer", "Float", "" }; 
    private Object[][] data = { { "Dummy", new Integer(12), new Float(12.15), "Consulter" } }; 
    private TableModel model = new DefaultTableModel(data, columnNames) 
    { 
    private static final long serialVersionUID = 1L; 

    public boolean isCellEditable(int row, int column) 
    { 
     return column == 3; 
    } 
    }; 
    private JTable table = new JTable(model); 

    public TableWithButtonDemo() 
    { 
    table.getColumnModel().getColumn(3).setCellRenderer(new ClientsTableButtonRenderer()); 
    table.getColumnModel().getColumn(3).setCellEditor(new ClientsTableRenderer(new JCheckBox())); 
    table.setPreferredScrollableViewportSize(table.getPreferredSize()); 
    table.setShowHorizontalLines(true); 
    table.setShowVerticalLines(false); 

    JScrollPane scroll = new JScrollPane(table); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.add(scroll); 
    frame.pack(); 
    frame.setLocation(150, 150); 
    frame.setVisible(true); 
    } 

    public static void main(String[] args) throws Exception 
    { 
    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
    EventQueue.invokeLater(new Runnable() 
    { 
     public void run() 
     { 
     new TableWithButtonDemo(); 
     } 
    }); 
    } 

    class ClientsTableButtonRenderer extends JButton implements TableCellRenderer 
    { 
    public ClientsTableButtonRenderer() 
    { 
     setOpaque(true); 
    } 

    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) 
    { 
     setForeground(Color.black); 
     setBackground(UIManager.getColor("Button.background")); 
     setText((value == null) ? "" : value.toString()); 
     return this; 
    } 
    } 
    public class ClientsTableRenderer extends DefaultCellEditor 
    { 
    private JButton button; 
    private String label; 
    private boolean clicked; 
    private int row, col; 
    private JTable table; 

    public ClientsTableRenderer(JCheckBox checkBox) 
    { 
     super(checkBox); 
     button = new JButton(); 
     button.setOpaque(true); 
     button.addActionListener(new ActionListener() 
     { 
     public void actionPerformed(ActionEvent e) 
     { 
      fireEditingStopped(); 
     } 
     }); 
    } 
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) 
    { 
     this.table = table; 
     this.row = row; 
     this.col = column; 

     button.setForeground(Color.black); 
     button.setBackground(UIManager.getColor("Button.background")); 
     label = (value == null) ? "" : value.toString(); 
     button.setText(label); 
     clicked = true; 
     return button; 
    } 
    public Object getCellEditorValue() 
    { 
     if (clicked) 
     { 
     JOptionPane.showMessageDialog(button, "Column with Value: "+table.getValueAt(row, 1) + " - Clicked!"); 
     } 
     clicked = false; 
     return new String(label); 
    } 

    public boolean stopCellEditing() 
    { 
     clicked = false; 
     return super.stopCellEditing(); 
    } 

    protected void fireEditingStopped() 
    { 
     super.fireEditingStopped(); 
    } 
    } 

} 
+0

Я пробовал это и работает легко – Mikel

0

перегружать Модель таблицы и set isCellEditable (int, int) возвращает false для ячеек с кнопками.

Он отлично работает с MouseListener, добавленным к столу.

0

Вот мое решение

ButtonEditor.java

public abstract class ButtonEditor extends DefaultCellEditor implements ActionListener { 
private static final long serialVersionUID = 1L; 

/** The cell's row. */ 
protected int row; 

/** The cell's column. */ 
protected int column; 

/** The cell's column. */ 
protected JTable table; 

/** The button we are editing. */ 
protected JButton button; 

/** The panel used when editing. */ 
protected JPanel panel = new JPanel(new GridBagLayout()); 

/** Constructor */ 
public ButtonEditor() {super(new JCheckBox());} 

/** 
* This method is called when the user try to modify a cell. 
* In this case it will be called whenever the user click on the cell. 
* @param table 
* @param value 
* @param isSelected 
* @param row 
* @param column 
* @return JPanel The JPanel returned contains a JButton with an ActionListener. 
*/ 
@Override 
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { 
    this.row = row; 
    this.column = column; 
    this.table = table; 
    button = (JButton) value; 

    //prevent to add the action listener everytime the user click on the cell. 
    if(button.getActionListeners().length == 0) button.addActionListener(this); 

    panel.add(button); 
    panel.setBackground(table.getGridColor()); 
    return panel; 
} 

/** 
* Return a renderer for JButtons. The result is a button centered in the table's cell. 
* @return 
*/ 
public static TableCellRenderer getRenderer() { 
    return new TableCellRenderer() { 
     @Override 
     public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 
      JPanel panel = new JPanel(new GridBagLayout()); 
      panel.add((JButton) value); 
      panel.setBackground(table.getGridColor()); 
      return panel; 
     } 
    }; 
} 

}

А вот как его использовать:

Demo.java

table.setDefaultRenderer(JButton.class, ButtonEditor.getRenderer()); 
    table.setDefaultEditor(JButton.class, new ButtonEditor() { 
     @Override 
     public void actionPerformed(ActionEvent e) { 

      //handle clicks here. for example: 
      if(column == 5) { 
       System.out.Println(row); 
       button.setFocusPainted(false);     
      } 
     } 
    }); 
Смежные вопросы