swing - 使用 JComponents 时的命令模式有用性

标签 swing design-patterns jbutton jmenuitem command-pattern

所以,我正在使用 Swing 库开发一个程序,我显然有按钮和菜单项。其中一些应该做同样的事情,我认为使用命令模式应该是这样做的方式,例如我有一个“保存”按钮和一个“保存”菜单项,它们必须实现相同的保存算法。
命令模式似乎没问题,但我不知道谁是接收者。一个命令不是应该在一个实现某种“接收器接口(interface)”的对象上工作,这样你就可以在不同的接收器上使用不同的命令来任意耦合它们吗?看起来我的模式实现中没有“接收器”。
我的另一个疑问是命令是否应该作为单例实现,因为您可能会从同一项目的不同部分调用它的函数,并且只实例化一次并使其静态调用会很方便吗?

谢谢你。

最佳答案

" I obviously have buttons and menu items. Some of these are supposed to do the same stuff,"



正如@nIcEcOw 所说,这就是 Action s 是为了。 This Answer正是表明了这一点。

How to use Actions 中所述:

An Action can be used to separate functionality and state from a component. For example, if you have two or more components that perform the same function, consider using an Action object to implement the function. An Action object is an action listener that provides not only action-event handling, but also centralized handling of the state of action-event-firing components such as tool bar buttons, menu items, common buttons, and text fields. The state that an action can handle includes text, icon, mnemonic, enabled, and selected status.



enter image description here

安只有三个Actions .打开、保存和新建。每个Action有一个 ActionCommand , 和 icon ,以及要执行的操作。 JMenuItemJToolBar按钮共享相同Action并做同样的事情。这是您可以运行的代码。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;

public class ActionTest {

    public ActionTest() {
        ImageIcon openIcon = new ImageIcon(
                ActionTest.class.getResource("/resources/image/open.gif"));
        ImageIcon saveIcon = new ImageIcon(
                ActionTest.class.getResource("/resources/image/save.gif"));
        ImageIcon newIcon = new ImageIcon(
                ActionTest.class.getResource("/resources/image/new.gif"));

        Action openAction = new AbstractAction("Open", openIcon) {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Open File");
            }
        };
        Action saveAction = new AbstractAction("Save", saveIcon) {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Save File");
            }
        };
        Action newAction = new AbstractAction("New", newIcon) {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("New File");
            }
        };

        JMenuItem openMenuItem = new JMenuItem(openAction);
        JMenuItem saveMenuItem = new JMenuItem(saveAction);
        JMenuItem newMenuItem = new JMenuItem(newAction);

        JMenuBar menuBar = new JMenuBar();
        JMenu fileMenu = new JMenu("File");
        fileMenu.add(openMenuItem);
        fileMenu.add(saveMenuItem);
        fileMenu.add(newMenuItem);
        menuBar.add(fileMenu);

        JToolBar toolBar = new JToolBar();
        toolBar.add(Box.createHorizontalGlue());
        toolBar.setBorder(new LineBorder(Color.LIGHT_GRAY, 1));
        toolBar.add(newAction);
        toolBar.add(openAction);
        toolBar.add(saveAction);

        JFrame frame = new JFrame("Toolbar and Menu Test");
        frame.setJMenuBar(menuBar);
        frame.add(toolBar, BorderLayout.PAGE_START);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationByPlatform(true);
        frame.setVisible(true);

    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new ActionTest();
            }
        });
    }
}

正如上述教程中的引文所述,您可以做的不仅仅是将图像和操作命令添加到 Action。 .您可以使用它来设置助记符和加速器。这是一个自定义Action上课
  • Action 命令字符串
  • 一个图标
  • 工具提示的描述
  • 助记符
  • 和一个关键的加速器。
    private class MyAction extends AbstractAction {
    
        String name;
    
        public MyAction(String name, Icon icon) {
            super(name, icon);
            this.name = name;
        }
    
        public MyAction(String name, Icon icon, String desc,
                        Integer mnemonic, KeyStroke accelorator) {
            super(name, icon);
            putValue(Action.SHORT_DESCRIPTION, desc);
            putValue(Action.MNEMONIC_KEY, mnemonic);
            putValue(Action.ACCELERATOR_KEY, accelorator);
            this.name = name;
        }
    
        @Override
        public void actionPerformed(ActionEvent e) {
            switch (name) {
                case "Open":
                    System.out.println("Open");
                    break;
                case "New":
                    System.out.println("New");
                    break;
                case "Save":
                    System.out.println("Save");
                    break;
            }
        }
    }
    

  • 这是 Action 的实例化
    Action newAction = new MyAction("New", newIcon,
                "Creates a new file",
                new Integer(KeyEvent.VK_N),
                KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK));
    

    这是新的结果。您将看到 actionCommand在菜单中,以及关键的助记符和加速键、工具提示,您将看到 jtoolbar 按钮具有相同的特征。您还将在最终代码中看到,一旦创建了组件,就永远不会。您只需添加 ActionJToolBarJMenu让他们发挥他们的魔力。

    enter image description here
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    
    public class ActionInterfaceDemo extends JFrame {
    
        public ActionInterfaceDemo() {
            ImageIcon openIcon = new ImageIcon(ActionInterfaceDemo.class.getResource("/resources/image/open.gif"));
            ImageIcon saveIcon = new ImageIcon(ActionInterfaceDemo.class.getResource("/resources/image/save.gif"));
            ImageIcon newIcon = new ImageIcon(ActionInterfaceDemo.class.getResource("/resources/image/new.gif"));
    
            Action openAction = new MyAction("Open", openIcon,
                    "Opens a file",
                    new Integer(KeyEvent.VK_O),
                    KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK));
            Action saveAction = new MyAction("Save", saveIcon,
                    "Saves a file",
                    new Integer(KeyEvent.VK_S),
                    KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK));
            Action newAction = new MyAction("New", newIcon,
                    "Creates a new file",
                    new Integer(KeyEvent.VK_N),
                    KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK));
    
            JMenuBar menuBar = new JMenuBar();
            JMenu fileMenu = new JMenu("File");
            setJMenuBar(menuBar);
            menuBar.add(fileMenu);
    
            fileMenu.add(newAction);
            fileMenu.add(openAction);
            fileMenu.add(saveAction);
    
    
            JToolBar toolBar = new JToolBar("Alignment");
            toolBar.setBorder(BorderFactory.createLineBorder(Color.BLUE));
            toolBar.add(Box.createHorizontalGlue());
            toolBar.add(newAction);
            toolBar.add(openAction);
            toolBar.add(saveAction);
    
            add(toolBar, BorderLayout.PAGE_START);
            add(new JScrollPane(new TextArea(10, 40)), BorderLayout.CENTER);
    
            setDefaultCloseOperation(EXIT_ON_CLOSE);
            setTitle("Action Interface Demo");
            pack();
            setLocationByPlatform(true);
            setVisible(true);
        }
    
        private class MyAction extends AbstractAction {
    
            String name;
    
            public MyAction(String name, Icon icon) {
                super(name, icon);
                this.name = name;
            }
    
            public MyAction(String name, Icon icon, String desc,
                    Integer mnemonic, KeyStroke accelorator) {
                super(name, icon);
                putValue(Action.SHORT_DESCRIPTION, desc);
                putValue(Action.MNEMONIC_KEY, mnemonic);
                putValue(Action.ACCELERATOR_KEY, accelorator);
                this.name = name;
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                switch (name) {
                    case "Open":
                        System.out.println("Open");
                        break;
                    case "New":
                        System.out.println("New");
                        break;
                    case "Save":
                        System.out.println("Save");
                        break;
                }
            }
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable(){
                public void run() {
                    new ActionInterfaceDemo();
                }
            });
        }
    }
    

    更新

    更好的解释Action的关系和 命令模式

    Command Pattern 中所述

    The command pattern is a commonly used pattern which encapsulates a method call or action-like code into a single class. The advantages of being able to package a method (or methods) into a class become evident when you have multiple invokers for a single action (for example a button and a menu item may perform the same action).

    In Swing and Borland Delphi programming, an Action is a command object. In addition to the ability to perform the desired command, an Action may have an associated icon, keyboard shortcut, tooltip text, and so on. A toolbar button or menu item component may be completely initialized using only the Action object.



    所以基本上 Swing 使用 的概念。命令模式通过使用Actions
    至于OP的问题

    "Command Pattern seems to be ok but I can't get who's the receiver in all that."



    至于接收器 ,wiki 以文本编辑器为例,定义了 接收器像这样

    Receiver, Target Object: the object that is about to be copied, pasted, moved, etc. The receiver object owns the method that is called by the command's execute method. The receiver is typically also the target object. For example, if the receiver object is a cursor and the method is called moveUp, then one would expect that the cursor is the target of the moveUp action. On the other hand, if the code is defined by the command object itself, the target object will be a different object entirely.



    的主要更多组件命令模式 声明如下

    与命令模式相关的四个术语是 命令、接收者、调用者和客户端。

    Client, Source, Invoker: the button, toolbar button, or menu item clicked, the shortcut key pressed by the user.



    所以把它们放在一起:
  • MenuItem ( 客户端 ) 调用它
  • 调用它的操作( 命令对象 )actionPerformed反过来
  • 调用 上的方法接收器 .

  • wiki article用一个 Java 例子很好读

    关于swing - 使用 JComponents 时的命令模式有用性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21512639/

    相关文章:

    c# - 在选择设计模式方面需要帮助

    design-patterns - 应用程序设计——可修改的业务规则

    java - 通过 TextArea 中的 JButton 删除单行

    java - 单击 JButton 并打开 file.java

    java - 在拖动过程中渲染拖动的对象

    java - 在 TextField 中显示文本时出现循环问题

    java - 使用 MouseListener 开始或结束无限循环

    design-patterns - 我在哪里可以学习生物力学算法?

    java - JButton 对 actionListener 无响应

    java - 一次声明多个 swing 元素