ActionListeners JMenuItems — кросс-классы

Я делаю очень плохую попытку использовать ActionListeners здесь.

Я пытаюсь использовать ActionListeners для запуска кода из другого класса (AddForm.java) после нажатия JMenuItem (в MainMenu.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();
                }    
            }        
    );
    */
}
}

ДобавитьФорму.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 в меню.

После нажатия этих «кнопок меню» «Добавить», «Удалить» и «Поиск» откроется соответствующая форма, которая позволит пользователю вводить данные.

Когда я запускаю свой код с прослушивателями действий и без них, он работает как обычно, но меню вообще не связаны. Как будто в них нет смысла?


person user3223921    schedule 01.12.2014    source источник
comment
Я настоятельно рекомендую вам изменить название на что-то более значимое.   -  person Zéychin    schedule 02.12.2014


Ответы (1)


Некоторые основные вопросы:

  • Если один класс должен воздействовать на другой, ему потребуется ссылка на этот другой класс, чтобы он мог использовать все свои методы.
  • Таким образом, если вашему классу MainMenu необходимо изменить состояние класса AddForm, то один из способов сделать это — для MainMenu потребуется поле AddForm, и, что более важно, это поле должно ссылаться на текущий активный объект AddForm.
  • Еще лучшей структурой программы является использование структуры M-V-C или Model-View-Control, в которой два представления связаны общей моделью, но это может быть немного сложно для вашей простой программы. Тем не менее, если вы хотите следовать передовым методам, это будет путь. В этом примере показана более простая идея View-Control, которая также может работать.
  • Обычно для графического интерфейса пользователя не рекомендуется иметь несколько окон верхнего уровня, что для Java означает несколько JFrames. Лучше иметь одно главное окно и другие виды, которые можно менять местами в нем, если это необходимо, с помощью CardLayout или которые можно отображать в диалоговых окнах, если это необходимо. Пожалуйста, ознакомьтесь с Использование нескольких JFrames, хорошая/плохая практика?.

Для простого примера без MVC у вас может быть один класс, вызывающий методы второго. Предположим, что JPanel содержит JList с именем View1, у которого есть общедоступный метод, 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. Затем этот второй класс может вызвать метод addItem(...) View1:

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();
      }
   }
}
person Hovercraft Full Of Eels    schedule 01.12.2014
comment
Кроме того, ActionListener обрабатывает (Swing) ActionEvent, но вам, вероятно, нужно что-то делать для всего остального. Не добавляйте ссылки на класс только для того, чтобы иметь удобный доступ к его методам. Вместо этого вы можете использовать другие механизмы (шаблоны проектирования), чтобы помочь вызвать метод в других классах, когда происходит событие GUI. - person hfontanez; 02.12.2014
comment
@hfontanez: Я согласен, лучше пойти в M-V-C, если это возможно. - person Hovercraft Full Of Eels; 02.12.2014
comment
Я не уверен, что вы имеете в виду с первым пунктом. Как вы понимаете ссылку? Это единственный способ, которым я планирую это сделать, так как я должен закончить его к завтрашнему дню, и изменить его сейчас было бы кошмаром?! А также что такое MVC? хаха. Все еще довольно новичок в Java. - person user3223921; 02.12.2014