如何从监听器的代码中分离GUI代码?

时间:2014-06-26 17:56:37

标签: java user-interface actionlistener

我必须创建一个带有图形用户界面的程序,按钮执行某些操作,包括登录和注册。 我想使用MVC模式来创建这个项目,使代码保持“有序”和干净。

所以我创建了3个包:Model,View和Controller。

Model 中,有几个定义对象的类(例如:User,Message等)。 在 View 中,有一些类包含NetBeans for GUI创建的代码。 我知道使用NetBeans GUI Builder可以创建监听器来关联各种按钮。 但是这个代码监听器是在与View相同的文件中创建的,而我想将视图中的文件与控制器中的文件分开。

所以我会有类似的东西:

  • 模型:定义对象的文件
  • 查看:定义GUI的文件
  • 控制器:文件“管理”用户输入并处理它们的GUI

但是现在在视图的文件中有GUI和控制器(监听器)。

例如,这是LoginView文件:

public class Login extends javax.swing.JFrame {


   /** Creates new form Login */
   public Login() {
      initComponents();
   }

   /** This method is called from within the constructor to
    * initialize the form.
    * WARNING: Do NOT modify this code. The content of this method is
    * always regenerated by the Form Editor.
    */
   @SuppressWarnings("unchecked")
   // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
   private void initComponents() {

      jPanel1 = new javax.swing.JPanel();
      usernameLabel = new javax.swing.JLabel();
      passwordLabel = new javax.swing.JLabel();
      usernameField = new javax.swing.JTextField();
      regButton = new javax.swing.JButton();
      logButton = new javax.swing.JButton();
      titleLabel = new javax.swing.JLabel();
      passwordField = new javax.swing.JPasswordField();

      javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
      jPanel1.setLayout(jPanel1Layout);
      jPanel1Layout.setHorizontalGroup(
         jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
         .addGap(0, 0, Short.MAX_VALUE)
      );
      jPanel1Layout.setVerticalGroup(
         jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
         .addGap(0, 0, Short.MAX_VALUE)
      );

      setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
      setTitle("Login");
      setLocationByPlatform(true);
      setName("login"); // NOI18N
      setResizable(false);

      usernameLabel.setText("Username:");

      passwordLabel.setText("Password:");
      passwordLabel.setOpaque(true);

      usernameField.setToolTipText("");

      regButton.setText("Registrati");
      regButton.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            regButtonActionPerformed(evt);
         }
      });

      logButton.setText("Accedi");
      logButton.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            logButtonActionPerformed(evt);
         }
      });

      titleLabel.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N
      titleLabel.setText("Inserisci i tuoi dati:");

      javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
      getContentPane().setLayout(layout);
      layout.setHorizontalGroup(
         layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
         .addGroup(layout.createSequentialGroup()
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
               .addGroup(layout.createSequentialGroup()
                  .addGap(26, 26, 26)
                  .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                     .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addComponent(usernameLabel)
                        .addComponent(passwordLabel, javax.swing.GroupLayout.Alignment.TRAILING))
                     .addGroup(layout.createSequentialGroup()
                        .addComponent(regButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 24, Short.MAX_VALUE)
                        .addComponent(logButton))
                     .addComponent(passwordField)
                     .addComponent(usernameField)))
               .addGroup(layout.createSequentialGroup()
                  .addGap(54, 54, 54)
                  .addComponent(titleLabel)))
            .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
      );
      layout.setVerticalGroup(
         layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
         .addGroup(layout.createSequentialGroup()
            .addContainerGap()
            .addComponent(titleLabel)
            .addGap(18, 18, 18)
            .addComponent(usernameLabel)
            .addGap(3, 3, 3)
            .addComponent(usernameField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(passwordLabel)
            .addGap(3, 3, 3)
            .addComponent(passwordField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addGap(18, 18, 18)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
               .addComponent(logButton)
               .addComponent(regButton))
            .addContainerGap(22, Short.MAX_VALUE))
      );

      usernameLabel.getAccessibleContext().setAccessibleName("usernameLabel");
      usernameLabel.getAccessibleContext().setAccessibleDescription("");
      passwordLabel.getAccessibleContext().setAccessibleName("passwordLabel");

      setSize(new java.awt.Dimension(218, 227));
      setLocationRelativeTo(null);
   }// </editor-fold>                        

   private void regButtonActionPerformed(java.awt.event.ActionEvent evt) {                                          
      // TODO add your handling code here:
      //**Code for signup (create a new record, insert in database, etc.)**
   }                                         

    private void logButtonActionPerformed(java.awt.event.ActionEvent evt) {                                          
        // TODO add your handling code here:
        //**Code for login (look in the database, etc.)**
    }                                         


   /**
    * @param args the command line arguments
    */
   public static void start() {
      /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
       * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
       */
      try {
         for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
               javax.swing.UIManager.setLookAndFeel(info.getClassName());
               break;
            }
         }
      } catch (ClassNotFoundException ex) {
         java.util.logging.Logger.getLogger(Login.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
      } catch (InstantiationException ex) {
         java.util.logging.Logger.getLogger(Login.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
      } catch (IllegalAccessException ex) {
         java.util.logging.Logger.getLogger(Login.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
      } catch (javax.swing.UnsupportedLookAndFeelException ex) {
         java.util.logging.Logger.getLogger(Login.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
      }
        //</editor-fold>

      /* Create and display the form */
      java.awt.EventQueue.invokeLater(new Runnable() {
         public void run() {
            new Login().setVisible(true);
         }
      });
   }

   // Variables declaration - do not modify                     
   private javax.swing.JPanel jPanel1;
   private javax.swing.JButton logButton;
   private javax.swing.JPasswordField passwordField;
   private javax.swing.JLabel passwordLabel;
   private javax.swing.JButton regButton;
   private javax.swing.JLabel titleLabel;
   private javax.swing.JTextField usernameField;
   private javax.swing.JLabel usernameLabel;
   // End of variables declaration                   
}

如何将视图与控制器分开? 你能告诉我一个例子吗?我在互联网上搜索了很多,但我找不到适合我的例子。

我的主要问题是创建NetBeans GUI Builder(按钮,JLabel,JList等)的组件是私有的,并包含在View类中。 我必须能够从外部类(在控制器中)管理这些对象。

例如,LoginView类只有GUI代码,而LoginController类管理LoginView类的按钮和JTextField ......

我该怎么办? 非常感谢你!

1 个答案:

答案 0 :(得分:0)

您想要创建另一个类来充当您的动作侦听器。您可以通过让类实现ActionListener接口来实现此目的。例如,这里有一个可以用于regButton

的类
package Controller; //I assume you'll want this class in the Controller package, right?

/*I'd recommend importing the classes you need at the beginning of the program
* that way, you don't have to type so much out every time */
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent; 

public class RegButtonListener implements ActionListener
{
    actionPerformed(ActionEvent evt)
    {
        Model.Login.regButtonActionPerformed(evt);
        //I'm assuming that the Login class you gave is in the Model package you made.
    }

    /*Because you're implementing an interface, you'll probably have to add in some
    *other abstract methods. Just add them in and leave them empty*/
}

现在在您的Login类中,只需在添加动作侦听器时按钮指向此新类。

  regButton.setText("Registrati");
  regButton.addActionListener(Controller.RegButtonListener);

  public void regButtonActionPerformed(java.awt.event.ActionEvent evt)
  {
      //Do whatever it is the button does
  }

使用此方法,您必须为每个组件创建一个完整的类。这真的很快就会变得非常混乱。一种替代方法是让您的新动作侦听类适用于所有组件并调用适当的方法。像这个例子:

package Controller;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent; 

public class GeneralActionListener implements ActionListener
{
    actionPerformed(ActionEvent evt)
    {
        Object source = evt.getSource();
        //This might not work if NetBeans makes everything private
        if (source == Model.Login.regButton)
        {
            Model.Login.regButtonActionPerformed(evt);
        }
        else if (source == Model.Login.logButton)
        {
            Model.Login.logButtonActionPerformed(evt);
        }
        //Repeat for each component
    }
}

希望有所帮助。对不起,我之前从未使用过NetBeans GUI构建器,但这通常是我做事的方式。另一个常见技巧(不保持类分离但仍然很方便)将使Login类本身实现ActionListener接口并将ActionPerformed方法放在那里。