Swing:使用按钮组将切换按钮和相应的菜单项链接在一起

14
为了一个学校项目,我需要制作一个简单的绘图应用程序,可以绘制直线、椭圆和矩形。
该任务规定我需要为每种类型的形状提供工具栏按钮和菜单项。
我想做得更好一些,通过将按钮设置为工具栏中的JToggleButtons,将菜单项设置为JRadioButtonMenuItems。此外,当您选择其中一个工具栏按钮时,它会取消选择其他按钮,选择适当的菜单项并取消选择其他菜单项。选择其中一个菜单项也是同样的处理方式。
我知道我可以使用ButtonGroup将任何AbstractButton分组,但我不确定这是否是正确的方法,因为虽然它可以很好地处理一个"组"的按钮,但我不确定它是否能够处理两个平行的组。
如果不使用ButtonGroup,则意味着在6个事件监听器中,我必须手动取消选择其他按钮,并且每对按钮都会调用相同的代码来设置形状类型。
我还可以制作两个ButtonGroup,一个用于菜单,一个用于工具栏,但是这样也必须复制形状类型设置代码。
在任何情况下,我也有可能出现菜单设置按钮,按钮设置菜单项,菜单项设置按钮等无限循环的情况。
如何解决这个问题最好的方法是什么?
(如果能够使用Netbeans GUI设计器解决问题,那就有额外的加分了;这样做更容易)

5
如果没有GUI设计师,那么额外加分。你花时间学习Java,因为它是可移植的,而IDE则不是。 - camickr
@camickr - 我实际上更喜欢使用Textmate和终端而不是IDE,只是GUI设计师使事情变得如此快速。我的观点是,我宁愿在设计师中解决问题并查看它是如何完成的,而不是通过编辑自动生成的代码并花费数小时来弄清楚为什么小事情不起作用。 - Austin Hyde
1个回答

18

How to Use Actions所述,Action接口是一种有效的方法,“如果您有两个或更多个执行相同功能的组件”,特别是,Action允许您的按钮和菜单项使用相同的代码。

附加说明:下面的示例展示了一个JMenu和一个JToolBar如何为多个文件共享相同的Action

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.io.File;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JToolBar;

/** @see https://dev59.com/YW855IYBdhLWcg3w_5qm */
public class FileMenu {

    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {

            public void run() {
                new FileMenu().create();
            }
        });
    }

    void create() {
        File userDir = new File(System.getProperty("user.dir"));
        File[] files = userDir.listFiles();

        JMenu menu = new JMenu("Recent Files");
        JToolBar toolBar = new JToolBar(JToolBar.VERTICAL);
        JLabel label = new JLabel(" ", JLabel.CENTER);
        for (File f : files) {
            if (f.isFile() && !f.isHidden()) {
                RecentFile rf = new RecentFile(f, label);
                menu.add(new JMenuItem(rf.getAction()));
                toolBar.add(rf.getAction());
            }
        }
        JMenuBar menuBar = new JMenuBar();
        menuBar.add(menu);

        JFrame f = new JFrame("FileMenu");
        f.setJMenuBar(menuBar);
        f.add(toolBar, BorderLayout.CENTER);
        f.add(label, BorderLayout.SOUTH);
        f.pack();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}

class RecentFile extends AbstractAction {

    private final File file;
    private final JLabel label;

    public RecentFile(final File file, final JLabel label) {
        this.file = file;
        this.label = label;
        this.putValue(Action.NAME, file.getName());
        this.putValue(Action.SHORT_DESCRIPTION, file.getAbsolutePath());
    }

    public void actionPerformed(ActionEvent e) {
        label.setText(file.getName());

    }

    public Action getAction() {
        return this;
    }
}

3
+1,编写动作(Actions)和编写ActionListener一样容易,但动作提供了更多的总体功能。 - camickr
2
你能解释一下为什么在这段代码中,你要添加 (rf.getAction()) 而不只是 (rf) 到工具栏中吗? 这样做的目的是什么? - user unknown
2
@userunknown:好问题;看起来我是从另一个使用组合而不是扩展的示例中进行了调整。 - trashgod
1
经过约7年的休息后,我又回到了Java编程。很高兴看到我1996年的Java书中的一般设计模式仍然适用。 - clockw0rk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接