Organizing Widget-Bound Methods
6 answers - 1471 bytes -

After yesterday's thread I understand that methods bound to a wxPython
widget must be in the same file as the class where the widget is defined and
declared. Now I need guidance on how to provide the same functionality
that's defined in two different source files. I'll explain.
My modeling application's UI uses notebook pages, with each page in a
separate *.py file. There's also the main frame's file.
When the application is invoked, it's necessary to create a new model
(held in a SQLite3 database) or open an existing model. And, of course,
models can be saved and closed, too. These functions are available in three
ways:
1) From the File menu (in the main frame .py file).
2) By typing the file name in the text control widget (in the notebook
page's .py file).
3) By clicking on the "New,", "," or "Save" buttons (also in the
notebook page's .py file).
I'd like to have a single method/function to process each type of action,
regardless of which route is chosen by the user. That way, a change (or
error correction) is made in one place and I don't have database creation
code in multiple modules.
Is this an ideal case for use of the model-view-controller paradigm? If
so, I better re-read that chapter in wPIA and re-organize all these modules
before writing more methods.
Suggestions, please,
Rich
No.1 | | 1654 bytes |
| 
Rich Shepard wrote:
These functions are available in three
ways:
1) From the File menu (in the main frame .py file).
2) By typing the file name in the text control widget (in the notebook
page's .py file).
3) By clicking on the "New,", "," or "Save" buttons (also in the
notebook page's .py file).
I'd like to have a single method/function to process each type of action,
regardless of which route is chosen by the user. That way, a change (or
error correction) is made in one place and I don't have database creation
code in multiple modules.
It sounds like the database is a application-global concept, so you're
right, there should be one place where it gets manipulated. I'd put all
that code in a single module.
Now each notebook page can import than module, and they'll all be taking
to the same thing.
You now have two choices:
1) have the event handlers be very simple functions like:
def New(self, event):
DB_MNew()
2) or, as I alluded to before, you don't' actually HAVE to put event
handlers in the same file as the wx.Panel (or whatever) class. You just
have to make sure that you reference the function properly:
NewButton.Bind(EVT_BUTTN, DB_MNew)
In this case, make sure that DB_MNew() can take an event as an
argument.
I'd be inclined to do (1), while is looks like extra unnecessary code,
there may well end up being time when it needs to do a bit more, or the
DB_MNew() function needs to now what page was active when it
was invoked, etc. etc.
-Chris
No.2 | | 1791 bytes |
| 
Tue, 24 2006, Christopher Barker wrote:
It sounds like the database is a application-global concept, so you're
right, there should be one place where it gets manipulated. I'd put all
that code in a single module.
Chris,
If I understand correctly, then yes, that's the case. The UI allows for
definition of the model and input of all parameters. Everything's stored in
the database. When the model is run, appropriate data are retrieved from the
database and manipulated while the progress and results are displayed in the
UI.
Now each notebook page can import than module, and they'll all be taking to
the same thing.
You now have two choices:
1) have the event handlers be very simple functions like:
def New(self, event):
DB_MNew()
Let me try this approach. I may not have done it correctly before, or I
had in there event handlers that should not have been in there.
2) or, as I alluded to before, you don't' actually HAVE to put event
handlers in the same file as the wx.Panel (or whatever) class. You just
have to make sure that you reference the function properly:
NewButton.Bind(EVT_BUTTN, DB_MNew)
In this case, make sure that DB_MNew() can take an event as an
argument.
I think I did not have the DB_Module file correctly constructed.
I'd be inclined to do (1), while is looks like extra unnecessary code, there
may well end up being time when it needs to do a bit more, or the
DB_MNew() function needs to now what page was active when it was
invoked, etc. etc.
Your advice is appreciated. I'll let you know if I stumble or if I have it
working smoothly.
Many thanks,
Rich
No.3 | | 336 bytes |
| 
Tue, 24 2006, Christopher Barker wrote:
1) have the event handlers be very simple functions like:
def New(self, event):
DB_MNew()
Chris,
Now that I see how this is working, it all makes sense. I think that my
previous attempt took the worst attributes from both approaches.
Thanks,
Rich
No.4 | | 928 bytes |
| 
Christopher Barker wrote:
2) or, as I alluded to before, you don't' actually HAVE to put event
handlers in the same file as the wx.Panel (or whatever) class. You just
have to make sure that you reference the function properly:
Just to clairify this a little bit more: You can just as easily bind
event handlers that are methods of another instance, top-level functions
in some other module, or even callable objects. The only requirement
for event handlers is that they are callable objects that can accept an
event parameter. In other words, if it's visible from the point where
you are doing the Bind (it's either in the same class or module, or has
been imported from another module, or passed as a parameter into this
method or is available as an attribute of this class, etc.) and is
callable with a single parameter, then it can be bound as an event handler.
No.5 | | 1003 bytes |
| 
Tue, 24 2006, Robin Dunn wrote:
Just to clairify this a little bit more: You can just as easily bind event
handlers that are methods of another instance, top-level functions in some
other module, or even callable objects. The only requirement for event
handlers is that they are callable objects that can accept an event
parameter. In other words, if it's visible from the point where you are
doing the Bind (it's either in the same class or module, or has been
imported from another module, or passed as a parameter into this method or
is available as an attribute of this class, etc.) and is callable with a
single parameter, then it can be bound as an event handler.
Thank you for the clarification, Robin. My problems almost certainly arose
because I was not calling the handlers properly.
The indirect method that Chris suggested is working in my application, so
I'll stick with that for now.
Much appreciated,
Rich
No.6 | | 442 bytes |
| 
Tue, 24, 2006 at 03:16:58PM -0700, Robin Dunn wrote:
In other words, if it's visible from the point where
you are doing the Bind and is
callable with a single parameter, then it can be bound as an event handler.
Good to know. I have always wondered whether I can name
event handlers like __on_something_happened(). It seems I
can as long as it can be resolved properly at Bind() time.
Thanks,
Karsten