Discussion:
wxPython and MVC
Mark Erbaugh
2007-12-02 22:15:27 UTC
Permalink
I'm trying to develop applications along the lines of
model-view-controller design.

I think the frame class is the view portion. However, the event handling
routines are part of the controller. How do people separate them?

What I've been doing is writing "stub" event handlers for each event
that basically just pass the event off to a controller object, if one
exists.


# in view
def onClick(self, event):
if self.controller:
self.controller.onClick(self, event)

# in controller
def onClick(self, view, event):
# here view gives the controller access to the view object
# (GUI frame instance)

Is there a better way?

Also, my concept of the controller is that it is independent of the
mechanism used to provide the GUI, so I don't want to import wx into it.
That means that sometimes end up writing more code in the GUI. For
example, if the controller needs to display a dialog box, I have a
method in the GUI frame to do that. The controller can then access the
dialog using this method on the GUI frame. It gets the GUI frame's
instance as the first parameter of its event handling code.

Thanks,
Mark
Pan Xingzhi
2007-12-03 03:32:28 UTC
Permalink
Hi Mark,

The controller must know something about the view, so it can update the
view according to the model.
However I'm not sure with the "stub" thing you wrote. What's the good
out of that? Why can't we just bind some function in the controller as event
handlers?

Cheers,
Harry Pan
Post by Mark Erbaugh
I'm trying to develop applications along the lines of
model-view-controller design.
I think the frame class is the view portion. However, the event handling
routines are part of the controller. How do people separate them?
What I've been doing is writing "stub" event handlers for each event
that basically just pass the event off to a controller object, if one
exists.
# in view
self.controller.onClick(self, event)
# in controller
# here view gives the controller access to the view object
# (GUI frame instance)
Is there a better way?
Also, my concept of the controller is that it is independent of the
mechanism used to provide the GUI, so I don't want to import wx into it.
That means that sometimes end up writing more code in the GUI. For
example, if the controller needs to display a dialog box, I have a
method in the GUI frame to do that. The controller can then access the
dialog using this method on the GUI frame. It gets the GUI frame's
instance as the first parameter of its event handling code.
Thanks,
Mark
---------------------------------------------------------------------
Mark Erbaugh
2007-12-03 03:46:43 UTC
Permalink
Post by Pan Xingzhi
Hi Mark,
The controller must know something about the view, so it can
update the view according to the model.
However I'm not sure with the "stub" thing you wrote. What's the
good out of that? Why can't we just bind some function in the
controller as event handlers?
Cheers,
Harry Pan
I'm trying to develop applications along the lines of
model-view-controller design.
I think the frame class is the view portion. However, the event handling
routines are part of the controller. How do people separate them?
What I've been doing is writing "stub" event handlers for each event
that basically just pass the event off to a controller object, if one
exists.
# in view
self.controller.onClick(self, event)
# in controller
# here view gives the controller access to the view object
# (GUI frame instance)
Is there a better way?
Also, my concept of the controller is that it is independent of the
mechanism used to provide the GUI, so I don't want to import wx into it.
That means that sometimes end up writing more code in the GUI. For
example, if the controller needs to display a dialog box, I have a
method in the GUI frame to do that. The controller can then access the
dialog using this method on the GUI frame. It gets the GUI frame's
instance as the first parameter of its event handling code.
Thanks,
Mark
Harry,

Thanks for the reply. After reading more about wxPython event handling,
I'm experimenting with that approach now and it looks like it may work.
I agree that the controller will have to know something about the view
so I added a 'view' data member to the controller object. However, the
controller object only accesses specific methods in the view object, it
doesn't directly access wxPython features.

For example, to populate a wxListBox, the controller would call a method
view.setListBox(data). The method in the view class would then call the
appropriate wxPython method (or methods) to populate the list box.

This way, if I would ever use a different GUI object, such as a
web-based interface, it would only have to implment a setListBox(data)
method and I could use the same controller. Ideally, the same program
could run with a desktop interface with wxPython, or even Tkinter) or a
web-based interface.

Mark
Pan Xingzhi
2007-12-03 04:59:53 UTC
Permalink
Mark,

Normally people regard things like wx widgets and web pages as view.
What you're doing is adding another abstract layer between controller and
view (the 'view' data member in the controller object), so ideally you may
change the view without affecting the controller. However, in most cases the
controller is allowed to be coupled with view (maybe except for the web
development, where view and controller may not even reside on the same
machine). Think about this: even if you apply the 'view' data member, you
still have to modify it if you change the UI from wx to web. So is it really
necessary to encapsulate this modification in this 'view' data member rather
than just modifying the controller?

That depends on how much you need on changing the face of your software
;-) But my suggestion is, don't overdo it. A lot of people tend to invent
"imaginary requirement" and then find themselves devoting 80% effort on 20%
(or less) of the functionalities.

You don't even need to make controller an object. Python doesn't force
this, neither does wx. In my opinion, a set of functions in a Python module
is enough. My point is that, the controller rarely has its own state, and
its job is to manipulate model and view rather than providing APIs to change
itself. OO gains little benefits here.

Cheers,
Harry Pan
Post by Mark Erbaugh
Post by Pan Xingzhi
Hi Mark,
The controller must know something about the view, so it can
update the view according to the model.
However I'm not sure with the "stub" thing you wrote. What's the
good out of that? Why can't we just bind some function in the
controller as event handlers?
Cheers,
Harry Pan
I'm trying to develop applications along the lines of
model-view-controller design.
I think the frame class is the view portion. However, the
event handling
routines are part of the controller. How do people separate them?
What I've been doing is writing "stub" event handlers for each event
that basically just pass the event off to a controller object, if one
exists.
# in view
self.controller.onClick(self, event)
# in controller
# here view gives the controller access to the view object
# (GUI frame instance)
Is there a better way?
Also, my concept of the controller is that it is independent of the
mechanism used to provide the GUI, so I don't want to import
wx into it.
That means that sometimes end up writing more code in the GUI. For
example, if the controller needs to display a dialog box, I have a
method in the GUI frame to do that. The controller can then access the
dialog using this method on the GUI frame. It gets the GUI frame's
instance as the first parameter of its event handling code.
Thanks,
Mark
Harry,
Thanks for the reply. After reading more about wxPython event handling,
I'm experimenting with that approach now and it looks like it may work.
I agree that the controller will have to know something about the view
so I added a 'view' data member to the controller object. However, the
controller object only accesses specific methods in the view object, it
doesn't directly access wxPython features.
For example, to populate a wxListBox, the controller would call a method
view.setListBox(data). The method in the view class would then call the
appropriate wxPython method (or methods) to populate the list box.
This way, if I would ever use a different GUI object, such as a
web-based interface, it would only have to implment a setListBox(data)
method and I could use the same controller. Ideally, the same program
could run with a desktop interface with wxPython, or even Tkinter) or a
web-based interface.
Mark
Mark Erbaugh
2007-12-03 13:46:05 UTC
Permalink
Harry,

Thank you for your comments. You have given me somethings to think
about.
Post by Pan Xingzhi
Normally people regard things like wx widgets and web pages as
view. What you're doing is adding another abstract layer between
controller and view (the 'view' data member in the controller object),
so ideally you may change the view without affecting the controller.
However, in most cases the controller is allowed to be coupled with
view (maybe except for the web development, where view and controller
may not even reside on the same machine). Think about this: even if
you apply the 'view' data member, you still have to modify it if you
change the UI from wx to web. So is it really necessary to encapsulate
this modification in this 'view' data member rather than just
modifying the controller?
In this design, the 'view' data member is simply a reference to the
wxFrame instance. The methods that store and retrieve data from the
wxFrame instance are just members of that object.
Post by Pan Xingzhi
That depends on how much you need on changing the face of your
software ;-) But my suggestion is, don't overdo it. A lot of people
tend to invent "imaginary requirement" and then find themselves
devoting 80% effort on 20% (or less) of the functionalities.
A very good point. I have a tendency to over-engineer things and to
spend too much time creating an elegant solution to something that never
becomes a problem.
Post by Pan Xingzhi
You don't even need to make controller an object. Python doesn't
force this, neither does wx. In my opinion, a set of functions in a
Python module is enough. My point is that, the controller rarely has
its own state, and its job is to manipulate model and view rather than
providing APIs to change itself. OO gains little benefits here.
Something to think about. I had assumed that the controller would keep
track of the current record and implement calls to a generic model
object. There would be only one instance of the model for a given screen
regardless of the number different instances of the same screen (each
with its own controller instance).

Thanks again,
Mark
Peter Decker
2007-12-03 13:10:31 UTC
Permalink
Post by Mark Erbaugh
I'm trying to develop applications along the lines of
model-view-controller design.
I think the frame class is the view portion. However, the event handling
routines are part of the controller. How do people separate them?
I think that the n-tier approach in Dabo is superior to MVC. The GUI
controls defer the logic to the business objects, and the results of
those business object methods (either modified values or raised
exceptions) are then reflected back in the GUI.

Events are necesarily at the UI level, so I usually have event handler
code in the UI that looks like:

def onSomeEvent(self, evt):
self.PrimaryBizobj.doSomethingAboutTheEvent(evt)

If you are familiar with Design Patterns, this arrangement is the
Chain of Responsibilty pattern, in which objects either handle the
action themselves, or defer it up the chain where it will reach the
object that is responsible for dealing with the event or action.
--
# p.d.
Fabrizio Pollastri
2007-12-03 13:31:49 UTC
Permalink
Just a contribution to the discussion.
I developed an alternative to MVC, you can see it here
http://avc.inrim.it/, widgets and application variables are connected
together automatically matching widgets names with variables names.
In these days, I am porting AVC to wx.

--
Cheers,
F. Pollastri
Mark Erbaugh
2007-12-03 14:03:22 UTC
Permalink
Post by Fabrizio Pollastri
Just a contribution to the discussion.
I developed an alternative to MVC, you can see it here
http://avc.inrim.it/, widgets and application variables are connected
together automatically matching widgets names with variables names.
In these days, I am porting AVC to wx.
Fabrizio,

Thanks.

I'm having trouble accessing the user manual from the website. I'm
getting a not found error.

Mark
Fabrizio Pollastri
2007-12-03 14:09:21 UTC
Permalink
Post by Mark Erbaugh
Post by Fabrizio Pollastri
Just a contribution to the discussion.
I developed an alternative to MVC, you can see it here
http://avc.inrim.it/, widgets and application variables are connected
together automatically matching widgets names with variables names.
In these days, I am porting AVC to wx.
Fabrizio,
Thanks.
I'm having trouble accessing the user manual from the website. I'm
getting a not found error.
Oops!
Now, it is on line again.
Robin Dunn
2007-12-03 20:09:19 UTC
Permalink
Post by Mark Erbaugh
I'm trying to develop applications along the lines of
model-view-controller design.
Just in case you haven't seen it yet:
http://wiki.wxpython.org/wxPython_Patterns
--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!
Mark Erbaugh
2007-12-03 20:20:43 UTC
Permalink
Post by Robin Dunn
http://wiki.wxpython.org/wxPython_Patterns
Robin,

I hadn't seen that, but it should be useful.

Thanks,
Mark
jonhattan
2007-12-06 11:09:40 UTC
Permalink
Hi Mark,

I've a design based on MVP, Model-View-Presenter --there's some about
mvp in the wiki.

I think my approach can help to achive your requirements, but it will
take a bit long for me to explain it --and english is not my first
lang--. Let's try:

The MVP is a modification of MVC where the Presenter is similar to the
Controller, and there's another component, the Interactor.

The Presenter talks to the model, the interactor and the view. There's
no direct comunication between model and view.

The interactor is where you do the event binding and handling. So the
Presenter is totally clean of wx code. I see the interactor as a bridge
between UI events and the presenter. Based on events, the interactor
tells the presenter what has happened in a higher level abstraction
layer (ie. ther presenter does not know anything about wx events).

I use wx.App as the view component, with basically two methods to be
called from the presenter: view.create_window(window_id) and
view.show_window(window_id). The window_id is a string referencing a
dialog / frame class.

The interactor exposes only a method to the presenter: install_window(...)

So,

###
#the presenter:
###

win = self.view.create_window(window_id)
self.interactor.install_window(window_id, win)
self.view.show_window(window_id)

###
#the interactor:
###

def install_window(window_id, win):
if window_id == 'address':
win.new.Bind(wx.EVT_BUTTON, self.on_new_address)
#do other bindings
elif window_id == '...':
pass

def on_new_address(self, evt):
self.presenter.goto('new address')

###
#the view:
###

winIds = {'address': 'AddressFrame',
'address_edit': 'AddressDialog',
'another': 'AnotherFrame'}

def create_window(self, window_id, **params):
klassname = windIds[window_id]
klass = getattr(self, klassname)
win = klass(params)
return win

*********
About the model.

The model is another class, as the presenter, interactor and view are.

(I'll expose later why I use classes instead of some functions in a
module, as suggested by Pan Xingzhi)

I started with a reference to the model in my presenter, and doing a
complete MVP iteration as:

data = self.model.get('list', component = window_id)
win.update(data) # almost all of my windows have a update() method
win = self.view.create_window(window_id)
self.interactor.install_window(window_id, win)
self.view.show_window(window_id)

My app is to be used in a intranet environment, with a computer as
database server.
First step, I changed the model to be a server itself, based on python
xml-rpc library -- pretty easy.

But I manage big chunks of data, and calling the model in a blocking way
is not appropiate as the app freezes untill the model returns the data.
On the other hand, while the server is responding a client, other
clients must wait.. so... threads in the server? ey, but there's still a
problem at client side: blocking calls to the model/server.

At this point twistedmatrix came into game.
I use Twisted's Perspective Broker protocol. It allowed me to do async
non blocking calls between both sides ("client" and "server"), so the
server can talk to several clients and the clients can do anything while
the server is preparing data for them --include doing another calls to
the model.

The last thing is using twisted's Cacheables. A cacheable is a object
the resides in the server and is sent to the client. Each time it
changes on the server, clients are notified. It allows me to
automagically update a listing in a client app after another client has
inserted a new register. -- it will be useful to update two or more
frames in the same client as you requested.

A lot more can be said on each of the MVP components (ej, the model is
based on SQLObject, the view provides a battery of validators and custom
widgets,...).

I would like to public release my code but I'ven't had no time to clean
it up. If some of you are interested in it, I'll try to put some efforts
in releasing it on xmas.



-- jonhattan
Post by Mark Erbaugh
Post by Robin Dunn
http://wiki.wxpython.org/wxPython_Patterns
Robin,
I hadn't seen that, but it should be useful.
Thanks,
Mark
---------------------------------------------------------------------
Mark Erbaugh
2007-12-06 13:46:08 UTC
Permalink
Post by jonhattan
I've a design based on MVP, Model-View-Presenter --there's some about
mvp in the wiki.
Jonhatten,

Thank you for your explanation. I had discovered the MVP write up in the
wiki and I am working through it. I noticed that Martin Fowler has
depricated the MVP pattern:

http://martinfowler.com/eaaDev/ModelViewPresenter.html

and replaced it with Supervising Controller and Passive View patterns.
I haven't had time to study this yet.

I think I have essentially implemented the functionality of your
interactor. Currently, it resides as a method in my view (wx.Frame)
class, but I have been thinking of separating it from there. Basically,
the wx.Frame descendent has a method, SetController that takes an
instance of the controller and then binds events from the wx.Frame to
methods in the controller.

One refinement I made was the ability to un-bind the controller before
cleanup. I found a case where, depending on the order that things were
destroyed, an event handler tried to update a widget that had already
been destroyed. Fortunately, I was able to come up with generic
un-binding code that uses the same code as SetController, so the the
un-bind method is generic. That means that you only have to hand-code
the binding of event, you don't have to hand-code the un-binding.

As I mentioned, I've been thinking of moving SetController out of the
wx.Frame class. Actually, I'm thinking of moving the SetController
method to a sub-class of my wx.Frame sub-class. That way it would still
be able to access all the widgets via self. One reason I'm considering
this is I use a GUI design tool (wxGlade) to design the frame. By
splitting SetController and the other hand-coded routines into a
separate file, I can re-run wxGlade and allow it to completely re-write
it's Python output file. With the design I have now, I have to make sure
that wxGlade doesn't overwrite my hand-coded changes.

Mark
Peter Damoc
2007-12-06 14:05:03 UTC
Permalink
There is another twist on the MVP pattern.... Trellis!
Even if it is a little bit young... this piece of software is great...
I've started using it for a piece of my main software and I felt in love
with it...
Now I'm looking at more ways to integrate it because it makes event
management simpler, way simpler.

Documentation for the old version:
http://peak.telecommunity.com/DevCenter/Trellis

New new version (the one from SVN trunk) has some things changed.... but the
previous documentation should provide a clear enough look at what the
library tries to achieve...
An overview of what changed:
http://www.eby-sarna.com/pipermail/peak/2007-November/002812.html

My intuition says that this is going to be used... a lot...

Peter.
Post by Mark Erbaugh
Post by jonhattan
I've a design based on MVP, Model-View-Presenter --there's some about
mvp in the wiki.
Jonhatten,
Thank you for your explanation. I had discovered the MVP write up in the
wiki and I am working through it. I noticed that Martin Fowler has
http://martinfowler.com/eaaDev/ModelViewPresenter.html
and replaced it with Supervising Controller and Passive View patterns.
I haven't had time to study this yet.
I think I have essentially implemented the functionality of your
interactor. Currently, it resides as a method in my view (wx.Frame)
class, but I have been thinking of separating it from there. Basically,
the wx.Frame descendent has a method, SetController that takes an
instance of the controller and then binds events from the wx.Frame to
methods in the controller.
One refinement I made was the ability to un-bind the controller before
cleanup. I found a case where, depending on the order that things were
destroyed, an event handler tried to update a widget that had already
been destroyed. Fortunately, I was able to come up with generic
un-binding code that uses the same code as SetController, so the the
un-bind method is generic. That means that you only have to hand-code
the binding of event, you don't have to hand-code the un-binding.
As I mentioned, I've been thinking of moving SetController out of the
wx.Frame class. Actually, I'm thinking of moving the SetController
method to a sub-class of my wx.Frame sub-class. That way it would still
be able to access all the widgets via self. One reason I'm considering
this is I use a GUI design tool (wxGlade) to design the frame. By
splitting SetController and the other hand-coded routines into a
separate file, I can re-run wxGlade and allow it to completely re-write
it's Python output file. With the design I have now, I have to make sure
that wxGlade doesn't overwrite my hand-coded changes.
Mark
---------------------------------------------------------------------
--
There is NO FATE, we are the creators.
jonhattan
2007-12-06 15:50:32 UTC
Permalink
Post by Mark Erbaugh
Post by jonhattan
I've a design based on MVP, Model-View-Presenter --there's some about
mvp in the wiki.
Jonhatten,
Thank you for your explanation. I had discovered the MVP write up in the
wiki and I am working through it. I noticed that Martin Fowler has
http://martinfowler.com/eaaDev/ModelViewPresenter.html
and replaced it with Supervising Controller and Passive View patterns.
I haven't had time to study this yet.
This is the original draft of MVP, by Taligent, a subsidiary of IBM.
http://www.wildcrest.com/Potel/Portfolio/mvp.pdf

I see Both Supervising Controller & Passive View as flavours of MVP.
That is, sometimes the presenter controls the view to the widget level
(Passive View), sometimes, the view takes control over the view logic
and the presenter acts at a higher abstraction level.

What I use to do is:

1) what I call "local bindings" (a bind done in the view itself)... to
manage some basic logic. Ej: change the available options of a widget
based on the value of other: if sex.GetValue() == 'male':
kinships.SetValues('father', 'brother', 'son') else:
kinships.SetValues('mother', 'sister', 'daughter')

2) Let the Presenter do the more complex operations, instructed by the
event binding in the Interactor. As an example, after "country
selection" in the View, the Interactor ask the Presenter to provide the
View with the states of given country (the Presenter will ask the Model
and when data is available, notify the corresponding window).

It naturally seems 1) is more like a Supervising Controller, 2) more as
a Passive View. I haven't read deeply on SC and PV, but I feel
comfortable with my rule of not letting the Presenter do trivial stuff
on the View, and let the View do as much as it can in it's own concern
with the available metadata.


-- jonhattan
Post by Mark Erbaugh
I think I have essentially implemented the functionality of your
interactor. Currently, it resides as a method in my view (wx.Frame)
class, but I have been thinking of separating it from there. Basically,
the wx.Frame descendent has a method, SetController that takes an
instance of the controller and then binds events from the wx.Frame to
methods in the controller.
One refinement I made was the ability to un-bind the controller before
cleanup. I found a case where, depending on the order that things were
destroyed, an event handler tried to update a widget that had already
been destroyed. Fortunately, I was able to come up with generic
un-binding code that uses the same code as SetController, so the the
un-bind method is generic. That means that you only have to hand-code
the binding of event, you don't have to hand-code the un-binding.
As I mentioned, I've been thinking of moving SetController out of the
wx.Frame class. Actually, I'm thinking of moving the SetController
method to a sub-class of my wx.Frame sub-class. That way it would still
be able to access all the widgets via self. One reason I'm considering
this is I use a GUI design tool (wxGlade) to design the frame. By
splitting SetController and the other hand-coded routines into a
separate file, I can re-run wxGlade and allow it to completely re-write
it's Python output file. With the design I have now, I have to make sure
that wxGlade doesn't overwrite my hand-coded changes.
Mark
Loading...