Multithreaded GUI in the MVC model

2019-09-05 16:27发布

问题:

I have gone through a ton of postings regarding GUI in the MVC model and where to put code and in which thread.

MadProgrammer and trashgod have put me in the right direction, but there are things I still don't understand.

In my main class I have the following code

import java.awt.EventQueue;

import javax.swing.JOptionPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import common.InitParameters;
import common.OraLogin;
import common.ThresholdValues;


public class cmtNew implements Runnable {
    public static void main(String[] args) {
        EventQueue.invokeLater(new cmtNew());
    }

    @Override
    public void run() {

        // Set look and feel of GUI
        try {
            UIManager.setLookAndFeel(
                    UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException | InstantiationException
                | IllegalAccessException | UnsupportedLookAndFeelException e) {
            e.printStackTrace();
        }

        // Login to database
        loginDb();  

        // Init system parameters
        initParameters();

        // Set up the application
        CmtModel theModel       = new CmtModel();
        CmtGui theGui           = new CmtGui();
        CmtControl theControl   = new CmtControl(theGui,theModel);

//        Model model           = new Model();
//        View view             = new View(model);
//        Control control       = new Control(model, view);

        // Show GUI
        theGui.setVisible(true);

    }

    /**
     * Login to database
     */
    private static void loginDb(){
        OraLogin login = new OraLogin();
        try {
            login.userLogin();
        } catch (Exception e) {
            JOptionPane.showMessageDialog(null, "Unable to log in to database: "+e.getMessage());
            System.exit(0);
        }
    }

    /**
     * Init parameters
     */
    private static void initParameters(){
        try {
            InitParameters initParameters = new InitParameters();
            ThresholdValues thresholdValues = new ThresholdValues();
        } catch (Exception e) {
            JOptionPane.showMessageDialog(null, "Unable initialize environment parameters: "+e.getMessage());
            System.exit(0);
        }
    }
}

I start up a number of SwingWorker threads in the constructor of the Control to take care of slow queries to the database.

Questions:

  1. The part that is commented out when initializing model, view, control is from the MVCgame example by trashgod https://stackoverflow.com/a/3072979/4654417 why pass the model to the view?

  2. The GUI updates is supposed to be done in the EDT, but putting the control, model, view init where it is in the code (apparently common practice), all of them will be on the EDT..., or?

  3. I have put the SwingWorker threads in the Control. Right or wrong? Good or bad?

  4. My background as a non OO programmer I still have a hard time to wrap my head arround the concept of event handling. I have implemented MVC in the way that Control tell Model to query for data in the database. Then Control ask Model for data and passes that on to View in an update method. What I understand..., that's the wrong way to go about it.

How I believe it kind of should work is that Control somehow tell Model to query data/read a file or whatever. If Model successfully can do that it triggers an event that says 'hey I have fresh data'. View (or Control) listens for the event and update the gui in the EDT thread somehow.

I just cant figure out the event traffic and who (Model, Control, View) is doing what and how. And yeeees, I have studied the numerous tutorials from Oracle but I still don't get it.

Cheers

回答1:

I hope I'm not contradicting anything MadProgrammer and trashgod have previously said.

Why pass the model to the view?

The model must remain ignorant of the view. This allows the model to be used with more than one type of view (Swing, web, smart phone).

However, the view can read from the model. The view most not update the model. Updating the model is the job of the controller.

The GUI updates [are] supposed to be done in the EDT, but putting the control, model, view, init where it is in the code (apparently common practice), all of them will be on the EDT?

Constructing and updating the GUI must be done on the EDT. Generally, you'll have action listeners and / or item listeners that listen for GUI changes. The code in the listeners will update the model and repaint / revalidate the GUI if necessary.

Basically, your listeners are your controllers. I'd suggest one or more listeners per GUI component, rather than a super listener that tries to handle multiple GUI components.

I have put the SwingWorker threads in the Control.

Generally, your SwingWorker threads are part of the the controller. Generally, I put threads in separate classes from everything else.

I have implemented MVC in the way that Control tell Model to query for data in the database. Then Control ask Model for data and passes that on to View in an update method.

Here's how I implement MVC in a Swing GUI.

  • The view may read from the model.
  • The view may not update the model.
  • The controllers will update the model.
  • The controllers will repaint / revalidate the view.

For a better idea of how I implement the MVC model in a Swing application, take a look at my Retro Snake Game article.