【问题标题】:Placing JToggleButton with JPanel within into a JTable cell将带有 JPanel 的 JToggleButton 放入 JTable 单元格中
【发布时间】:2012-03-24 04:59:26
【问题描述】:

我需要一个 JToggleButton(具有自定义背景),其中包含一个 JPanel,其中包含多个 JLabel。那部分有效。

此按钮随后被放置在 JTable 单元格中,并且是供用户按下的。问题是我只能在第二次点击时按下按钮。 Apperenty 在第一次单击时,焦点首先跳转到带有 JLabels 的面板,然后才跳转到实际按钮。

我尝试了几种方法来尝试解决此问题,但同样的问题仍然存在。 A) 将带有标签的 JPanel 直接放在 JToggleButton#add() 上。 B) 使用 JLayeredPane 将 Button 和 JPanel 放置到 JToggleButton 采用约束 Integer(-) 的不同层上,以便带有 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);
}
}

【问题讨论】:

  • 与您的问题没有直接关系:编辑器实现无效:当编辑因内部原因终止时,它必须通知其侦听器。至于你的问题:基本上你必须a)确保在第一次点击时开始编辑b)抓住那个点击,计算它在编辑组件坐标中的位置并在编辑时发送到“真实”目标组件(fi按钮)面板
  • 顺便说一句:你永远不会在你的 tableModel 中保留组件......因为你的 TableModel 实现也很可疑(它宣布可编辑但缺少任何 api 来更改单元格值),也许您应该阅读并理解一些表格基础知识,然后再跳到不那么琐碎的东西中间:-)
  • @kleopatra,感谢您的提示。您能否链接/显示如何 a) 确保在第一次单击时开始编辑 b) 抓住该单击,计算其在编辑组件坐标中的位置并发送到编辑面板上的“真实”目标组件我不确定是什么你的意思是通过将事件调度到真正的目标,是 doClick() 调用你的意思。如果是这样,恐怕我会失去 jToggleButton 提供的点击动画。
  • TablePopupEditor 可以替代吗?
  • 垃圾神,不是真的。我需要的是一个可点击的 ToggleButton,上面放置了一些附加小部件,没有弹出窗口。

标签: java swing jtable jlayeredpane jtogglebutton


【解决方案1】:

当表格捕获鼠标事件以选择单元格时,它将鼠标事件传递给最深的组件,而不管该组件是否可以处理鼠标事件。在您的示例中,第一次点击最终到达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);

在此之后,按钮内任何组件上的任何鼠标事件也将到达按钮并因此改变其状态。完成此操作后,我发现按钮对每次点击都会做出反应。

【讨论】:

  • coderanch.com/t/570021/GUI/java/… 为我提供了另一个解决方案,它“脆弱”但代码更少。我想我会坚持下去。感谢您的解释和解决方案,我都非常需要。
  • 看了,确实是“脆”这个词:)谢谢分享。
【解决方案2】:

【讨论】:

  • 这很可能不会挽救你的职业生涯 ;-) 更好地学习如何正确使用表格/渲染器/编辑器...
  • 一切都错了,从我的 cmets 中的一些项目符号开始到您的问题...
  • 我只指这部分 ((ClickableCustomButtonInTable)(SwingUtilities.getAncestorOfClass(ClickableCustomButtonInTable.class,SwingUtilities.getDeepestComponentAt(table,me.getX(),me.getY())))).doClick( );其余代码只是一个示例,实际代码是不同的(但感谢有关在表格模型中包含组件的提示)
猜你喜欢
  • 2011-03-14
  • 1970-01-01
  • 2021-12-28
  • 1970-01-01
  • 1970-01-01
  • 2013-05-09
  • 1970-01-01
  • 2021-08-28
相关资源
最近更新 更多