3

In my application there are many views(sub components) and only one controller. Selecting some options in one view can change the layout and number of components in another view. The controller initialises the view, which in turn creates all the sub components.

In an application such as this does the controller need to have a reference to all the sub components? As in a listener in one view calls the controller to carry out the action and then needs to update the other view. I feel that the controller should not have a reference to all the views but dont know where to go form here. The example in the Head first design patterns book only has one view so I am stuck.

++++++++++++++++++++++++

More detail. The game I am writing is a checkers (draughts) game. In one scenario when the computer is playing against itself the user has to choose some options before the game starts. One such option is to choose the games strategy for certain periods during the game. Such as when it has 12 to 8 pieces on the board it will attack more, 8 to 4 pieces on the board it will be more defensive.

The way the game GUI is structured at the moment, is that there is one overall JPanel (RightContainerFrame) this contains the other JPanels; there is then one JPanel (StartGamePanel) in which the user can configure the game. There is also a JTabbedPane (jTabbedPane1) which contains tabs. Currently in the StartGamePanel when a user selects a certain option in a JComboBox, tabs need to be added or removed from jTabbedPane1.

The way I achieve this currently is in StartGamePanel

RightContainerFrame.getInstance().generateAndDisplayPlayerTwoRangeTabs(numberOfRangeTabsNeeded);

Now I know this is all wrong as I have one view, StartGamePanel directly changing another view JTabbedPane by calling a method in another there container view RightContainerFrame.

I am open to any suggestions as to how to structure this problem.

First I could move the jComboBox1ActionPerformed method to the controller. This could either update a model for the jTabbedPane1. Or it could call a method directly in the jTabbedPane1 to display the number of tabs required.

user1213428
  • 77
  • 2
  • 7
  • When you state "many views" I usually think of many different GUI's each displaying the information in a different way. If you don't mean this but on the other hand mean that there is one GUI (one view) that displays different portions of the data in different sections, then the answer will be different. Please clarify. If the latter, than no, the control only needs a reference to the master view, but this will need public methods so that the control can change its state, and so that the view can respond to these state changes. – Hovercraft Full Of Eels Feb 16 '12 at 21:14
  • I mean one GUI with many JPanels, a selection in one JPanel will affect what informaiton is displayed in other JPanels. Would the master view have a reference to all the sub components? – user1213428 Feb 16 '12 at 21:18
  • What's the master view? The controller? – toto2 Feb 16 '12 at 21:35
  • In my version, in the controller constructor its creates the view. This view then creates all the sub components. So this is rightly or wrongly the master view. `public Controller() { ... this.gameView = new GameView(this);` – user1213428 Feb 16 '12 at 21:37
  • I don't know of any one-size-fits-all answer for your question other than that you should strive to "maximize cohesion and minimize coupling" however seems best. I try to make my views as dumb as possible, and my models as ignorant of the views and the control as possible. For more specific advice, you'll probably have to tell us more detail and publish your code. – Hovercraft Full Of Eels Feb 16 '12 at 22:35
  • I will post the code tomorrow getting later here now. – user1213428 Feb 16 '12 at 22:48

3 Answers3

3

Swing is not a true MVC architecture: it's a model/(view+controller) architecture. Each JComponent is both a view and a controller.

You need to define callback methods (aka event listeners) which you associate to some event on the components. There are different types of event listeners for different types events on the different JComponents.

Here's a example where an event listener is registered on a button such that when it is clicked, it changes the text in another component (myJLabel):

jButton1.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent event) {
        myJLabel1.setText("You just clicked a button.");
    }
}
// you can add other ActionListeners to the same jButton1

You could have a global controller that handles all events, but you would need to register it as an listener for each component. When the global controller received the event, it can query it to find out from which button it came from and change other JComponent(s) accordingly. So, yes, your global controller would need references to all JComponents, on top of being registered to all of them as a listener. The global controller would need to implement not just ActionListener, as above to get the mouse clicks, but also all other types of EventListeners needed to handle all the other types of events from the other components.

It might not be a good idea to have a global controller because it could end up being a very large class. Just letting each JComponent registering one (or many) event listener(s) that directly change some other component(s) should be sufficient.

EDIT:
I am not so sure it's a bad idea to have a global controller: you end up with a huge class, but at least all the callback logic is in one place.

toto2
  • 5,306
  • 21
  • 24
  • Thanks that's the way I wrote it originally views changing other views. From reading up views changing other views should be avoided but it also seems to be the easiest way. – user1213428 Feb 16 '12 at 22:22
  • It's messy with or without a global controller... I'm not sure which is the best. I don't think there is a very clean way of dealing with callbacks functions. I'd be glad to see the opinion of others. – toto2 Feb 17 '12 at 00:47
2

What I don't know yet is how views update other views.

This simple example illustrates the observer pattern, which lets the model update the view in response to controller and view actions. This more elaborate example shows three views listening to a single model.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • 1
    Just a comment related to my answer: in your example you don't put all control handling in your controller. The ButtonHandlers for the PieceButtons are still part of the View instead of the Control. You could have made Control implement ActionListener and registered it with the PieceButtons and have it modify the model and update the view. – toto2 Feb 17 '12 at 01:06
1

I honestly fail to clearly understand your design, but the design I would adopt in this case (assuming we are talking about rich component based UI technologies) is to have the Views listen to an event bus and adapt their own layout on the grounds of the events transiting in the bus. In this context UI action handlers may post events in the bus. Effectively decoupling the views from each other and from the controller as well.

Update: have a look here - being Google's stuff tends to be a bit nerdy and overdesigned for most low-medium complexity needs, but you can trim it down to suit yours.

Alessandro Santini
  • 1,943
  • 13
  • 17
  • My design is that the views observe the model. The controller handles the events that the view creates. What I dont know yet is how views update other views. – user1213428 Feb 16 '12 at 21:31
  • Well, I think you have no other option but to have the controller know all the views. I do not think it is optimal maintenance-wise, but that's your call. – Alessandro Santini Feb 16 '12 at 21:41
  • I am not fixed into this design. Is there a design pattern or class in Java that I could use to implement the event bus? – user1213428 Feb 16 '12 at 21:43