2012-04-27 10 views
20

Ecco lo screenshot di quello che voglio fare:Fare un cliccabile JButton all'interno di una JTable

enter image description here

Quello che sta succedendo c'è il JButton mostra correttamente, ma non succede nulla quando faccio clic su di esso. Dopo qualche ricerca, ho scoperto che il Object restituito da table.getValueAt() è una stringa invece di un JButton ...

Ecco il codice:

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

Io lo uso per la compilazione a run-time la JTable: (tblResult è ora 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)); 
    }} 
); 

Qui la ClientsTableRenderer classe

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; 
    } 


} 

E finalmente, il 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(); 
      } 

     } 
     } 
    } 

Sono gentilmente nuovo a Java, l'aiuto sarebbe molto apprezzato :)

Grazie in anticipo!

+0

value.getClass()? Restituisce anche "java.lang.String" – noli

+0

CellRenderer è usato solo per "dipingere" la tabella, non sono impostati come "Componenti live". getValueAt restituisce un valore di TableModel, non un componente, quindi probabilmente restituirà "Consulter" –

+0

Questo è quello che pensavo. Tuttavia, c'è un modo per risolverlo? – noli

risposta

9

Il problema è che il JButton non esiste più se dipinto nella tabella. Questi componenti vengono utilizzati solo per creare un 'timbro' quando la tabella viene renderizzata. Non è presente alcun pulsante attuale.

C'è un modo per consentire di fare clic sul pulsante, e mantenere la tabella non modificabile, ma è lontano dal codice corretto. Solo un rapido schema per una possibile soluzione (non ho il tempo in questo momento per dare un esempio di codice completo)

  • allegare un listener del mouse al tavolo
  • quando si riceve un clic del mouse, determinare il cellule in cui il mouse verificato
  • chiedere il rendering tavolo per il componente di quella cella
  • utilizzare la posizione del mouse per determinare se un pulsante è presente nel componente della fase precedente a quella particolare posizione
  • in tal caso, fare clic con il pulsante api (il metodo doClick)

E questa non è nemmeno la parte sporca del codice. Dal momento che il tuo renderer (si spera) non restituisce un nuovo JButton ogni volta, dovresti nel tuo ActionListener che è collegato allo JButton tenere traccia di quale componente il clic si è effettivamente verificato. Una possibile soluzione è di mantenere un riferimento al valore del modello di tabella per cui l'ultima volta è stato creato un JButton (quindi nel metodo getCellRendererComponent tenere traccia della riga/colonna), ma non sono sicuro se questo è l'approccio migliore.

Come detto, una soluzione possibile ma tutt'altro che elegante.

Il modo più semplice è quello di fare solo che una colonna modificabile e utilizzare un editor, come sottolineato in altre risposte

+0

Grazie per il tuo tempo. beh, non è sexy come previsto, ma potrebbe essere una soluzione. – noli

+0

Potrei provare ad aggiungere del codice se trovo il tempo durante il fine settimana. So che la soluzione di cui sopra funziona per un 'JTree' come l'ho usato lì – Robin

7

Prova questa:

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

Ho provato questo e funziona facilmente – Mikel

0

sovraccarico tua Modello di tabella e imposta isCellEditable (int, int) return false per le celle con i pulsanti.

Funziona perfettamente con un MouseListener aggiunto alla tabella.

0

Ecco la mia soluzione

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; 
     } 
    }; 
} 

}

Ed ecco come usarlo:

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);     
      } 
     } 
    });