【问题标题】:ActionListeners JMenuItems - Cross classesActionListeners JMenuItems - 跨类
【发布时间】:2014-12-01 22:46:09
【问题描述】:

我在这里对 ActionListeners 的尝试非常糟糕。

一旦单击 JMenuItem(在 MainMenu.java 中),我正在尝试使用 ActionListeners 从另一个类 (AddForm.java) 中运行代码。

首先,代码如下:MainMenu.java

package carparksystem;

import javax.swing.JFrame;
import javax.swing.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.*;
import java.awt.event.*;

public class MainMenu extends JFrame
{
public MainMenu()
{
    JMenuBar mainMenu = new JMenuBar();
    JMenu main = new JMenu("Menu");

    mainMenu.add(main);

    JMenuItem addCar = new JMenuItem("Add Car");
    addCar.setActionCommand("Add");
    main.add(addCar);
    //addCar.addActionListener();

    JMenuItem removeCar = new JMenuItem("Remove Car");
    removeCar.setActionCommand("Remove");
    main.add(removeCar);

    JMenuItem searchCars = new JMenuItem("Search Cars");
    searchCars.setActionCommand("Search");
    main.add(searchCars);

    setJMenuBar(mainMenu);

    /*
    //Add action listener for the Add Car button
    addCar.addActionListener
    (
        new ActionListener()
            {
                @Override
                public void actionPerformed(ActionEvent e) 
                {
                    MainMenu.windowClosed();
                }    
            }        
    );
    */
}
}

AddForm.java:

package carparksystem;

import javax.swing.ButtonGroup;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
import javax.swing.JFrame;

public class AddForm extends JFrame
{
public AddForm()
{        
    JLabel regNumLabel = new JLabel("Registration Number:");
    JLabel highValLabel = new JLabel("High Value?");
    JLabel largeLabel = new JLabel("Large Vehicle?");

    JRadioButton btnYesHighVal = new JRadioButton("Yes", false);
    JRadioButton btnNoHighVal = new JRadioButton("No", true);
    JRadioButton btnYesLarge = new JRadioButton("Yes", false);
    JRadioButton btnNoLarge = new JRadioButton("No", true);

    ButtonGroup highVal = new ButtonGroup();        //allows just one radio button from the group to be selected
    highVal.add(btnYesHighVal);
    highVal.add(btnNoHighVal);

    ButtonGroup largeCar = new ButtonGroup();       //allows just one radio button from the group to be selected
    largeCar.add(btnYesLarge);
    largeCar.add(btnNoLarge);

    JTextField regNumField = new JTextField();

    JButton addCar = new JButton("   Add  ");
    JButton addCancel = new JButton("Cancel");

    GroupLayout addLayout = new GroupLayout(getContentPane());      //chosen to display components in group layout
    getContentPane().setLayout(addLayout);
    addLayout.setAutoCreateGaps(true);
    addLayout.setAutoCreateContainerGaps(true);

    addLayout.setHorizontalGroup(addLayout.createSequentialGroup()
        .addGroup(addLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addComponent(regNumLabel)
            .addComponent(highValLabel)
            .addComponent(largeLabel))
        .addGroup(addLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addComponent(regNumField)
            .addGroup(addLayout.createSequentialGroup()
                .addGroup(addLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
                .addComponent(btnYesHighVal)
                .addComponent(btnYesLarge))
            .addGroup(addLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
                .addComponent(btnNoHighVal)
                .addComponent(btnNoLarge))))
        .addGroup(addLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addComponent(addCar)
            .addComponent(addCancel))
    );

    addLayout.setVerticalGroup(addLayout.createSequentialGroup()
        .addGroup(addLayout.createParallelGroup(GroupLayout.Alignment.BASELINE)
            .addComponent(regNumLabel)
            .addComponent(regNumField)
            .addComponent(addCar))
        .addGroup(addLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGroup(addLayout.createSequentialGroup()
                .addGroup(addLayout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                    .addComponent(highValLabel)
                    .addComponent(btnYesHighVal)
                    .addComponent(btnNoHighVal))
                .addGroup(addLayout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                    .addComponent(largeLabel)    
                    .addComponent(btnYesLarge)
                    .addComponent(btnNoLarge)))
                .addComponent(addCancel))
        );

    setSize(375, 150);
    setTitle("Add Car");
    setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
}

在主框架上,我绘制了一系列首先出现在框架上的形状。并且在此上方会有一个 JMenu,菜单中有 JMenuItems Add、Remove 和 Search Cars。

点击这些“添加删除”和“搜索”“菜单按钮”后,它们将打开相应的表单,允许用户输入数据。

当我在有和没有动作监听器的情况下运行我的代码时,它正常运行,但菜单根本不链接。就好像它们没有意义一样?

【问题讨论】:

  • 我强烈建议您将标题修改为更有意义的内容。

标签: java swing actionlistener jmenu jmenuitem


【解决方案1】:

一些基本问题:

  • 如果一个类要对另一个类产生影响,则需要对该类的引用,以便它可以使用其所有方法。
  • 因此,如果您的 MainMenu 类需要更改 AddForm 类的状态,那么发生这种情况的一种方法是 MainMenu 需要一个 AddForm 字段,更重要的是,该字段必须引用当前活动的 AddForm 对象。李>
  • 更好的程序结构是使用 M-V-C 或模型-视图-控制结构,其中两个视图通过共享模型连接,但这对于您的简单程序可能有点高级。不过,如果您想遵循最佳实践,这将是您的最佳选择。 This example 展示了一个更简单的 View-Control 想法,它也可以工作。
  • GUI 拥有多个顶级窗口通常是个坏主意,这对于 Java 意味着多个 JFrame。最好有一个主窗口和其他视图,如果需要,可以使用 CardLayout 在其中交换,或者如果需要,可以在对话框窗口中显示。请查看The Use of Multiple JFrames, Good/Bad Practice?

对于一个简单的非 MVC 示例,您可以有一个类调用第二个类的方法。假设一个 JPanel 包含一个名为 View1 的 JList,该 JList 具有一个公共方法 addItem(String item),它将项目添加到 JList 的模型中:

public class View1 extends JPanel {
   private static final String PROTOTYPE = String.format("%50s", " ");
   private DefaultListModel<String> listModel = new DefaultListModel<>();
   private JList<String> list = new JList<>(listModel);

   public View1() {
      list.setPrototypeCellValue(PROTOTYPE);
      list.setVisibleRowCount(8);
      JScrollPane scrollPane = new JScrollPane(list);
      scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
      add(scrollPane);
   }

   public void addItem(String item) {
      listModel.addElement(item);
   }
}

考虑第二个 JPanel 类 View2,它包含一个 JTextArea 和一个 JButton 以及一个 View1 的实例。然后第二个类可以调用 View1 的addItem(...) 方法:

public class View2 extends JPanel {
   private View1 view1;
   private JTextField textField = new JTextField(10);

   public View2(View1 view1) {
      Action addItemAction = new AddItemAction();
      this.view1 = view1;
      add(textField);
      add(new JButton(addItemAction));
      textField.setAction(addItemAction);
   }

   private class AddItemAction extends AbstractAction {
      public AddItemAction() {
         super("Add Item");
         putValue(MNEMONIC_KEY, KeyEvent.VK_A);
      }

      @Override
      public void actionPerformed(ActionEvent e) {
         view1.addItem(textField.getText()); // *** calls view1's method here
         textField.selectAll();
      }
   }
}

然后您可以创建两个类,将 View1 传递给 View2 的构造函数

  View1 view1 = new View1();
  View2 view2 = new View2(view1);

然后将一个放入一个JFrame另一个放入一个非模态的JDialog并显示。例如:

import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.*;

public class SimpleGuis {
   private static void createAndShowGui() {
      View1 view1 = new View1();
      View2 view2 = new View2(view1);

      JFrame frame = new JFrame("SimpleGuis");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(view1);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);

      JDialog dialog = new JDialog(frame, "View2", ModalityType.MODELESS);
      dialog.add(view2);
      dialog.pack();
      dialog.setLocationByPlatform(true);
      dialog.setVisible(true);
   }

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

class View1 extends JPanel {
   private static final String PROTOTYPE = String.format("%50s", " ");
   private DefaultListModel<String> listModel = new DefaultListModel<>();
   private JList<String> list = new JList<>(listModel);

   public View1() {
      list.setPrototypeCellValue(PROTOTYPE);
      list.setVisibleRowCount(8);
      JScrollPane scrollPane = new JScrollPane(list);
      scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
      add(scrollPane);
   }

   public void addItem(String item) {
      listModel.addElement(item);
   }
}

class View2 extends JPanel {
   private View1 view1;
   private JTextField textField = new JTextField(10);

   public View2(View1 view1) {
      Action addItemAction = new AddItemAction();
      this.view1 = view1;
      add(textField);
      add(new JButton(addItemAction));
      textField.setAction(addItemAction);
   }

   private class AddItemAction extends AbstractAction {
      public AddItemAction() {
         super("Add Item");
         putValue(MNEMONIC_KEY, KeyEvent.VK_A);
      }

      @Override
      public void actionPerformed(ActionEvent e) {
         view1.addItem(textField.getText());
         textField.selectAll();
      }
   }
}

【讨论】:

  • 另外,ActionListener 处理(Swing)ActionEvent,但您可能需要做其他事情。不要添加对类的引用,以便您可以方便地访问其方法。相反,当 GUI 事件发生时,您可以使用其他机制(设计模式)来帮助调用其他类的方法。
  • @hfontanez:我同意,如果可能的话最好去 M-V-C。
  • 我不确定你对第一点的意思。你是什​​么意思参考?这是我计划这样做的唯一方法,因为我必须在明天完成它,现在改变它会是一场噩梦?!还有什么是MVC?哈哈。对 Java 来说还是很陌生。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-23
  • 1970-01-01
  • 2015-08-23
  • 2015-02-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多