I recently learned Smalltalk's version of the Model-View-Presenter pattern
and am able to construct UI controls. I ran across a fairly undocumented design question, however, when dealing with multiple views of the same model. The UI control I am attempting to create should have a tab control with multiple pages, much like many Windows programs' options pages, Outlook for example. I began creating a class named MyModel, which was no problem. I also created a Presenter MyPresenter to act as the manipulator of the model. Next came the views. I created a view named 'Default View' by subclassing ContainerView with the class named MyView. I coupled MyView with MyPresenter without issue, as well. I then opened 'MyPresenter.Default View' in the View Editor and added a 'ListPresenter.Tab View' control and initialized it with three strings in MyPresenter>>model:. The strings were 'Subview1', 'Subview2', and 'Subview3'. Tested and so far so good; a tab view with the specified strings appeared. Next, I created three more subclasses of ContainerView, one for each Tag, named MySubview1, MySubview2, and MySubview3, with the corresponding names in the View Editor: 'MyPresenter.Subview1', 'MyPresenter.Subview2', and 'MyPresenter.Subview3'. Each subview will display a different set of the MyModel data and should notify MyPresenter of its events. Questions: Using the MVP pattern, what is the proper way to couple a Presenter to multiple views? Should the composite view have instance variables containing its subviews or should that be the responsibility of the Presenter? The Presenter class itself has an instance variable named view which, I assume, contains the Presenter's default view. I have found many examples of creating one-to-one relationships between Presenters and Views, but that can often result in creating more Presenters than necessary; I tend to rely on a one-to-one relationship between the Presenter and the Model. Should I just create an instance variable for each of the subviews in the Presenter and toggle each's visibility each time a new tag is selected? Thanks, in advance. Jon |
Jon,
I think you may be unnecessarily complicating the addition of the tab control. Dolphin already has a MVP, named Presenter.Card container, that does most of the hard work for you, but from your references to ListPresenter.Tab view and creating ContainerView subclasses it would seem to indicate you are trying to do it the hard way? There are two main ways to use the tab controls. 1) "Lump" mode :-) where all of the components are lumped together. You can imagine this as a normal Presenter and Model but with a View that only shows a small selection of the available controls (the ones on the currently selected tab). The Presenter can update all of the controls at any time but the user will only see the visible one. Similarly, all the inputs are active all the time but the user can only get at the ones on the visible tab. So, say you wanted a Presenter with 3 tabs, tabA, tabB, tabC. You would - Create a Shell subclass called MyShell - Open the ViewComposer on a new ShellView - Make the layoutManager for the ShellView a BorderLayout. - Drop a Presenter.Card container onto the main Shell - Set it's arrangement aspect to #centre Now you can add the three cards - Drop a Presenter.Default view onto the CardContainer. This will be show as a card with a tab at the top. In the #arrangement aspect type "tabA", the label on the tab will change. - Do the same twice more but name them "tabB" and "tabC" You can then add subviews to each card. - Select "tabA" - Drop a TextPresenter.Default view onto the view - Give it the name "tabAText" - Do the same for "tabB" and "tabC", naming the text edits tabB.Text and tabC.Text respectively Save the view and go back to the Presenter. You can now add a normal #createComponents methods createComponents super createComponents. tabAText := self add: TextPresenter new name: 'tabAText'. tabBText := self add: TextPresenter new name: 'tabBText'. tabCText := self add: TextPresenter new name: 'tabCText'. and use them just as you would any other MVP component. onViewOpened super onViewOpened. tabAText value: 'TabA'. tabBText value: 'TabB'. tabCText value: 'TabC' The fact that two of the three presenters will be invisible is immaterial, you can still access/receive events from them as normal However, you can see that the more tabs you add, and the more controls you have on each tab, that this technique can get a bit messy. 2) "Discrete" mode. For each of the tabs you create a discrete MVP triad. Instead of dropping a Presenter.Default view onto the CardContainer, and then adding controls to that, you drop the appropriate prebuilt and self contained MVP component. Your createComponents would then be createComponents super createComponents. tabA := self add: MyTabA new name: 'tabA'. tabB := self add: MyTabB new name: 'tabB'. tabC := self add: MyTabC new name: 'tabC' Communication between you main Presenter/Model and the subPresenter would then be done using normal message sends and events. onViewOpened super onViewOpened. tabA setTextTo: 'TabA'. tabB setTextTo: 'TabB'. tabC setTextTo: 'TabC'. You would also (probably) share the model between all the subpresenters to prevent a lot of unnecessary access methods. Mail me if you want some code examples. Regards Ian |
Ian
Thanks for the enlightening reply. You're right; the Presenter.Card container really simplifies the procedure greatly! I was able to complete using the tab view with no major difficulties after reading your explanation. Thanks again, Jon "Ian Bartholomew" <[hidden email]> wrote in message news:Xm_d9.4657$J47.367953@stones... > Jon, > > I think you may be unnecessarily complicating the addition of the tab > control. Dolphin already has a MVP, named Presenter.Card container, that > does most of the hard work for you, but from your references to > ListPresenter.Tab view and creating ContainerView subclasses it would seem > to indicate you are trying to do it the hard way? > > There are two main ways to use the tab controls. > > 1) "Lump" mode :-) where all of the components are lumped together. You > imagine this as a normal Presenter and Model but with a View that only shows > a small selection of the available controls (the ones on the currently > selected tab). The Presenter can update all of the controls at any time but > the user will only see the visible one. Similarly, all the inputs are > active all the time but the user can only get at the ones on the visible > tab. > > So, say you wanted a Presenter with 3 tabs, tabA, tabB, tabC. You would > - Create a Shell subclass called MyShell > - Open the ViewComposer on a new ShellView > - Make the layoutManager for the ShellView a BorderLayout. > - Drop a Presenter.Card container onto the main Shell > - Set it's arrangement aspect to #centre > > Now you can add the three cards > > - Drop a Presenter.Default view onto the CardContainer. This will be show > as a card with a tab at the top. In the #arrangement aspect type "tabA", > the label on the tab will change. > - Do the same twice more but name them "tabB" and "tabC" > > You can then add subviews to each card. > - Select "tabA" > - Drop a TextPresenter.Default view onto the view > - Give it the name "tabAText" > - Do the same for "tabB" and "tabC", naming the text edits tabB.Text and > tabC.Text respectively > > Save the view and go back to the Presenter. You can now add a normal > #createComponents methods > > createComponents > super createComponents. > tabAText := self add: TextPresenter new name: 'tabAText'. > tabBText := self add: TextPresenter new name: 'tabBText'. > tabCText := self add: TextPresenter new name: 'tabCText'. > > and use them just as you would any other MVP component. > > onViewOpened > super onViewOpened. > tabAText value: 'TabA'. > tabBText value: 'TabB'. > tabCText value: 'TabC' > > The fact that two of the three presenters will be invisible is immaterial, > you can still access/receive events from them as normal > > However, you can see that the more tabs you add, and the more controls you > have on each tab, that this technique can get a bit messy. > > 2) "Discrete" mode. For each of the tabs you create a discrete MVP triad. > Instead of dropping a Presenter.Default view onto the CardContainer, and > then adding controls to that, you drop the appropriate prebuilt and self > contained MVP component. Your createComponents would then be > > createComponents > super createComponents. > tabA := self add: MyTabA new name: 'tabA'. > tabB := self add: MyTabB new name: 'tabB'. > tabC := self add: MyTabC new name: 'tabC' > > Communication between you main Presenter/Model and the subPresenter would > then be done using normal message sends and events. > > onViewOpened > super onViewOpened. > tabA setTextTo: 'TabA'. > tabB setTextTo: 'TabB'. > tabC setTextTo: 'TabC'. > > You would also (probably) share the model between all the subpresenters to > prevent a lot of unnecessary access methods. > > Mail me if you want some code examples. > > Regards > Ian > > |
Free forum by Nabble | Edit this page |