我需要一个JToggleButton(具有自定义背景),该JToggleButton包含一个JPanel,其内部带有多个JLabel。该部分有效。
此按钮此后放置在JTable单元中,供用户按下。问题是我只能在第二次单击时按下按钮。第一次单击时,首先将焦点移到带有JLabel的面板上,然后才跳转到实际按钮。
我尝试了几种方法来尝试解决此问题,但是相同的问题仍然存在。
A)将带有标签的JPanel直接放置在JToggleButton#add()上。
B)使用JLayeredPane将Button和JPanel放置在JToggleButton接受约束Integer(-)的不同图层上,以便带有JLabel的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);
}
}
最佳答案
当表捕获鼠标事件以选择一个单元格时,它会将鼠标事件传递给最深层的组件,而不管该组件是否可以处理鼠标事件。在您的示例中,第一次单击最终结束于JLabels
之一,从而完全绕开了JToggleButton
。 JToggleButton
成为 Activity 单元格编辑器后,单击鼠标即可正常工作。如果失去焦点,则需要再次单击两次才能激活。
如果您在演示中注意到单击按钮边框(而不是包含的面板),也可以看到此按钮,该按钮将按需工作。
解决此问题的一种方法是确保针对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);
此后,按钮上任何组件上的任何鼠标事件也将到达按钮,因此更改其状态。完成此操作后,我发现按钮可根据需要对每次单击使用react。