Java:如何从AbstractAction对象引用GUI组件?

通常需要根据另一个GUI对象的状态更改其他GUI对象的行为。 例如,当按下按钮时,标签应更改其名称。 但是,当我使用像JButton myButton = new JButton(myButtonAction);这样的AbstractAction对象时JButton myButton = new JButton(myButtonAction); 我需要对inheritance自AbstractAction的对象中的GUI对象的引用。 我应该只是在GUI中创建AbstractAction对象,然后将所有必要的GUI引用传递给AbstractAction对象,还是可以认为是坏样式?

为了使它更具体:

 // AbstractAction public class MyAction extends AbstractAction { public MyAction(String name, String description, Integer mnemonic, JLabel) { super(name); putValue(SHORT_DESCRIPTION, description); putValue(MNEMONIC_KEY, mnemonic); } public void actionPerformed(ActionEvent e) { // do something } } } public class GUI{ public Action myAction = null; public GUI(){ JLabel label = new JLabel("text"); //This is not a good idea: myAction = new MyAction("some text" , desc, new Integer(KeyEvent.VK_Q), label); JButton myButton = new JButton(myAction); } } 

你想尽可能地放松耦合,而不是像你的问题所暗示的那样收紧耦合,为了做到这一点,我认为你应该进一步抽象,通过将部分进一步分成一个完整的MVC程序。 然后,侦听器(Action)可以更改模型,作为GUI的视图可以监听模型的更改并进行相应的响应。

例如:

 import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.*; import javax.swing.event.SwingPropertyChangeSupport; public class MvcEg { private static void createAndShowGui() { View view = new MvcEgView(); Model model = new MvcEgModel(); new MvcEgControl(model, view); JFrame frame = new JFrame("MvcEg"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(view.getMainPanel()); frame.pack(); frame.setLocationByPlatform(true); frame.setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGui(); } }); } } interface View { void setMyButtonAction(Action action); Component getMainPanel(); void setStatusLabelText(String text); } @SuppressWarnings("serial") class MvcEgView implements View { private static final int PREF_W = 500; private static final int PREF_H = 400; private static final String STATUS_TEXT = "Status: "; private JPanel mainPanel = new JPanel() { @Override public Dimension getPreferredSize() { return new Dimension(PREF_W, PREF_H); } }; private JLabel statusLabel = new JLabel(STATUS_TEXT, SwingConstants.CENTER); private JButton myButton = new JButton(); public MvcEgView() { JPanel btnPanel = new JPanel(new GridBagLayout()); btnPanel.add(myButton); mainPanel.setLayout(new BorderLayout()); mainPanel.add(btnPanel, BorderLayout.CENTER); mainPanel.add(statusLabel, BorderLayout.SOUTH); } @Override public void setMyButtonAction(Action action) { myButton.setAction(action); } @Override public void setStatusLabelText(String text) { statusLabel.setText(STATUS_TEXT + text); } @Override public Component getMainPanel() { return mainPanel; } } interface Model { public static final String MOD_FIVE_STATUS = "mod five status"; void incrementStatus(); ModFiveStatus getModFiveStatus(); void removePropertyChangeListener(PropertyChangeListener listener); void addPropertyChangeListener(PropertyChangeListener listener); void setModFiveStatus(ModFiveStatus modFiveStatus); } class MvcEgModel implements Model { private ModFiveStatus modFiveStatus = ModFiveStatus.ZERO; private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport( this); @Override public void incrementStatus() { int value = modFiveStatus.getValue(); value++; value %= ModFiveStatus.values().length; setModFiveStatus(ModFiveStatus.getValuesStatus(value)); } @Override public void setModFiveStatus(ModFiveStatus modFiveStatus) { ModFiveStatus oldValue = this.modFiveStatus; ModFiveStatus newValue = modFiveStatus; this.modFiveStatus = modFiveStatus; pcSupport.firePropertyChange(MOD_FIVE_STATUS, oldValue, newValue); } @Override public ModFiveStatus getModFiveStatus() { return modFiveStatus; } @Override public void addPropertyChangeListener(PropertyChangeListener listener) { pcSupport.addPropertyChangeListener(listener); } @Override public void removePropertyChangeListener(PropertyChangeListener listener) { pcSupport.removePropertyChangeListener(listener); } } enum ModFiveStatus { ZERO(0, "Zero"), ONE(1, "One"), TWO(2, "Two"), THREE(3, "Three"), FOUR(4, "Four"); private int value; private String text; private ModFiveStatus(int value, String text) { this.value = value; this.text = text; } public int getValue() { return value; } public String getText() { return text; } public static ModFiveStatus getValuesStatus(int value) { if (value < 0 || value >= values().length) { throw new ArrayIndexOutOfBoundsException(value); } for (ModFiveStatus modFiveStatus : ModFiveStatus.values()) { if (modFiveStatus.getValue() == value) { return modFiveStatus; } } // default that should never happen return null; } } @SuppressWarnings("serial") class MvcEgControl { private Model model; private View view; public MvcEgControl(final Model model, final View view) { this.model = model; this.view = view; view.setMyButtonAction(new MyButtonAction("My Button", KeyEvent.VK_B)); view.setStatusLabelText(model.getModFiveStatus().getText()); System.out.println("model's status: " + model.getModFiveStatus()); System.out.println("model's status text: " + model.getModFiveStatus().getText()); model.addPropertyChangeListener(new ModelListener()); } private class MyButtonAction extends AbstractAction { public MyButtonAction(String text, int mnemonic) { super(text); putValue(MNEMONIC_KEY, mnemonic); } @Override public void actionPerformed(ActionEvent e) { model.incrementStatus(); System.out.println("button pressed"); } } private class ModelListener implements PropertyChangeListener { @Override public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals(Model.MOD_FIVE_STATUS)) { String status = model.getModFiveStatus().getText(); view.setStatusLabelText(status); System.out.println("status is: " + status); } } } } 

我心中的关键是模型对视图一无所知,而视图对模型知之甚少(此处什么都不知道)。

放大@ Hovercraft的建议方法,让您的按钮和标签访问一个通用模型。 按钮的Action更新模型,模型通知监听标签,可能使用此处概述的PropertyChangeListener 。 在javax.swing.text.EditorKit的具体实现中可以看到更详细的示例,它在swing文本组件使用的公共Document模型上运行。