Слушатели действий Java в другом классе не работают

Недавно я работал с JFrame, и у меня был простой вход в систему, регистрация и всплывающие окна, когда они были у меня в одном классе. Я хотел сделать его более красивым и не упаковывать все в один класс, поэтому я сделал класс для фреймов, кнопок, панелей, переменных и основного класса. Моя проблема в том, что сами фреймы работают нормально, загружаются и отображаются, но ActionListeners на кнопках вообще не работают. Ничего не меняется, когда я нажимаю кнопку и т. д. Я новичок в Java и очень новичок в JFrames и JButtons. Могу ли я что-нибудь сделать, чтобы сделать это проще или сделать мой код лучше? Код будет в каждом отдельном классе:

Прямо сейчас ничего не работает, даже «Это работает» в основном, прежде чем он должен вызывать LoginScreen(), не запускается. Я не уверен, что я изменил, чтобы это произошло?

Основной класс:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import static javax.swing.WindowConstants.DISPOSE_ON_CLOSE;

public class myGame {


   public static void main(String[] args){ 
      buttons myButtons = new buttons();
      frames myFrames = new frames();
      panels myPanels = new panels();
      variables myVariables = new variables();    

      System.out.println("This is running");  
      myFrames.loginScreenFrame();     
      System.out.println("This is also running");                                                                      }
}

класс кадров:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import static javax.swing.WindowConstants.DISPOSE_ON_CLOSE;

public class frames{


   public JFrame loginScreenFrame(){
      variables myVariables = new variables();
      panels myPanels = new panels();
      buttons myButtons = new buttons();


      myVariables.loginFrame.setSize(300,125);
      myVariables.loginFrame.setLocation(550,250);

      myVariables.loginFrame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);

      Container content = myVariables.loginFrame.getContentPane();
      content.add(myPanels.loginScreenPanel(), BorderLayout.CENTER);
      content.add(myPanels.loginScreenButtonsPanel(), BorderLayout.SOUTH);
      myButtons.registerButton.addActionListener(myButtons.registerListener);

      myVariables.loginFrame.setVisible(true);

      return myVariables.loginFrame;
   }

   public JFrame registerFrame(){

      variables myVariables = new variables();
      panels myPanels = new panels();

      myVariables.registerFrame.setSize(400,125);
      myVariables.registerFrame.setLocation(550,250);
      myVariables.registerFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      Container content = myVariables.registerFrame.getContentPane();

      content.add(myPanels.registerScreenPanel(), BorderLayout.CENTER);
      content.add(myPanels.registerScreenButtonsPanel(), BorderLayout.SOUTH);

      myVariables.registerFrame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);

      myVariables.registerFrame.setVisible(true); 

      return myVariables.registerFrame;
   }
}

Кнопки Класс:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import static javax.swing.WindowConstants.DISPOSE_ON_CLOSE;

public class buttons{
   JButton loginButton = new JButton("Login");
   JButton registerButton = new JButton("Register");
   JButton cancelButton = new JButton("Cancel");
   JButton checkUsernameButton = new JButton("Check Username");


   public void actionListeners(){

   variables myVariables = new variables();
   frames myFrames = new frames();
   panels myPanels = new panels();

      ActionListener cancelListener = new ActionListener(){
         public void actionPerformed(ActionEvent ae){
            frames myFrames = new frames();
            myFrames.registerFrame().dispose();
         }
      };

      ActionListener usernameListener = new ActionListener(){
         public void actionPerformed(ActionEvent ae){

         }
      };

      ActionListener passwordListener = new ActionListener(){
         public void actionPerformed(ActionEvent ae){

         }
      };

      ActionListener passwordCheckListener = new ActionListener(){
         public void actionPerformed(ActionEvent ae){

         }
      };

      ActionListener checkUsernameListener = new ActionListener(){
         public void actionPerformed(ActionEvent ae){
            variables myVariables = new variables();
            if (myVariables.usernameAndPassword.get(myVariables.username) == null){
               JPanel okButtonPanel = new JPanel();
               final JFrame invalidUsernameFrame = new JFrame();
               invalidUsernameFrame.setSize(400,75);
               invalidUsernameFrame.setLocation(550,250);
               JButton okButton = new JButton("Ok");
               Container invalidUsernameContainer =  invalidUsernameFrame.getContentPane();
               okButtonPanel.add(okButton);
               JLabel invalidUsernameLabel = new JLabel();
               invalidUsernameLabel.setText("                            Username is Available!");
               invalidUsernameContainer.add(invalidUsernameLabel);
               invalidUsernameContainer.add(okButtonPanel, BorderLayout.SOUTH);
               invalidUsernameFrame.setVisible(true);
               ActionListener okListener = new ActionListener(){
                  public void actionPerformed(ActionEvent ae){
                     myGame mainClass = new myGame();
                     invalidUsernameFrame.dispose();
                  }
               };
               okButton.addActionListener(okListener);
            }

            else{
               JPanel okButtonPanel = new JPanel();
               final JFrame invalidUsernameFrame = new JFrame();
               invalidUsernameFrame.setSize(400,75);
               invalidUsernameFrame.setLocation(550,250);
               JButton okButton = new JButton("Ok");
               Container invalidUsernameContainer = invalidUsernameFrame.getContentPane();
               okButtonPanel.add(okButton);
               JLabel invalidUsernameLabel = new JLabel();
               invalidUsernameLabel.setText("                         Username is not Available");
               invalidUsernameContainer.add(invalidUsernameLabel);
               invalidUsernameContainer.add(okButtonPanel, BorderLayout.SOUTH);
               invalidUsernameFrame.setVisible(true);
               ActionListener okListener = new ActionListener(){
                  public void actionPerformed(ActionEvent ae){
                     myGame mainClass = new myGame();
                     invalidUsernameFrame.dispose();
                  }
               };
               okButton.addActionListener(okListener);
            }
         }
      };
      ActionListener registerListener = new ActionListener(){
         public void actionPerformed(ActionEvent ae){
            frames myFrames = new frames();
            myFrames.registerFrame();
         }
      };
      cancelButton.addActionListener(cancelListener);
      myVariables.usernameField.addActionListener(usernameListener);
      myVariables.passwordField.addActionListener(passwordListener);
      myVariables.passwordCheckField.addActionListener(passwordCheckListener);
      registerButton.addActionListener(registerListener);

      checkUsernameButton.addActionListener(checkUsernameListener);
   }


}

Класс панелей:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;

public class panels{


      buttons myButtons = new buttons();
      frames myFrames = new frames();
      variables myVariables = new variables();

   public JPanel loginScreenPanel(){

      buttons myButtons = new buttons();
      frames myFrames = new frames();
      variables myVariables = new variables();

      JPanel panel = new JPanel();
      panel.setLayout(new GridLayout(2,2));    
      panel.add(new JLabel("Username:"));  
      panel.add(myVariables.usernameFrame);
      panel.add(new JLabel("Password:"));
      panel.add(myVariables.passwordFrame);

      return panel;
   }

   public JPanel loginScreenButtonsPanel(){


      JPanel buttons = new JPanel();
      buttons.add(myButtons.loginButton);
      buttons.add(myButtons.registerButton);
      buttons.add(myButtons.cancelButton);


      return buttons;
   }

   public JPanel registerScreenPanel(){



      JPanel panel = new JPanel();
      panel.setLayout(new GridLayout(3,2));    
      panel.add(new JLabel("Username:"));  
      panel.add(myVariables.usernameField);
      panel.add(new JLabel("Password:"));
      panel.add(myVariables.passwordField);
      panel.add(new JLabel("Re-Enter Password:"));
      panel.add(myVariables.passwordCheckField);


      return panel;
   }

   public JPanel registerScreenButtonsPanel(){


      JPanel buttons = new JPanel();
      buttons.add(myButtons.registerButton);
      buttons.add(myButtons.checkUsernameButton);
      buttons.add(myButtons.cancelButton);


      return buttons;
   }
}

New Code:

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class ExampleGame {

java.util.HashMap<String,char[]> usernamesAndPasswords = new         java.util.HashMap<String,char[]>();
public static void main(String[] args) {
    new ExampleGame();
}

public ExampleGame() {
    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
            }

            LoginPane pane = new LoginPane();
            storeInfo info = new storeInfo();
            int result = JOptionPane.showOptionDialog(null, pane, "Login", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null, new String[]{"Login", "Cancel"}, 0);
            if (result == 0) {

                User user = pane.getUser();
                // Perform the login...


                usernamesAndPasswords = info.storeInfo(user.name, user.password, usernamesAndPasswords);
                System.out.println("Name entered: " + user.name);
                System.out.print("Password entered: ");
                System.out.println(user.password);
                System.out.println(usernamesAndPasswords.get(user.name));

            }

        }
    });
}

public class LoginPane extends JPanel {

    private JTextField userName;
    private JPasswordField password;

    public LoginPane() {

        userName = new JTextField(10);
        password = new JPasswordField(10);

        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.insets = new Insets(4, 4, 4, 4);
        gbc.anchor = GridBagConstraints.EAST;
        add(new JLabel("Username:"), gbc);

        gbc.gridx++;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        add(userName, gbc);

        gbc.gridx = 0;
        gbc.gridy++;
        gbc.fill = GridBagConstraints.NONE;
        add(new JLabel("Password:"), gbc);

        gbc.gridx++;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        add(password, gbc);

    }

    public User getUser() {

        return new User(userName.getText(), password.getPassword());

    }

}

public class User {

    private String name;
    private char[] password;

    public User(String name, char[] password) {
        this.name = name;
        this.password = password;
        }

    }

    public class storeInfo{

      public java.util.HashMap storeInfo(String name, char[] password, java.util.HashMap <String, char[]> usernamesAndPasswords){

         usernamesAndPasswords.put(name, password);
         return usernamesAndPasswords;
      }

    }

}

Я добавил класс в ваш пример, чтобы заставить его хранить значения в HashMap, мне интересно, правильно ли я сделал это или есть ли другой лучший способ сделать это? Прямо сейчас он сохраняет значения в HashMap, но выдает предупреждение: Примечание: ExampleGame.java использует непроверенные или небезопасные операции. Примечание. Перекомпилируйте с параметром -Xlint:unchecked для получения подробной информации.

Я прочитал ссылки, которые вы дали, некоторые из них не имели смысла, но я думаю, что по большей части он имел смысл. непосредственно перед тем, как я начну пытаться заставить это работать, я хочу убедиться, что правильно сделал этот HashMap.

Также есть ли у меня ваше разрешение на использование кода, который вы сделали? Я мог бы сделать что-то подобное сам, но, вероятно, это было бы не так красиво и чисто.


person Molten    schedule 28.10.2013    source источник
comment
Вы продолжаете создавать экземпляры переменных, которые не имеют никакого отношения друг к другу. Например, в вашем слушателе действия close вы создаете еще один экземпляр frames, который не является экземпляром, который находится на экране.   -  person MadProgrammer    schedule 29.10.2013
comment
Вы имеете в виду прослушиватель отмены? где у меня есть: кадры myFrames = новые кадры ()? Здесь я просто звоню в тот, который я уже сделал. Я не совсем понимаю, что вы имеете в виду. Можете быть более конкретными?   -  person Molten    schedule 29.10.2013
comment
В вашем классе buttons в классе actionListeners вы создаете 3 новых экземпляра класса myFrames, ни один из которых не имеет никакого отношения к тому, что на самом деле находится на экране. Всего вы делаете это 6 раз...   -  person MadProgrammer    schedule 29.10.2013
comment
Так как же тогда мне называть свои кадры? Когда у меня их нет, он говорит, что buttons.java:97: ошибка: доступ к локальной переменной myFrames осуществляется из внутреннего класса; должен быть объявлен окончательным, за исключением того, что без myFrames.loginScreenFrame он говорит, что ошибка не может найти символ.   -  person Molten    schedule 29.10.2013
comment
Это будет во многом зависеть от вашего приложения, но я полагаю, что вы передадите ссылку на все объекты, которые вам нужны, либо через конструктор класса, либо через какие-то методы установки, и сохраните эти ссылки как переменные экземпляра, сделав их доступными для всего класса.   -  person MadProgrammer    schedule 29.10.2013
comment
Как бы я сделал это для этого экземпляра? Я новичок в JFrame и понятия не имею, как бы я это сделал с прослушивателями действий и т. Д.   -  person Molten    schedule 29.10.2013
comment
Я добавил еще немного информации в конец основного файла с измененным файлом кнопок, теперь, когда я запускаю его, ничего не появляется, и ни один из экранов не появляется.   -  person Molten    schedule 29.10.2013
comment
По сути, ваш код — это миска спагетти, и распутать его в текущей форме может быть невозможно.   -  person MadProgrammer    schedule 29.10.2013
comment
Как это исправить? Я пытался сделать так, чтобы это текло как можно лучше, но я думаю, что это не сработало. Если бы я собирался сделать это более читаемым и работающим, как бы я это сделал? Не совсем уверен, почему он не работает, поскольку он должен что-то делать до вызова loginScreen().   -  person Molten    schedule 29.10.2013
comment
Я буквально только что поменял местами две строки кода, и теперь я не получаю ошибку переполнения стека, однако теперь у меня все еще возникает первая проблема, заключающаяся в том, что мои кнопки ничего не делают, когда они нажаты.   -  person Molten    schedule 29.10.2013


Ответы (1)


По сути, у вас есть тесно связанная миска спагетти, которую в ее нынешнем состоянии, вероятно, невозможно распутать.

Основная проблема заключается в том, что вы создаете новые экземпляры frames, panels, buttons и variables повсюду. Это означает, что от одной части вашего приложения к другой все они используют свои собственные экземпляры этих классов, которые не связаны друг с другом.

Другая проблема заключается в том, что многие из этих частей приложения на самом деле не нуждаются в прямом доступе к объектам, к которым вы пытаетесь получить доступ.

Вместо этого начните с разбивки вашего приложения на полезные компоненты/элементы с определенными обязанностями.

Например, части пользовательского интерфейса должны собирать информацию, которая возвращается в систему для обработки. Уровень обработки не должен заботиться о том, откуда поступила эта информация, только о том, соответствует ли она его потребностям.

Например...

Следующее просто создает диалоговое окно входа в систему, которое возвращает объект User, представляющий имя пользователя и пароль, введенные пользователем (это очень простой пример, поэтому проверка несложная).

Диалог входа в систему не заботится о том, как происходит процесс входа в систему, он отвечает только за получение информации.

Точно так же никакая другая часть приложения не нуждается в доступе к полям в LoginPane, они должны заботиться только о результате.

введите здесь описание изображения

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class ExampleGame {

    public static void main(String[] args) {
        new ExampleGame();
    }

    public ExampleGame() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                LoginPane pane = new LoginPane();
                int result = JOptionPane.showOptionDialog(null, pane, "Login", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null, new String[]{"Login", "Cancel"}, 0);
                if (result == 0) {

                    User user = pane.getUser();
                    // Perform the login...

                }

            }
        });
    }

    public class LoginPane extends JPanel {

        private JTextField userName;
        private JPasswordField password;

        public LoginPane() {

            userName = new JTextField(10);
            password = new JPasswordField(10);

            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.insets = new Insets(4, 4, 4, 4);
            gbc.anchor = GridBagConstraints.EAST;
            add(new JLabel("Username:"), gbc);

            gbc.gridx++;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            add(userName, gbc);

            gbc.gridx = 0;
            gbc.gridy++;
            gbc.fill = GridBagConstraints.NONE;
            add(new JLabel("Password:"), gbc);

            gbc.gridx++;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            add(password, gbc);

        }

        public User getUser() {

            return new User(userName.getText(), password.getPassword());

        }

    }

    public class User {

        private String name;
        private char[] password;

        public User(String name, char[] password) {
            this.name = name;
            this.password = password;
        }

    }

}

Вы должны взглянуть на шаблон Model-View-Control

Программа для интерфейса

person MadProgrammer    schedule 29.10.2013
comment
Спасибо за ответ, я просто думаю, что того, что я знаю о JFrame и т. Д., Недостаточно, чтобы сделать это правильно, я не на 100% на сумке Grid, но я понимаю. Также для общедоступного пользователя getUser вы в основном возвращаете общедоступного пользователя, который находится в пользовательском общедоступном классе? Я действительно не знал, что ты можешь это сделать. Также не совсем уверен, что такое UIManager. Любые предложения о том, куда я должен пойти, чтобы изучить такие вещи? И что делает эта строка? int result = JOptionPane.showOptionDialog(null, pane, Login, JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null, new String[]{Login, Cancel}, 0); - person Molten; 29.10.2013
comment
JOptionPane.showOptionDialog создает диалог и диалоговые кнопки - person MadProgrammer; 29.10.2013
comment
Вы можете взглянуть на Создание графического интерфейса с помощью Swing, но я бы также посоветовал вы потратите некоторое время на изучение языка Java - person MadProgrammer; 29.10.2013
comment
Я бы проголосовал за ваш ответ, но я не могу без 15 репутации, я думаю. Что именно делает @Override? Я никогда не видел этого раньше. И EventQueue.invokeLater(new Runnable()? Не совсем уверен, что это такое. Также я заметил, что вы никогда не использовали JFrame, почему это? Не совсем уверен, что делает gbc.insets или gbc.anchor. Является ли gridx++, gridy++ gridx = 0, поэтому получается (pos1,pos2 (новая строка) pos 3, pos4) - person Molten; 29.10.2013
comment
Я знаю основы Java + немного больше, и у меня есть опыт объектно-ориентированного программирования. Я просто совсем не знаком с графическими интерфейсами или синтаксисом Java для некоторых вещей. Спасибо за ссылки, хотя я посмотрю их. У меня есть две книги по Java, и в одной из них я делал некоторые вещи с графическим интерфейсом, из которых не очень хорошо обращались с actionListeners, кнопками и т. д. - person Molten; 29.10.2013
comment
@Override — это аннотация, используемая компилятором, чтобы гарантировать, что я действительно переопределил метод, который, как я думал, был. EventQueue.invokeLater гарантирует, что код в методе run указанного Runnable будет выполняться в контексте Поток отправки событий. Я не использую JFrame, так как полагаюсь на JOptionPane сделать мне диалог - person MadProgrammer; 29.10.2013
comment
Основная причина использования JOptionPane заключается в том, что выполнение программы будет остановлено до тех пор, пока диалоговое окно не будет закрыто. gbc являются GridBagConstraints, которые изменяют способ GridBagLayout расположения своих компонентов, и да, gridx и gridy определяют ячейки, в которые будут помещены компоненты - person MadProgrammer; 29.10.2013
comment
Еще раз спасибо за все ответы, я немного прочитал то, что вы связали, и я думаю, что теперь это имеет больше смысла, но все же не до конца. Я добавил HashMap и метод, который сохраняется в HashMap так же, как я думаю, что вы сделали это для остальных методов. Не могли бы вы просмотреть это для меня и дать мне знать? Новый код является последним набором в исходном вопросе. Также у меня есть ваше разрешение на использование кода, который вы разместили, или вы хотите, чтобы я сделал свой собственный? Я мог бы, но это было бы не так красиво и не так чисто. Кроме того, я хотел бы перенести это в чат для обсуждения, но у меня только 1 репутация, поэтому я не могу, - person Molten; 30.10.2013
comment
@user2045177 user2045177 Вы можете использовать мой код сколько угодно;) - person MadProgrammer; 30.10.2013
comment
Отлично, спасибо =), теперь мне просто интересно, в порядке ли моя реализация моего HashMap, и могу ли я игнорировать небольшое предупреждающее сообщение, которое я получаю. - person Molten; 30.10.2013
comment
закрытый char[] пароль; почему у вас это с массивом символов? Не проще ли было бы просто использовать строку? - person Molten; 30.10.2013
comment
@Molten String интернирован на весь срок службы JVM, а это означает, что кто-то может проверить память и найти пароль. См. это и это и здесь подробнее - person MadProgrammer; 30.10.2013
comment
Использование HashMap не обязательно является плохой идеей, проблема заключается в ограничении доступа к нему. Как вы мешаете другим частям вашей программы изменить его? - person MadProgrammer; 30.10.2013
comment
Я действительно не против того, чтобы кто-то нашел пароль на этом этапе, это будет очень простая вещь, в которой, вероятно, в любом случае будут читы, единственная причина, по которой у меня есть логин, по сути, для сохранений. И что вы имеете в виду под своим вторым вопросом? Если это то, что я думаю, вы имеете в виду, разве это не будет просто личным? Я просто хочу иметь возможность добавлять пользователей и пароли в HashMap, добавляя их, а затем отправляя их в файл. При запуске программы загрузите файл в HashMap. И во время входа в систему проверьте значения HashMap. Так что единственный раз, когда мне нужно изменить его, это во время - person Molten; 30.10.2013
comment
Читать из файлов, и когда я получаю новый ввод, если я устанавливаю его как частный, разве они не должны быть в одном классе? Или есть другой способ сделать это? - person Molten; 30.10.2013
comment
Тогда я предлагаю вам взглянуть на Properties или Preferences API, который сделает эту работу за вас. Это всего лишь мое мнение, но выставлять значения таким образом и удалять оттуда управляющий контекст — это, как правило, плохой дизайн. - person MadProgrammer; 30.10.2013