2012-04-27 29 views
20

Dưới đây là ảnh chụp màn hình của những gì tôi muốn làm:Làm một nhấp được JButton bên trong một JTable

enter image description here

gì đang xảy ra ở đó là JButton cho thấy một cách chính xác nhưng có gì xảy ra khi tôi bấm vào nó. Sau khi một số tìm kiếm, tôi đã phát hiện ra rằng Object trả về bởi table.getValueAt() là một chuỗi thay vì một JButton ...

Đây là mã:

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

tôi sử dụng này cho Populating tại thời gian chạy các JTable: (tblResult tại Clients.rblResult là)

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

Ở đây ClientsTableRenderer lớp

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


} 

và cuối cùng, các 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(); 
      } 

     } 
     } 
    } 

Tôi vui lòng mới cho Java, trợ giúp sẽ được rất nhiều đánh giá cao :)

Cảm ơn trước!

+0

value.getClass()? Nó cũng trả về "java.lang.String" – noli

+0

CellRenderer chỉ được sử dụng để "vẽ" bảng, chúng không được đặt là "Thành phần trực tiếp". getValueAt trả về một giá trị của TableModel, không phải là một thành phần, vì vậy nó có thể sẽ trả về "Consulter" –

+0

Đó là những gì tôi nghĩ. Tuy nhiên, có cách nào để sửa chữa nó? – noli

Trả lời

9

Vấn đề là JButton không còn tồn tại khi được sơn trong bảng. Những thành phần này chỉ được sử dụng để tạo ra một 'tem' khi bảng được hiển thị. Không có nút thực tế nào.

Có một cách để cho phép bạn nhấp vào nút và vẫn giữ cho bảng của bạn không thể chỉnh sửa, nhưng nó cách xa mã thích hợp. Chỉ cần một phác thảo nhanh chóng cho một giải pháp khả thi (Tôi không có thời gian tại thời điểm này để cung cấp cho một ví dụ mã đầy đủ)

  • đính kèm một người biết lắng nghe chuột vào bảng
  • khi bạn nhận được một cú nhấp chuột, xác định tế bào trong đó click chuột xảy ra
  • hỏi các renderer bảng cho các thành phần cho rằng tế bào
  • sử dụng vị trí của click chuột để xác định xem một nút có mặt trong thành phần từ bước trước ở nơi đặc biệt
  • nếu có, hãy nhấp qua nút api (phương pháp doClick)

Và đây không phải là phần bẩn của mã. Vì trình kết xuất của bạn (hy vọng) không trả lại JButton mỗi lần, bạn nên nhập số ActionListener được đính kèm vào JButton theo dõi thành phần nào mà nhấp chuột thực sự xảy ra. Một giải pháp có thể là để giữ tham chiếu đến giá trị mô hình bảng mà bạn đã tạo lần cuối JButton (vì vậy trong phương thức getCellRendererComponent theo dõi hàng/cột), nhưng tôi không chắc liệu đây có phải là phương pháp tốt nhất hay không.

Như đã nói, một giải pháp có thể nhưng cách xa thanh lịch.

Cách đơn giản nhất là chỉ cần làm cho điều đó một cột có thể chỉnh sửa và sử dụng một trình soạn thảo, như đã chỉ ra trong câu trả lời khác

+0

Cảm ơn bạn đã dành thời gian. tốt, nó không phải là sexy như mong đợi nhưng nó có thể là một giải pháp. – noli

+0

Tôi có thể thử thêm một số mã nếu tôi tìm thấy thời gian trong ngày cuối tuần. Tôi biết các giải pháp trên hoạt động cho một 'JTree' như tôi đã sử dụng nó ở đó – Robin

7

Hãy thử điều này:

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

Tôi đã thử điều này và hoạt động dễ dàng – Mikel

0

quá tải của bạn Mô hình bảng và đặt isCellEditable (int, int) trả về false cho các ô có các nút.

Nó hoạt động tốt với một Trình ghi chuột được thêm vào bảng.

0

Đây là giải pháp của tôi

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

}

Và đây là làm thế nào để sử dụng nó:

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