所以,我正在使用Swing库开发一个程序,我显然有按钮和菜单项。其中一些应该做同样的事情,我认为使用命令模式应该是这样做的方式,例如,我有一个“保存”按钮和一个“保存”菜单项,他们必须实现相同的保存算法。 命令模式似乎没问题,但我无法确定谁是接收器。是不是一个命令应该在一个实现某种“接收器接口”的对象上工作,这样你就可以在不同的接收器上使用不同的命令来耦合它们?看起来我的模式实现中没有“接收器”。 我的另一个疑问是命令是否应该作为单例实现,因为你可以从同一个项目的不同部分调用它的函数,并且只需要实例化一次并使其静态可调用就可以了吗?
谢谢。
答案 0 :(得分:4)
“我显然有按钮和菜单项。其中一些应该做同样的事情,”
正如@nIcEcOw所说,这就是Action
的用途。 This Answer正好显示了这一点。
如How to use Actions中所述:
Action可用于将功能和状态与组件分开。例如,如果您有两个或多个执行相同功能的组件,请考虑使用Action对象来实现该功能。 Action对象是一个动作侦听器,它不仅提供动作事件处理,还集中处理动作事件触发组件的状态,例如工具栏按钮,菜单项,公共按钮和文本字段。操作可以处理的状态包括文本,图标,助记符,已启用和已选择状态。
An只有三个Actions
。 Ont打开,保存和新建。每个Action
都有一个ActionCommand
和icon
,以及要执行的操作。 JMenuItem
和JToolBar
按钮共享相同的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
类,需要
和一个关键的加速器。
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按钮共享相同的特征。您还将在最终代码中看到,一旦创建了组件,您就不会再这样做了。您所做的只是将Action
添加到JToolBar
和JMenu
,让他们发挥他们的魔力。
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
和命令模式
命令模式是一种常用模式,它将方法调用或类似动作的代码封装到单个类中。当您为单个操作设置多个调用者时(例如,按钮和菜单项可以执行相同的操作),能够将一个或多个方法打包到类中的优势变得明显。
在Swing和Borland Delphi编程中,
Action
是一个命令对象。除了能够执行所需命令外,Action
还可以具有关联的图标,键盘快捷键,工具提示文本等。可以仅使用Action
对象完全初始化工具栏按钮或菜单项组件。
所以基本上Swing通过使用Actions
关于OP的问题
“命令模式似乎没问题,但我无法确定接收者是谁。”
对于接收器,维基使用文本编辑器作为示例,并将接收器定义为
接收器,目标对象:即将复制,粘贴,移动等对象。接收器对象拥有由命令的execute方法调用的方法。接收器通常也是目标对象。例如,如果接收者对象是游标并且该方法被称为moveUp,则可以预期游标是moveUp动作的目标。另一方面,如果代码由命令对象本身定义,则目标对象将完全是另一个对象。
命令模式的主要组成部分如下所述
与命令模式始终相关的四个术语是命令,接收者,调用者和客户端。
客户端,来源,推荐人:点击按钮,工具栏按钮或菜单项,用户按下快捷键。
所以要把它们放在一起:
actionPerformed
使用Java示例
可以很好地阅读wiki article答案 1 :(得分:2)
当两个或多个组件的意思完全相同时,应该查看Action,这会减少重复的代码。
进一步帮助的小例子:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ActionExample {
private JFrame frame;
private JButton button;
private JMenuItem exitItem;
private Action commonActions;
private class CommonActions extends AbstractAction {
public CommonActions(String title, String desc) {
super(title);
putValue(SHORT_DESCRIPTION, desc);
}
@Override
public void actionPerformed(ActionEvent ae) {
JOptionPane.showMessageDialog(frame,
"Closing Frame", "Information", JOptionPane.INFORMATION_MESSAGE);
frame.dispose();
}
};
private void displayGUI() {
frame = new JFrame("Action Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
commonActions = new CommonActions("Exit", "To Exit the Application");
JPanel contentPane = new JPanel();
button = new JButton();
button.setAction(commonActions);
contentPane.add(button);
frame.setJMenuBar(getMenuBar());
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JMenuBar getMenuBar() {
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
exitItem = new JMenuItem(commonActions);
fileMenu.add(exitItem);
menuBar.add(fileMenu);
return menuBar;
}
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
new ActionExample().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ActionExample {
private JFrame frame;
private JButton button;
private JMenuItem exitItem;
private void displayGUI() {
frame = new JFrame("Action Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
CommonActions.setValues(frame);
JPanel contentPane = new JPanel();
button = new JButton();
button.setAction(CommonActions.getInstance());
contentPane.add(button);
frame.setJMenuBar(getMenuBar());
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JMenuBar getMenuBar() {
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
exitItem = new JMenuItem(CommonActions.getInstance());
fileMenu.add(exitItem);
menuBar.add(fileMenu);
return menuBar;
}
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
new ActionExample().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}
class CommonActions extends AbstractAction {
private static CommonActions commonActions = null;
private static JFrame frame = null;
static {
try {
commonActions = new CommonActions("Exit", "To Exit the Application");
} catch (Exception e) {
throw new RuntimeException("BINGO, an error");
}
}
private CommonActions(String title, String desc) {
super(title);
putValue(SHORT_DESCRIPTION, desc);
}
public static CommonActions getInstance() {
return commonActions;
}
public static void setValues(JFrame f) {
frame = f;
}
@Override
public void actionPerformed(ActionEvent ae) {
JOptionPane.showMessageDialog(frame,
"Closing Frame", "Information", JOptionPane.INFORMATION_MESSAGE);
frame.dispose();
}
}