I created a small test. I had one model and one view with 3 components on
it. Components: - text edit field for the var instance variable - label for the var instance variable - push button to set some static text. Model subclass: #SimpleModel instanceVariableNames: 'var' initialize var := 'default var value'. var: aVar var := aVar. Shell subclass: #SimplePresenter instanceVariableNames: 'varPresenter varPresenter2' createComponents super createComponents. varPresenter := self add: TextPresenter new name: 'textField'. varPresenter2 := self add: TextPresenter new name: 'textLabel'. model: aSimpleModel super model: aSimpleModel. varPresenter model: (aSimpleModel aspectValue: #var). varPresenter2 model: (aSimpleModel aspectValue: #var) aspectTriggersUpdates. setVarCommand varPresenter value: ('New Value'). defaultModel ^SimpleModel new When I run this example I was surprised that only text field was updated, since I used presenter of the text field to update the value of the model. Text label was not updated. I made the following changes to enable automatic text label updates. SimpleModel>>var: aVar var := aVar. self trigger: #varChanged "ADDED" publishedEventsOfInstances "NEW METHOD: What is that?" ^super publishedEventsOfInstances add: #varChanged; yourself. SimplePresenter>>model: aSimpleModel super model: aSimpleModel. varPresenter model: (aSimpleModel aspectValue: #var) aspectTriggersUpdates. "CHANGED" varPresenter2 model: (aSimpleModel aspectValue: #var) aspectTriggersUpdates. "CHANGED" varPresenter model aspectTriggers: #varChanged. "ADDED" varPresenter2 model aspectTriggers: #varChanged. "ADDED" This worked. It even updated label when I changed contents of the text field and moved focus away from the text field. That is what I expected to see in the first version of the code. I am confused. If the following make any sense at all: Why can't aspect of the simple model take care of the notification of two presenters itself? ----------------------- I am coming from MVC background in Java: create table model and get an instance of it; create an instance of table view; set a model object for a view. Done. Connect two views to a single model object: no problem. If forgot the details of how to use some component take a quick look at a tutorial on sun website. |
Sergei,
> Why can't aspect of the simple model take care of the notification of two > presenters itself? I think your message subject answered part of the reason. Dolphin does not consider your model as a "GUI" components as such - it is just a normal object that happens to be being used in a GUI. If every object automatically triggered an event when its state changed, which you would need to get the automatic notification you want, it would add a lot of overhead and slow things down. It would also mean that every object would expose part of it's inner workings, breaking encapsulation - one of the OO guidelines. [code snipped] > When I run this example I was surprised that only text field was updated, > since I used presenter of the text field to update the value of the model. > Text label was not updated. > > I made the following changes to enable automatic text label updates. [code snipped] > This worked. It even updated label when I changed contents of the text > field and moved focus away from the text field. That is what I expected > to see in the first version of the code. There was no need to do most of that. The #aspectTriggersUpdates method is now deprecated (i.e. you shouldn't use it for new code but it is still temporarily provided for backward capability) so you should be using #aspectTriggers: directly in your presenter. You will still need to change the #var method in your SimpleModel to trigger an event SimpleModel>>var: aVar var := aVar. self trigger: #varChanged but you only need to change one line in the #model method of your SimplePresenter SimplePresenter>>model: aSimpleModel super model: aSimpleModel. varPresenter model: (aSimpleModel aspectValue: #var). varPresenter2 model: ((aSimpleModel aspectValue: #var) aspectTriggers: #varChanged) I know it's only an example but I think your code is also slightly dangerous in that it relies on a third party to change the value in the model. I would tend to code it like (just the changes) SimplePresenter>>setVarChanged self model var: 'new value' SimplePresenter>>model: aSimpleModel super model: aSimpleModel. varPresenter model: ((aSimpleModel aspectValue: #var) aspectTriggers: #varChanged). varPresenter2 model: ((aSimpleModel aspectValue: #var) aspectTriggers: #varChanged) so that both presenters reflect the current value of the model. Finally. Did you realise you don't need a new model at all?. You could just use the model belonging to one of the TextEdits - all the trigger wiring is then done for you. SimplePresenter>>setVarChanged varPresenter model value: 'new value' SimplePresenter>>model: aModel super model: aModel. varPresenter model: varPresenter2 model There are lots of other ways of doing this, using a ValueModel to wrap the instance variable for yourself for example, but I've probably confused you enough already.... Regards Ian |
[snipped]
> There was no need to do most of that. The #aspectTriggersUpdates method is > now deprecated (i.e. you shouldn't use it for new code but it is still > temporarily provided for backward capability) so you should be using > #aspectTriggers: directly in your presenter. You will still need to change > the #var method in your SimpleModel to trigger an event > > SimpleModel>>var: aVar > var := aVar. > self trigger: #varChanged > > but you only need to change one line in the #model method of your > SimplePresenter > > SimplePresenter>>model: aSimpleModel > super model: aSimpleModel. > varPresenter model: (aSimpleModel aspectValue: #var). > varPresenter2 model: ((aSimpleModel aspectValue: #var) aspectTriggers: > #varChanged) I followed your instructions. Everything worked great. I decided to sublclass not from Model, but from Object. Code still worked (different gui componens updated). It does not seem that Model parent plays any role in this case. When can I use Object instead of Model? I provide here the code to reduce confusion: Object subclass: #SimpleModel instanceVariableNames: 'var' var: aVar var := aVar. self trigger: #varChanged Shell subclass: #SimplePresenter instanceVariableNames: 'varPresenter varPresenter2' createComponents super createComponents. varPresenter := self add: TextPresenter new name: 'textField'. varPresenter2 := self add: TextPresenter new name: 'textLabel'. model: aSimpleModel super model: aSimpleModel. varPresenter model: (aSimpleModel aspectValue: #var). varPresenter2 model: ((aSimpleModel aspectValue: #var) aspectTriggers: #varChanged). [snipped] > I know it's only an example but I think your code is also slightly dangerous > in that it relies on a third party to change the value in the model. I > would tend to code it like (just the changes) [snipped] Thank you. |
Sergei,
> It does not seem that Model parent plays any role in this case. > When can I use Object instead of Model? You can always use Object instead of Model as a superclass. Model is really just a convenient place to add domain objects so they are a bit more obvious, but it does also have a couple of code changes. - #new automatically calls an instance side #initialize method - As Model's will often trigger events (as part of MVP) the event collection for Model subclasses is maintained in a more efficient way - in an instance variable rather than in a Dictionary. Triggering an event from a Model subclass is therefore slightly faster than one from an Object subclass. Regards Ian |
Free forum by Nabble | Edit this page |