5

First time posting a question on StackOverflow, so please go easy on me :)

From what I understand, proper use of the model-view-controller pattern requires that we decouple the view and controller such that the view knows nothing about the controller. I'm having a bit of a problem understanding how to do this using Java Swing.

Say I have a view (some class that would extend JFrame), and this view has a button. Is it safe to say that I would want to register the controller as an ActionListener of the button? Or do I make it a listener of the entire view itself.

And how do I go about doing this without doing something like:

button.addActionListener(myController)

in the view, because if I were to do this in the view code, wouldn't it now have a dependency on the controller?

I didn't post any code because, frankly I don't have much to go on at the moment.

any help is appreicated!

Alan
  • 2,897
  • 4
  • 23
  • 27
  • link to relevant question on stackoverflow: http://stackoverflow.com/questions/3066590/gui-problem-after-rewriting-to-mvc . My main problem with MVC is that there are so many ways to do it, and I have come to realize that the view and controller are generally tightly coupled, so it's really up to the coder to decide how s/he wants to resolve dependencies. Thanks for all your replies! – Alan Jan 06 '11 at 21:46

3 Answers3

4

It might help to not think of the view in terms of buttons etc. so much as an interface. The interface makes it possible for web ui's, command line consoles, etc. to be written and fulfill the role of the view.

In the case of your button event, the button represents a call to some command carried out by the controller.

So, you could have an interface like this:

public interface MyViewIf {
    // used by the controller to register its self as a listener of the view
    public addViewListener(ViewListener vl);
    ...
}

and:

public interface ViewListenerIf {
    // used by the View to notify any listeners of control events etc.
    public onViewEvent(ViewEvent ve);
}

Then your controller would implement ViewListenerIf and register it's self with a factory generated instance of MyViewIf. That way the controller doesnt need to know any specifics about your view class(es).

Your view class would then internally handle it's own button events, turn them into ViewEvent objects and call onViewEvent() on the controller that registered it's self with the view, leaving the View 100% oblivious to the existence of the Controller.

Nick
  • 8,181
  • 4
  • 38
  • 63
  • One more quick comment - you can also replace addViewListener and onViewEvent methods with a series of more specific addXXXEventListener methods and the corresponding event objects etc. Sometimes it's not convenient to try and genericize all View events into a single object. – Nick Jan 06 '11 at 19:29
  • Thanks! This is definitely on the track of what I was looking for. Can you elaborate a little on ViewEvent objects. Is this something I would have to code up myself, or are there relevant classes in the java swing libraries that I can extend..? I've been reading on swing in the java tutorials, so if I've missed out on an explanation elsewhere, you could just point me in the right direction :) – Alan Jan 06 '11 at 19:31
  • As far as what to use for your Event class, it can be pretty much any class but I've found it to be quickest to write them yourself since they tend to be very simple objects with application specific fields. For example, if your view only needs to pass messages and not strings, arrays etc. your ViewEvent object could consist of a single int or enum field representing the messageId. – Nick Jan 07 '11 at 02:47
  • Almost forgot - you can take a look at Java's Observer and Observable classes. They give you pretty much everything you need short of your Event class(es). You might also consider using them as a template to create your own generified versions to get the stronger typing. – Nick Jan 07 '11 at 04:40
1

Take a look at the Spring Framework to get an insight in implementing the MVC pattern. Brief Spring tutorial Tutorial

dsr
  • 1,306
  • 1
  • 13
  • 21
1

Make an actionlistener in your view class. From your actionlistener you call your controller.

Code for actionlistener:

controller.doButtonClick();

This means you need to inject your model and controller to the view. That is how I do it.

Mads Andersen
  • 3,123
  • 5
  • 38
  • 44
  • Doesn't this introduce a dependency on the controller from the view? If so, is this acceptable in the MVC pattern? And if not, how so, since we are indeed referring to the controller from the view, just indirectly through the actionlistener? – Alan Jan 06 '11 at 19:26
  • 1
    Yes it does. But I think it is okay. We use the mvc pattern to seperate the ui from the domain logic. If you were going to create a new ui it would still only be the view code you had to change. – Mads Andersen Jan 06 '11 at 19:40
  • 1
    What you could do though, is from your controller call: getView().getButton().addActionListener(myControllerButtonActionListener); if you like that better. This doesnt introduce a dependency on the controller from the view. – Mads Andersen Jan 06 '11 at 19:43