2012-03-06 68 views
5

Tôi cần có nút JToggleButton (có nền tùy chỉnh) chứa JPanel với một số JLabels bên trong chính nó. Phần đó hoạt động.Đặt JToggleButton với JPanel vào trong ô JTable

Nút này được đặt sau đó trong ô JTable và có nghĩa là được ép bởi người dùng. Vấn đề là tôi chỉ có thể nhấn nút trên lần nhấp thứ hai. Apperenty trên lần đầu tiên nhấp vào tiêu điểm đầu tiên nhảy vào bảng điều khiển với JLabels và chỉ sau đó đến nút thực tế.

Tôi đã thử một số cách để giải quyết vấn đề này, nhưng vấn đề tương tự vẫn tồn tại. A) đặt JPanel với nhãn trực tiếp lên nút JToggleButton # add(). B) sử dụng JLayeredPane để đặt Nút và JPanel lên các Lớp khác nhau trong đó JToggleButton lấy ràng buộc Số nguyên (-) sao cho JPanel với JLabels vẫn hiển thị trên đầu trang

Bạn có lời khuyên nào không? Cảm ơn

Dưới đây là mã mẫu minh họa sự cố. Nhấp vào nút chỉ hoạt động lần thứ hai.

public class ClickableCustomButtonInTable extends JToggleButton { 

public ClickableCustomButtonInTable() { 
    Dimension d = new Dimension(100, 100); 
    JLabel lFirst = new JLabel("1st label"); 
    lFirst.setPreferredSize(d); 

    JLabel lSecond = new JLabel("2nd label"); 
    lSecond.setPreferredSize(d); 

    JPanel panel = new JPanel(); 
    panel.setOpaque(true); 

    panel.setLayout(new BorderLayout()); 
    panel.add(lFirst, BorderLayout.NORTH); 
    panel.add(lSecond, BorderLayout.SOUTH); 
    add(panel); 
    addActionListener(new ActionListener() { 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      System.out.println("Button clicked"); 
     } 
    }); 
} 

private static class CustomButtonRenderer implements TableCellRenderer { 

    private final ClickableCustomButtonInTable button = new ClickableCustomButtonInTable(); 

    @Override 
    public Component getTableCellRendererComponent(JTable table, 
      Object value, boolean isSelected, boolean hasFocus, int row, 
      int column) { 
     return button; 
    } 
} 

private static class CustomButtonEditor extends AbstractCellEditor 
     implements TableCellEditor { 

    private final ClickableCustomButtonInTable button = new ClickableCustomButtonInTable(); 

    @Override 
    public Object getCellEditorValue() { 
     return button.getText(); 
    } 

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

} 

public static void main(String[] args) { 
    JFrame frame = new JFrame(); 
    frame.setSize(new Dimension(200, 200)); 
    Container content = frame.getContentPane(); 
    TableModel model = new AbstractTableModel() { 

     @Override 
     public Object getValueAt(int rowIndex, int columnIndex) { 
      return null; 
     } 

     @Override 
     public int getRowCount() { 
      return 1; 
     } 

     @Override 
     public int getColumnCount() { 
      return 1; 
     } 

     @Override 
     public boolean isCellEditable(int rowIndex, int columnIndex) { 
      return true; 
     } 

     @Override 
     public Class<?> getColumnClass(int columnIndex) { 
      return ClickableCustomButtonInTable.class; 
     } 
    }; 

    JTable table = new JTable(model); 
    // table.setBounds(new Rectangle(0, 0, content.getWidth(), content 
    // .getHeight())); 
    table.setRowHeight(frame.getHeight()); 
    table.setDefaultRenderer(ClickableCustomButtonInTable.class, 
      new CustomButtonRenderer()); 
    table.setDefaultEditor(ClickableCustomButtonInTable.class, 
      new CustomButtonEditor()); 

    content.add(table); 
    content.setVisible(true); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.setVisible(true); 
} 
} 
+1

không liên quan trực tiếp đến vấn đề của bạn: việc thực hiện biên tập là _invalid_: nó _must_ thông báo cho người nghe nó khi chỉnh sửa được chấm dứt vì lý do nội bộ. Đối với vấn đề của bạn: về cơ bản bạn phải a) đảm bảo chỉnh sửa được bắt đầu vào lần nhấp đầu tiên b) lấy nhấp chuột đó, tính vị trí của nó trong chỉnh sửa tọa độ thành phần và gửi đến thành phần đích "thực" (fi nút) trên chỉnh sửa Bảng điều khiển – kleopatra

+2

BTW: bạn _never-ever_ giữ các thành phần trong tableModel của bạn ... như thực hiện TableModel của bạn cũng có thể chỉnh sửa nhưng thiếu bất kỳ api nào để thay đổi các giá trị của ô), có lẽ bạn nên đọc và hiểu bảng cơ bản trước khi nhảy ngay ở giữa các công cụ không quá tầm thường :-) – kleopatra

+0

@ kleopatra, cảm ơn lời khuyên của bạn. Bạn có thể liên kết/hiển thị cách a) đảm bảo chỉnh sửa được bắt đầu vào lần nhấp đầu tiên b) lấy nhấp chuột đó, tính vị trí của nó trong chỉnh sửa tọa độ thành phần và gửi đến thành phần đích "thực" trên bảng chỉnh sửa tôi không chắc chắn những gì bạn có nghĩa là bằng cách gửi sự kiện đến mục tiêu thực sự, là nó doClick() gọi những gì bạn có ý nghĩa.nếu vậy, tôi sợ tôi sẽ mất hoạt hình nhấp chuột mà jToggleButton cung cấp. – d56

Trả lời

0
+1

mà hầu hết có thể sẽ không tiết kiệm sự nghiệp của bạn ;-) Tốt hơn hãy học cách _correctly_ sử dụng bảng/trình kết xuất/biên tập viên ... – kleopatra

+0

có gì sai với giải pháp đó? – d56

+0

tất cả mọi thứ là sai, bắt đầu với một số viên đạn trong ý kiến ​​của tôi cho câu hỏi của bạn ... – kleopatra

8

Khi bảng chụp sự kiện chuột để chọn ô, nó chuyển sự kiện chuột vào thành phần sâu nhất bất kể thành phần đó có thể xử lý sự kiện chuột hay không. Trong ví dụ của bạn, nhấp chuột đầu tiên kết thúc trên một trong số JLabels, bỏ qua hoàn toàn JToggleButton. Khi số JToggleButton trở thành trình chỉnh sửa ô hiện hoạt, lần nhấp chuột hoạt động bình thường. Nếu nó bị mất tập trung, nó một lần nữa sẽ yêu cầu hai lần nhấp chuột để kích hoạt.

Bạn cũng có thể thấy điều này nếu bạn nhận thấy trong bản trình diễn của mình, bạn bấm vào đường viền nút, chứ không phải trên bảng điều khiển chứa, nút hoạt động như mong muốn.

Một cách để giải quyết vấn đề này là đảm bảo rằng mọi sự kiện chuột được nhắm mục tiêu tại bất kỳ thành phần nào trong số JToggleButton. Bạn có thể làm điều này bằng phương pháp này tĩnh:

static void addEventBubble(final Container target, Container container) { 
    for(Component comp:container.getComponents()) { 
     if (comp instanceof Container) { 
      addEventBubble(target, (Container) comp); 
     } 
     comp.addMouseListener(new MouseAdapter() { 
      private MouseEvent retarget(MouseEvent e) { 
       return new MouseEvent(target, e.getID(), e.getWhen(), 
         e.getModifiers(), e.getX(), e.getY(), 
         e.getClickCount(), e.isPopupTrigger(), 
         e.getButton()); 
      } 


      public void mousePressed(MouseEvent e) { 
       MouseEvent r = retarget(e); 
       for(MouseListener listen:target.getMouseListeners()) { 
        listen.mousePressed(r); 
       } 
      } 


      public void mouseReleased(MouseEvent e) { 
       MouseEvent r = retarget(e); 
       for(MouseListener listen:target.getMouseListeners()) { 
        listen.mouseReleased(r); 
       } 
      } 


      public void mouseClicked(MouseEvent e) { 
       MouseEvent r = retarget(e); 
       for(MouseListener listen:target.getMouseListeners()) { 
        listen.mouseClicked(r); 
       } 
      } 
     }); 
    } 
} 

và sau đó ở phần cuối của constructor invoke của bạn:

addEventBubble(this,this); 

Sau này bất kỳ sự kiện chuột vào bất kỳ thành phần trong nút cũng sẽ đạt nút và do đó thay đổi trạng thái của nó. Sau khi làm điều này, tôi thấy nút phản ứng với mọi nhấp chuột như mong muốn.

+0

Tôi đã được đưa ra một giải pháp khác tại http://www.coderanch.com/t/570021/GUI/java/click-event-custom-JToggleButton-JTable Đó là "dễ vỡ" nhưng ít mã hơn. Tôi nghĩ rằng tôi sẽ gắn bó với nó sau đó. Cảm ơn bạn đã giải thích và giải pháp, tôi cần cả hai rất nhiều. – d56

+0

Có vẻ, "giòn" thực sự là từ cho nó :) Cảm ơn bạn đã chia sẻ. –

Các vấn đề liên quan