2012-04-27 24 views
20

Oto zrzut ekranu, co chcę zrobić:Making klikalny JButton wewnątrz JTable

enter image description here

Co się tam dzieje jest JButton pokazuje poprawnie, ale nic się nie dzieje po kliknięciu na nim. Po pewnym poszukiwań, znalazłem, że Object zwrócony przez table.getValueAt() jest String zamiast JButton ...

Oto kod:

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

Używam tego do wypełniania w czasie wykonywania JTable: (tblResult jest teraz 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)); 
    }} 
); 

Tutaj ClientsTableRenderer klasa

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


} 

I wreszcie, 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(); 
      } 

     } 
     } 
    } 

jestem uprzejmie nowy Java, pomoc będzie bardzo mile widziane :)

Z góry dzięki!

+0

value.getClass()? Zwraca również "java.lang.String" – noli

+0

CellRenderer są używane tylko do "pomalowania" tabeli, nie są ustawione jako "Komponenty aktywne". getValueAt zwraca wartość TableModel, a nie komponentu, więc prawdopodobnie zwróci "Consulter" –

+0

Tak właśnie myślałem. Czy istnieje jednak sposób, aby to naprawić? – noli

Odpowiedz

9

Problem polega na tym, że JButton nie istnieje już po namalowaniu w tabeli. Te komponenty są używane tylko do tworzenia "pieczątek", gdy tabela jest renderowana. Nie ma aktualnego przycisku.

Istnieje sposób, aby umożliwić kliknięcie przycisku, a nadal zachować tabelę nie do edycji, ale jest daleko od właściwego kodu. Wystarczy szybki szkic do możliwego rozwiązania (nie mam czasu, w tej chwili, aby dać pełny przykład kodu)

  • dołączyć słuchacza myszy na stole
  • po odebraniu przyciskiem myszy, określenia komórka, w której kliknięcie myszy wystąpiły
  • poprosić renderujący stołowego dla komponentu dla tej komórki
  • wykorzystywać położenie myszy, aby ustalić, czy przycisk jest obecna w składniku z poprzedniego etapu w danym miejscu
  • jeśli tak, kliknij przycisk API (metoda doClick)

A to nawet nie jest brudna część kodu. Ponieważ twój renderer (z nadzieją) nie zwraca za każdym razem nowego JButton, powinieneś w swoim ActionListener dołączyć do JButton śledzić, dla którego komponentu rzeczywiście nastąpiło kliknięcie. Możliwym rozwiązaniem jest zachowanie odniesienia do wartości modelu tabeli, dla której ostatnio utworzono metodę JButton (w metodzie getCellRendererComponent należy śledzić wiersz/kolumnę), ale nie jestem pewien, czy jest to najlepsze podejście.

Jak powiedziałem, możliwe rozwiązanie, ale dalekie od elegancji.

Najprostszym sposobem jest po prostu sprawiają, że jedna kolumna edytowalne i użyć edytora, jak wskazano w innych odpowiedzi

+0

Dziękuję za poświęcony czas. Cóż, nie jest tak sexy, jak się spodziewano, ale może być rozwiązaniem. – noli

+0

Mogę spróbować dodać jakiś kod, jeśli znajdę czas w weekend. Wiem, że powyższe rozwiązanie działa dla 'JTree', ponieważ go tam użyłem – Robin

7

Spróbuj tego:

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

Próbowałem tego i działa łatwo – Mikel

0

przeciążać Model tabeli i zestaw isCellEditable (int, int) zwraca false dla komórek za pomocą przycisków.

Działa wspaniale dzięki dodaniu MouseListener do tabeli.

0

Oto moje rozwiązanie

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

}

A oto jak go używać:

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