2012-03-06 76 views
5

我需要一個JToggleButton(它具有自定義背景),它包含一個JPanel和幾個JLabel。該部分起作用。將JToggleButton和JPanel放在一個JTable單元格中

此按鈕被放置在一個JTable單元中,並被用戶按下。問題是我只能按第二次點擊按鈕。第一次單擊焦點時首先用JLabels跳到面板,然後再跳到實際的按鈕。

我嘗試了幾件事來嘗試解決這個問題,但同樣的問題依然存在。 A)將帶有標籤的JPanel直接放到JToggleButton#add()上。 B)使用JLayeredPane將Button和JPanel放置到不同的圖層上,其中JToggleButton採用約束整數( - ),使帶有JLabels的JPanel保持可見頂部

您有任何提示嗎?謝謝

下面是說明問題的示例代碼。點擊該按鈕只能再次使用。

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

不直接關係到你的問題:編輯器實現_invalid_:當編輯終止內部原因,_must_通知其聽衆。至於你的問題:基本上你必須a)確保在第一次點擊時開始編輯b)抓住該點擊,在編輯組件座標中計算它的位置,並在編輯時調度到「真實」目標組件(fi按鈕)面板 – kleopatra 2012-03-12 09:15:01

+2

順便說一句:你永遠不會在你的tableModel中保留組件...因爲你的TableModel實現也很腥(它宣佈它是可編輯的,但缺少任何改變單元格值的API),也許你應該閱讀並理解一些桌面基礎知識,然後在不太平凡的東西中間跳躍:-) – kleopatra 2012-03-12 09:18:31

+0

@kleopatra,感謝您的提示。你可能會鏈接/顯示如何:a)確保編輯在第一次點擊時開始b)抓住該點擊,在編輯組件座標中計算它的位置並在編輯面板上發送到「真實」目標組件 我不是確定你將事件分派給真正的目標是什麼意思,它是doClick()調用你的意思。如果是這樣,恐怕我會失去jToggleButton提供的點擊動畫。 – d56 2012-03-12 09:25:49

回答

8

當表捕獲鼠標事件來選擇不管該組件是否能處理鼠標事件它傳遞到最深部件鼠標事件的細胞。在你的例子中,第一次點擊結束於JLabels之一,完全繞過JToggleButton。一旦JToggleButton已成爲活動單元格編輯器,鼠標點擊正常工作。如果它失去了重點,它將再次需要雙擊才能激活。

如果您在演示中注意到您點擊了按鈕邊框,而不是在包含的面板上,那麼您可以看到此按鈕,該按鈕按需要工作。

解決此問題的一種方法是確保任何針對JToggleButton內的任何組件的鼠標事件。爲此,您可以使用此靜態方法:

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

,然後在你的構造函數調用結束:

addEventBubble(this,this); 

這在按鈕中的任何組件的任何鼠標事件後也將達到按鈕,因此改變了它的狀態。做完這些之後,我發現按鈕會根據需要對每次點擊做出反應。

+0

我在http://www.coderanch.com/t/570021/GUI/java上獲得了另一個解決方案/ click-event-custom-JToggleButton-JTable 它很「脆弱」但代碼較少。我想我會堅持下去。 謝謝你的解釋和解決方案,我需要這麼多。 – d56 2012-03-13 20:24:20

+0

看了之後,「脆弱」的確是這個詞:)謝謝分享。 – 2012-03-13 23:44:51