473,399 Members | 3,832 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,399 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 8757
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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
by: adrian | last post by:
hi all this is my first post to this group, so pls bear with me while i try to make some sense. i am trying to create a sproc which uses dynamic sql to target a particuar table eg. '.' and...
12
by: Simon Harvey | last post by:
Whato chaps, I work (or am hoping to work! :) for a company that specialises in the following: - Localisation of media - including software, manuals, literature and training material. -...
2
by: malcolm | last post by:
Hello, We have a robust (.NET 1.1 c# winforms) client-server application that utilizes many typed DataSets, typed DataTables and typed DataRows. Our application is a series of windows and popup...
5
by: Fred | last post by:
Not much expertise on XSLT and trying to understand it's uses when creating apps in VS.NET? If I wanted flexibility on the UI (View aspect of M.V.C.): - How does it compare with creating...
13
by: Stumped and Confused | last post by:
Hello, I really, really, need some help here - I've spent hours trying to find a solution. In a nutshell, I'm trying to have a user input a value in form's textfield. The value should then be...
7
by: narayana | last post by:
hi friends, i want to create a procedure like when i give a name as parameter to the procedure it should create a table with that name and with two column names as any type. plz explain it with...
122
by: Edward Diener No Spam | last post by:
The definition of a component model I use below is a class which allows properties, methods, and events in a structured way which can be recognized, usually through some form of introspection...
2
by: cjard | last post by:
Suppose: A TextBox is bound to a BindingSource, which is bound to a DataTable A BindingNavigator is used to alter the current row being looked at by the BindingSource (i.e. Nav's NEXT button is...
18
by: Angus | last post by:
Hello We have a lot of C++ code. And we need to now create a library which can be used from C and C++. Given that we have a lot of C++ code using classes how can we 'hide' the fact that it is...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

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.