简体   繁体   中英

MVC - Observer/Observable pattern in Java Swing

I am trying to build a Swing user interface based on MVC and have a couple of questions on the topic. The best way of asking my questions would be with the help of a simple example.

Let's say that we have a JDialog with one JButton and 3 JTextFields. When that button is pressed I want this JDialog to close and another one to open that requires the data from the 3 JTextFields.

The easy way of doing this (going for just snippets of code, no need to annoy you too much) is:

myButton.addMouseListener(new MouseAdapter(){

    @Override
    public void mouseClicked(MouseEvent evt){
        firstFrame.setVisible(false);
        secondFrame.setData(jTextField1.getText(),jTextField2.getText(),jTextField3.getText());//just sending the data to the new window, would be this or something similar
        secondFrame.setVisible(true);
        }});

Or something like that.

First Question: If I don't use an anonymous inner class but decide to use a seperate class for my Listener how would I pass the data from the 3 JTextFields to my mouseListener class? Are there any alternatives other than keeping a reference of the view in the Listener class?

Carrying on, given the MVC pattern:

Second Question: I guess that it makes sense the listener (controller according to MVC) to call another window without the model getting involved, that it's job I guess. But the data that need to pass from one window to the next one (the data from the 3JTextFields) shouldn't those go through the model ? Like having the first window save that data in the model, and then when the second one needs them request them from the model.

Third Question: I was considering of using the Observer/Observable pattern. How would that be used in this example to open the last window? I mean since (I think) the Controller is the class that opens the second window, would that mean that the Listener would have to be Observed and the second window would have to be an Observer so that the Listener would say

 notifyObservers("openSecondWindow");

and then the second window would see that and open itself?

Finally: I heard that a PropertyChangeListener could work as well, and that it is sometimes preffered over the Observer/Observable Pattern. What are your thoughts on this, especially regarding my example.

I am confused..

Thank you for your time.

I'm not sure about the Java specific aspects. But talking about OOP, it's pretty reasonable to make your application decoupled by an event-driven design. So, instead of dealing directly with the components, you'll instead trigger events, as you wrote: notifyObservers("openSecondWindow"); .

But, you don't need to pass through the model layer to do so. Instead you should have an event class representing the given event and set the values of the mentioned fields within the event class.

Something like:

exampleEvent.setProperty1('blah').setProperty2('blah2');
notify('openSecondFrame', exampleEvent);

I've posted a question regarding this event-driven stuff a while ago:

PHP: Am I mixing up event-driven programming with signals-aware interfaces (Signal and Slots / Observer Pattern)?

There are several links that you might be interested in reading (it's PHP, but the concept applies to OOP).

So, following this concept, it's a good idea to create an EventHandler component to manage those events and signals.

But again, take into account that I'm not proficient in Java. It's just about OOP.

First Question

If I don't use an anonymous inner class but decide to use a separate class for my Listener how would I pass the data from the 3 JTextFields to my mouseListener class?

Your separate MouseAdapter class would have a constructor, where you pass what you need from your JPanel class to your MouseAdapter class.

This code is for an ActionListener , but I think the general idea will show you how to write a MouseAdapter class.

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

import com.ggl.project.planner.model.Planner;
import com.ggl.project.planner.model.Project;
import com.ggl.project.planner.view.CreateUpdateProjectDialog;
import com.ggl.project.planner.view.ProjectPlannerFrame;

public class CreateProjectActionListener implements ActionListener {

    protected Planner planner;

    protected Project project;

    protected ProjectPlannerFrame frame;

    public CreateProjectActionListener(ProjectPlannerFrame frame,
            Planner planner, Project project) {
        this.frame = frame;
        this.planner = planner;
        this.project = project;
    }

    @Override
    public void actionPerformed(ActionEvent event) {
        CreateUpdateProjectDialog dialog = 
                new CreateUpdateProjectDialog(frame, project, true);
        if (dialog.isOkPressed()) {
            planner.setProjectOpen(true);
        }
    }

}

Second Question

I guess that it makes sense the listener (controller according to MVC) to call another window without the model getting involved, that it's job I guess. But the data that need to pass from one window to the next one (the data from the 3JTextFields) shouldn't those go through the model ? Like having the first window save that data in the model, and then when the second one needs them request them from the model.

I'm not sure I understand your question. When I build a GUI, I have one or more data models that represent the values from the GUI. The instances to those data models are passed through most of the components that make up the GUI.

The rest of the application accesses the GUI information through the models.

In the ActionListener class that I posted as part of the answer to the first question, there are 2 data models, Project and Planner . Project is specific to a particular project, while Planner is global to the GUI.

Third Question

I was considering of using the Observer/Observable pattern. How would that be used in this example to open the last window?

Swing already has the listener pattern built in. You can use action listeners for your own actions. You can even add your own listener type to Swing, although it's a painful process. I added my own listener type once when I extended a JPanel to make a JCroppingPanel .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM