Correctly Implementing the MVC Pattern in Gui Development Using Swing in Java

Correctly implementing the MVC pattern in GUI development using Swing in Java

Maybe I am misunderstanding, and everything should be done differently in different languages?

There is no misunderstanding; the pattern is merely applied differently.

As noted in a comment by @ordous and this this answer by @udalmik, a Swing application may have multiple implementations of the MVC pattern. As noted here and here, "not every interaction needs to pass through your application's controller." In contrast, a web application may well "have a 1:1 relation between views and controllers."

The Swing separable model architecture, cited here, "collapses the view and controller parts of each component into a single UI (user-interface) object." Swing controllers are scattered among the descendants of JComponent, typically in the component's UI delegate. As a concrete example, BasicButtonUI contains a BasicButtonListener that handles user mouse interaction.

Almost used the answer in the link, but the fact that his controller extends JPanel ruined it, totally confused me there.

This can be confusing, as a simple Swing program may have no explicit controller at all. As suggested in this outline, the controller has direct access to any relevant view and model; it may also listen to user interaction with the view. The example was intended to illustrate the simplest such interaction. It is mere coincidence that the effect is evoked by user interaction with a view component. The simulation cited here, for example, has a ControlPanel of view components that update the application's view and model. The DisplayPanel listens directly for a ComponentEvent that requires a model update. Etc.

Your application's controller is then free to focus on the application's needs.

@Marco13 elaborates on this and cites additional examples in this related answer.

The MVC pattern and Swing

A book I'd highly recommend to you for MVC in swing would be "Head First Design Patterns" by Freeman and Freeman. They have a highly comprehensive explanation of MVC.

Brief Summary

  1. You're the user--you interact with the view. The view is your window to the model. When you do something to the view (like click the
    Play button) then the view tells the controller what you did. It's the
    controller's job to handle that.

  2. The controller asks the model to change its state. The controller takes your actions and interprets them. If you click on a
    button, it's the controller's job to figure out what that means and
    how the model should be manipulated based on that action.

  3. The controller may also ask the view to change. When the controller receives an action from the view, it may need to tell the
    view to change as a result. For example, the controller could enable
    or disable certain buttons or menu items in the interface.

  4. The model notifies the view when its state has changed. When something changes in the model, based either on some action you took
    (like clicking a button) or some other internal change (like the next
    song in the playlist has started), the model notifies the view that
    its state has changed.

  5. The view asks the model for state. The view gets the state it displays directly from the model. For instance, when the model
    notifies the view that a new song has started playing, the view
    requests the song name from the model and displays it. The view might
    also ask the model for state as the result of the controller
    requesting some change in the view.

Sample Image
Source (In case you're wondering what a "creamy controller" is, think of an Oreo cookie, with the controller being the creamy center, the view being the top biscuit and the model being the bottom biscuit.)

Um, in case you're interested, you could download a fairly entertaining song about the MVC pattern from here!

One issue you may face with Swing programming involves amalgamating the SwingWorker and EventDispatch thread with the MVC pattern. Depending on your program, your view or controller might have to extend the SwingWorker and override the doInBackground() method where resource intensive logic is placed. This can be easily fused with the typical MVC pattern, and is typical of Swing applications.

EDIT #1:

Additionally, it is important to consider MVC as a sort of composite of various patterns. For example, your model could be implemented using the Observer pattern (requiring the View to be registered as an observer to the model) while your controller might use the Strategy pattern.

EDIT #2:

I would additionally like to answer specifically your question. You should display your table buttons, etc in the View, which would obviously implement an ActionListener. In your actionPerformed() method, you detect the event and send it to a related method in the controller (remember- the view holds a reference to the controller). So when a button is clicked, the event is detected by the view, sent to the controller's method, the controller might directly ask the view to disable the button or something. Next, the controller will interact with and modify the model (which will mostly have getter and setter methods, and some other ones to register and notify observers and so on). As soon as the model is modified, it will call an update on registered observers (this will be the view in your case). Hence, the view will now update itself.

Java Swing + MVC pattern in a modular way

The Model, View, Controller pattern allows us to separate business logic, screen rendering and handling asynchronous events into discrete classes. The benefit of this is that it effectively decouples all the fundamental responsibilities of a GUI-driven application into dedicated classes. This means that the functionality of each class is isolated, which better accommodates application-specific customization and maintainability.

So, with this fundamental approach, the application's overall architecture for your application is good so far, however what your boss is looking for is slightly different. He's asking for the implementation of some architecture which will allow you to rapidly and simply modify the UI. So, immediately, you can tell what he's asking for is with respect to the View element of the MVC.

Below I use pseudo-code to provide a generic example of how you could create these modular graphical elements.

public final class View {

private GUIElement mModularElement;

public final void setModularElement(final GUIElement pModularElement) {
this.mModularElement = pModularElement;
}

public final GUIElement getModularElement() {
return this.mModularElement;
}

public final void onRender(final GUIVariable pGUIVariable) {
this.getModularElement().draw(pGUIVariable);
}

}

In this code, we've defined the View of the application access to an instance of something called ModularElement, of type GUIElement. By using public getter/setter methods, the Controller can get the View to render any type of Object that inherits from GUIElement. So, if you ever wanted to change the GUI, you could specify a new kind of GUIElement without making changes to the surrounding architecture.

This is a basic example, because other kinds of responsibilities, not just rendering, would need to be handled by the GUIElement to maximize flexibility. These would include defining the screen layout, encapsulation of further graphical elements, how they handle MotionEvents, all lie within extending the functionality of GUIElement. You could even draw an array of GUIElements. Importantly, mModularElement would exist within your Model to adhere to the MVC pattern; the implementation above avoids this in the interest of simplicity.

Hope this helps.

Implementing MVC paradigm in Swing (Java) using Threads

My aim is to implement each of the M, V and C as a separate thread.

This is probably not a useful division. Swing views must be constructed and manipulated only on the event dispatch thread, and users expect Swing controls to remain responsive, as discussed here.

Instead, run any time-consuming model in the background of a SwingWorker, and update listening views in your implementation of process(). In this example, the view components are updated directly, but you can also fire a custom event for registered listeners, as suggested here. In this example, the chart listens to its data model, series, via SeriesChangeEvent; it responds to the worker's update in process(). You can show progress via a PropertyChangeEvent, as suggested here or here.

MVC pattern in Java application

I would not consider DropBoxDownloader or FileParser to be part of your model. Your model essentially represents your data. Your model is what gets persisted to a database. Generally, my model consists of POJOs (plain ole Java Objects), which is just a list of properties with getters and setters, and is serializable, so it can be sent over a network connection in a common format like JSON or XML. Anybody who can receive this information in a common format is free to do with it whatever they please, include deserializing into a different programming language. This is how complex systems can communicate with each other, and in some cases, not even knowing the other exists. I always keep my model in a separate package, and sometimes a separate project to enhance visibility and res-usability.

Your view should be able to exist without your data. It wont do everything you want it to do, but it should still be minimally operable as a shell. It should also be replaceable with a different view without loss of functionality. This means you shouldn't be mixing things like database queries in your View files, because you'll have to rewrite your queries for a new view.

Your controller is the glue which integrates your model and packages it up in an easy way to pass along to your view. In general, it does verbs (methods) to nouns (your model objects). I would consider FileParser (assuming it does what it says it does) and DropBoxDownloader to be functions of your controller.

Can you build a Swing GUI for an MVC-style game if the Controller doesn't have a reference to the Model?

I'm not gonna go into whether your flow is right or wrong.

  • Create an event queue in input. Listeners can then add events to the queue. Model can then ask the Input whether there are unhandled events in the queue and perform an action depending on the event that occurred. Let model hold a reference to the view interface call the appropriate view method in the performAction method.

Pseudo code:

    class Controller{
Queue<UIEvent> events;

void setupUI(){
button.addEventListener( new EventListener(){
Model.this.events.add(new TappedButtonEvent());
});
}

UIEvent dequeueEvent(){
if(events.size() > 0){
return events.pop()
}
return null;
}

}

class Model{

public void loop(){
while (!gameFinished) {
UIEvent in = input.dequeueEvent();
if(in != null){
performAction(in);
}
}
}
}
  • Do not encapsulate how something is displayed in Model, let view handle it.

    interface View{
    void displayExitMessage()
    }

    class CommandLineView implements View{

    void displayExitMessage(){
    this.commandLine.append("Are you sure you want to exit(Y/N)?");
    }
    }

    class CommandLineView implements View{

    void displayExitMessage(){
    this.window.showDialog("Are you sure you want to exit?", Button.YES, Button.NO);
    }
    }


Related Topics



Leave a reply



Submit