MVP question: multiple views of the same model

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

MVP question: multiple views of the same model

Jonathon Spaeth
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


Reply | Threaded
Open this post in threaded view
|

Re: MVP question: multiple views of the same model

Ian Bartholomew-17
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


Reply | Threaded
Open this post in threaded view
|

Re: MVP question: multiple views of the same model

Jonathon Spaeth
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
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
>
>