Multiple Forms with MVC in Swing

2019-08-04 08:28发布

问题:

First post here, so please be gentle! I have searched far and wide for an answer to my question, but have turned up nothing.

I am trying to learn and apply the MVC architecture to create a Java Swing application. I think I understood the separate roles of the model, view and the controller.

However, my application has a JMenuBar (File, Edit and so on...).

What I want to do is after clicking a menu item, a form to pop up (which gets delegated in to the controller from the DVSDesk class).

The difficulty I am having is how to display the form accepting the controller and model -- from what I have read, each JFrame needs it's own thread, which is where I get confused. As the invokeLater is in its own unique thread, I can not seem to pass model or controller in.

Apologies if this is a dumb question, but I have been doing a lot of searching around, and seem to be getting nowhere fast!

EDIT -- My real question -- Is the showImporterForm() the correct way of creating and showing the new form?

Below is the code for the main thread (DVSMain.java)

public static void main(String[] args) {
    TopLevelController TLC;
    TopLevelModel TLM;

     java.awt.EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            TopLevelModel TLM = new TopLevelModel();
            TopLevelController TLC = new TopLevelController(TLM);
        }
    });
}

Below is the code for the controller (TopLevelController.java)

public class TopLevelController {    
// Initialise model and view
TopLevelModel TLM;
DVSDesk TLV;

public TopLevelController(TopLevelModel model) {
    // Get a reference to the view and model
    TLM = model;
    TLV = new DVSDesk(this,model);
    TLV.setVisible(true);
}

public void showImporter() {
    ImportForm importFm = new ImportForm(this,TLM);
    importFm.setVisible(true);
}

/*public void showForm(final Form fm) {        
    // Show the form which has been passed in

    java.awt.EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {                
            fm.show();
        }
    });
}*/

public void quit() {System.exit(0);};
}

And below is the code from DVSDesk.java (the menu based GUI)...

public class DVSDesk extends javax.swing.JFrame {

/**
 * Creates new form DVSDesk
 */

TopLevelController TLC;
TopLevelModel TLM;

public DVSDesk(TopLevelController controller, TopLevelModel model) {
    initComponents();
    TLC = controller;
    TLM = model;
}

/**
 * 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() {

    jLayeredPane1 = new javax.swing.JLayeredPane();
    jSeparator1 = new javax.swing.JSeparator();
    jMenuBar1 = new javax.swing.JMenuBar();
    jMenu1 = new javax.swing.JMenu();
    fImportDiags = new javax.swing.JMenuItem();
    jSeparator2 = new javax.swing.JPopupMenu.Separator();
    fQuit = new javax.swing.JMenuItem();
    jMenu2 = new javax.swing.JMenu();

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

    jMenu1.setText("File");

    fImportDiags.setText("Import Diagrams...");
    fImportDiags.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            fImportDiagsActionPerformed(evt);
        }
    });
    jMenu1.add(fImportDiags);
    jMenu1.add(jSeparator2);

    fQuit.setText("Quit...");
    fQuit.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            fQuitActionPerformed(evt);
        }
    });
    jMenu1.add(fQuit);

    jMenuBar1.add(jMenu1);

    jMenu2.setText("Edit");
    jMenuBar1.add(jMenu2);

    setJMenuBar(jMenuBar1);

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGap(0, 800, Short.MAX_VALUE)
    );
    layout.setVerticalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGap(0, 579, Short.MAX_VALUE)
    );

    pack();
}// </editor-fold>                        

private void fQuitActionPerformed(java.awt.event.ActionEvent evt) {                                      
    TLC.quit();
}                                     

private void fImportDiagsActionPerformed(java.awt.event.ActionEvent evt) {                                             
    TLC.showImporter();
}                                            

/**
 * @param args the command line arguments
 */
public static void main(String args[]) {
    /*
     * 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(DVSDesk.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (InstantiationException ex) {
        java.util.logging.Logger.getLogger(DVSDesk.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (IllegalAccessException ex) {
        java.util.logging.Logger.getLogger(DVSDesk.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (javax.swing.UnsupportedLookAndFeelException ex) {
        java.util.logging.Logger.getLogger(DVSDesk.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    }
    //</editor-fold>
}
// Variables declaration - do not modify                     
private javax.swing.JMenuItem fImportDiags;
private javax.swing.JMenuItem fQuit;
private javax.swing.JLayeredPane jLayeredPane1;
private javax.swing.JMenu jMenu1;
private javax.swing.JMenu jMenu2;
private javax.swing.JMenuBar jMenuBar1;
private javax.swing.JSeparator jSeparator1;
private javax.swing.JPopupMenu.Separator jSeparator2;
// End of variables declaration                   
}

回答1:

All Swing components share a common event dispatch thread, although applications typically use a single JFrame. You can learn more about MVC and Swing here.

Addendum: As an aside, don't let the GUI designer dictate your GUI design. You need to understand how to use Swing manually in order to understand problems encountered when using the designer. As shown here, you can add content to your chosen top-level container and limit using the designer for components that need it.