472,119 Members | 2,059 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,119 software developers and data experts.

Using MVC when the model is dynamic

Hi, I have a couple of general requests for pointers to python
examples and design advice.

I'm looking for examples of MVC-based GUI controls done in python
(model-view-controller).

Also, examples where something like a simulation model running in its
own thread sends fast updates to a GUI in near real-time. The only
examples I've seen, such as SimPy, wait until the model is finished
running before outputting data.

Most MVC controls I see in java for example are only designed for
infrequent user-driven changes, like resizing a window or mouse
clicks, not cases where the underlying model is changing itself over
time.
Jul 18 '05 #1
7 8556
pysim wrote:
Hi, I have a couple of general requests for pointers to python
examples and design advice.

I'm looking for examples of MVC-based GUI controls done in python
(model-view-controller).

Also, examples where something like a simulation model running in its
own thread sends fast updates to a GUI in near real-time. The only
examples I've seen, such as SimPy, wait until the model is finished
running before outputting data.

Most MVC controls I see in java for example are only designed for
infrequent user-driven changes, like resizing a window or mouse
clicks, not cases where the underlying model is changing itself over
time.


Here's a baroque example. Maybe it will inspire others to respond
with something more concise :)

The attached example app has a text-based "GUI", as I wanted it to
be more or less self-contained. The app prints a sinusoidal
line of "#"s, until you type "q" and hit return. E.g.

#
#
#
#
#
#
#
#
#
#
#
#
....

The classes in the example include:

Observable -- maintains a set of observers, notifying them whenever
the value of the Observable changes.

Model -- runs a simple computation in a background thread. The
Model's state is an Observable.

View -- displays a model's state as shown above. Also processes
keyboard input, looking for a line starting with 'Q' or 'q' as
a shutdown request.

App -- acts like a controller, but also includes the application's
main event loop, which blocks until keyboard input is available.
The Model and View know nothing about each other. The
App glues them together; it tells the View to update whenever
the Model state changes. It also routes user input (keyboard
input, in this case) to the View. This is a common way
to build MVC applications, and it addresses your concern about
controls which are designed only for user-driven changes.
There's a lot of synchronization overhead in updating the view.
If you have lots of views on the same model, or if your views
take a long time to pain, performance and responsiveness will
suffer. In such cases it might be good to have the model publish
its state only at regular intervals -- store its current state
in a protected attribute and only occasionally copy that state
into an Observable.

Or, if you want to write really baroque code (like me,
apparently :) you could use a "delayed" Observable which
propagates model state changes at low rates. For example, the
model might publish its state using an instance of this
(untested) class:

class DelayedObservable(Observable):
...
def __init__(self, notifyInterval=1.0):
self._tLastChange = time.time()
self._notifyInterval = notifyInterval # Seconds

def _notify(self, force=0):
dt = time.time() - self._tLastChange
if force or (dt >= self._notifyInterval):
for observer in self._observers:
...
self._tLastChange = time.time()
This is all pretty verbose, but maybe it will be helpful.

For better ideas on limiting the rate of propagation of model
state changes, it might be good to look at the documentation
for NSNotificationQueue. It's part of the Cocoa framework of
Mac OS X.

--
Mitch

#!/usr/bin/env python
"""Demo a basic MVC app structure in which
The model is a simulation running in its own thread.
The model undergoes frequent, View-able state changes
"""

import sys, sets, threading, select, math
class Observable(object):
"""An Observable notifies its observers whenever its value changes.
Observers are just Python callables having the signature
callMe(sender)

Lots of MT-safe overhead, here. So...
TO DO: Demonstrate asynchronous, coalesced notifications."""
def __init__(self):
self._observers = sets.Set()
self._lock = threading.RLock()
self._value = None

def addObserver(self, newObserver):
self._observers.add(newObserver) # This oughtta be locked...

def removeObserver(self, anObserver):
self._observers.remove(anObserver) # This oughtta be locked...

def _notify(self):
for observer in self._observers: # This oughtta be locked...
try:
observer(self)
except:
pass # Don't let one broken observer gum up everything

def _getValue(self):
self._lock.acquire()
result = self._value
self._lock.release()
return result

def _setValue(self, newValue):
self._lock.acquire()
self._value = newValue
self._lock.release()
self._notify()

value = property(_getValue, _setValue, None, "The observable value")
class Model(threading.Thread):
"""Computes new values asynchronously. Notifies observers whenever
its state changes."""
def __init__(self, **kw):
threading.Thread.__init__(self, **kw)
self._stopped = 0
self._state = Observable()

def onStateChange(self, observer):
self._state.addObserver(observer)

def removeStateChange(self, observer):
self._state.removeObserver(observer)

def run(self):
"""Run the model in its own thread."""
self._stopped = 0
i = 0.0
di = math.pi / 8.0
while not self._stopped:
self._state.value = math.sin(i)
i += di

def stop(self):
self._stopped = 1
class View:
"""Dummy 'view' just prints the model's current value whenever
that value changes, and responds to keyboard input."""
def __init__(self):
self._onQuitCB = None

def modelStateChanged(self, modelState):
valueBar = " " * int((1 + modelState.value) * 10)
print "%s#" % valueBar

def onQuit(self, newOnQuitCB):
self._onQuitCB = newOnQuitCB

def handleInput(self, userInput):
if userInput.lower().startswith("q"):
if self._onQuitCB:
self._onQuitCB(self)
class App:
"""This sample application computes and displays garbage, at
a high rate of speed, until the user quits."""
def __init__(self):
# Yep, this is really a controller and not just an app runner.
self._model = Model()
self._view = View()
self._terminated = 0

self._model.onStateChange(self._view.modelStateCha nged)
self._view.onQuit(self._quitApp)

def run(self):
self._model.start()

self._terminated = 0
while not self._terminated:
ins, outs, errs = select.select([sys.stdin], [], [])
if ins:
self._view.handleInput(raw_input())

self._model.join()

def _quitApp(self, *args):
self._terminated = 1
self._model.stop()
self._model.removeStateChange(self._view.modelStat eChanged)
def main():
"""Module mainline (for standalone execution)"""
theApp = App()
theApp.run()

if __name__ == "__main__":
main()

Jul 18 '05 #2
Mitch Chapman wrote:
Model -- runs a simple computation in a background thread. The
Model's state is an Observable.

View -- displays a model's state as shown above. Also processes
keyboard input, looking for a line starting with 'Q' or 'q' as
a shutdown request.

App -- acts like a controller, but also includes the application's
main event loop, which blocks until keyboard input is available.
The Model and View know nothing about each other. The
App glues them together; it tells the View to update whenever
the Model state changes. It also routes user input (keyboard
input, in this case) to the View. This is a common way
to build MVC applications, and it addresses your concern about
controls which are designed only for user-driven changes.


Hi Mitch :) Note that Mitch's example won't work on windows since you
can't use select on stdin (only sockets).

I have been playing with two approaches to this issue of dynamically
changing events from a model.

1) I've recently become a fan of using the GUI's native events to
control state from the model to the view. They are thread-safe and easy
to implement. wxPython has a good example in their demo of doing this.
See the Threads entry of "Process and Events"

Model -> state is an observable ->| generates an event |<- View responds

when the observable is altered a GUI event is posted through the
callback scheme. The gui can then asynchronously respond to changes in
states. Warning: sometimes multiple instances of the same event
handler can be run simultaneously so be careful here. I usually prevent
this through some locking mechanism.

This is pretty much the same as Mitch's example except the observable is
decoupled from the View through the event mechanism. I expect the same
could be accomplished using a Queue and a timer.

2) Spawn an independent process and simply monitor the processes
standard output and respond accordingly. See the LongRunningTasks entry
on http://staffa.wi.mit.edu/people/kelley

Both of these gloss over the issue of how does the view talk to the
model. The only real answer I have is polling. The model must
occasionally poll for new instructions from the view or have it's own
event-style manager.

Brian Kelley

Jul 18 '05 #3
In article <3f*********************@senator-bedfellow.mit.edu>,
Brian Kelley <bk*****@wi.mit.edu> wrote:
Jul 18 '05 #4
Cameron Laird wrote:
Both of these gloss over the issue of how does the view talk to the
model. The only real answer I have is polling. The model must
occasionally poll for new instructions from the view or have it's own
event-style manager.

Was an interest for fast communications from user to model
desired? Or was the question solely along the lines of, is
there an architecture that'll permit the View to keep up
with the Model more-or-less in real time?


You are correct in what the original poster wanted (i.e. is
there an architecture that'll permit the View to keep up
with the Model more-or-less in real time). I was just being pedantic :)

Brian

Jul 18 '05 #5
Brian Kelley wrote:
Cameron Laird wrote:
Both of these gloss over the issue of how does the view talk to the
model. The only real answer I have is polling. The model must
occasionally poll for new instructions from the view or have it's own
event-style manager.

Was an interest for fast communications from user to model
desired? Or was the question solely along the lines of, is
there an architecture that'll permit the View to keep up
with the Model more-or-less in real time?

You are correct in what the original poster wanted (i.e. is
there an architecture that'll permit the View to keep up
with the Model more-or-less in real time). I was just being pedantic :)


Hi Brian :)

I'm confused by the comments about the model needing to poll for new
instructions from the view. (BTW does this mean you usually prefer to
combine view and controller responsibilities in a single entity, rather
than implement them separately?)

Why not just have the model provide control methods which clients can
invoke directly (t. ex. the stop() method in the example I posted)?
Are you saying this doesn't fit well in wxPython, that it's more
natural in that environment to communicate via event codes and queues?

If that's the case, can you define a model-controller class which
receives view events and translates them into method invocations on
an associated model? That does seem like a lot of work, but it
would let the model remain ignorant of -- loosely coupled to --
its observers.

--
Mitch

Jul 18 '05 #6
In article <Yk******************@newsread4.news.pas.earthlink .net>,
Mitch Chapman <mi**********@earthlink.net> wrote:
Jul 18 '05 #7
Cameron Laird wrote:
In article <Yk******************@newsread4.news.pas.earthlink .net>,
Mitch Chapman <mi**********@earthlink.net> wrote:
I'm confused by the comments about the model needing to poll for new
instructions from the view. (BTW does this mean you usually prefer to
combine view and controller responsibilities in a single entity, rather
than implement them separately?)


Maybe when I say polling it is a symantic issue, but in your run method:

def run(self):
"""Run the model in its own thread."""
self._stopped = 0
i = 0.0
di = math.pi / 8.0
while not self._stopped:
self._state.value = math.sin(i)
i += di

isn't "while not self._stopped" a method of polling? This variable is
still set asynchronously. This is the only point that I was getting at,
for example if you had many states in your model that can be altered,
you still need to periodically check to affect these state changes.
If that's the case, can you define a model-controller class which
receives view events and translates them into method invocations on
an associated model? That does seem like a lot of work, but it
would let the model remain ignorant of -- loosely coupled to --
its observers.


Yes. This is actually what I do. I still consider this in the realm of
polling though (note that I am talking about receiving the model change
event and converting it to a method invocation here). Using the normal
threading model the polling is hidden as in your example, i.e. keep
checking to see if self._stopped is true.

Perhaps polling is not the proper way to talk about this. But, tt helps
my mental picture of what is going on though in that "at any time there
could be a state change so if you are interested in it, keep checking
for the change." This mental picture works (for me at least) when
running the model in a thread or running the model in another process.

Brian.

Jul 18 '05 #8

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

5 posts views Thread by Fred | last post: by
13 posts views Thread by Stumped and Confused | last post: by
122 posts views Thread by Edward Diener No Spam | last post: by
reply views Thread by leo001 | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.