Organizing Widget-Bound Methods

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,", "Open," 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

···

--
Richard B. Shepard, Ph.D. | The Environmental Permitting
Applied Ecosystem Services, Inc.(TM) | Accelerator
<http://www.appl-ecosys.com> Voice: 503-667-4517 Fax: 503-667-8863

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,", "Open," 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 OnNew(self, event):
  DB_Module.OpenNew()

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:

OpenNewButton.Bind(EVT_BUTTON, DB_Module.OpenNew)

In this case, make sure that DB_Module.OpenNew() 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_Module.OpenNew() function needs to now what page was active when it was invoked, etc. etc.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                         
NOAA/OR&R/HAZMAT (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

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 OnNew(self, event):
  DB_Module.OpenNew()

   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:

OpenNewButton.Bind(EVT_BUTTON, DB_Module.OpenNew)

In this case, make sure that DB_Module.OpenNew() 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_Module.OpenNew() 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

···

On Tue, 24 Oct 2006, Christopher Barker wrote:

--
Richard B. Shepard, Ph.D. | The Environmental Permitting
Applied Ecosystem Services, Inc.(TM) | Accelerator
<http://www.appl-ecosys.com> Voice: 503-667-4517 Fax: 503-667-8863

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

···

On Tue, 24 Oct 2006, Christopher Barker wrote:

1) have the event handlers be very simple functions like:

def OnNew(self, event):
  DB_Module.OpenNew()

--
Richard B. Shepard, Ph.D. | The Environmental Permitting
Applied Ecosystem Services, Inc.(TM) | Accelerator
<http://www.appl-ecosys.com> Voice: 503-667-4517 Fax: 503-667-8863

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.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

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

···

On Tue, 24 Oct 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.

--
Richard B. Shepard, Ph.D. | The Environmental Permitting
Applied Ecosystem Services, Inc.(TM) | Accelerator
<http://www.appl-ecosys.com> Voice: 503-667-4517 Fax: 503-667-8863

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

···

On Tue, Oct 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.

--
GPG key ID E4071346 @ wwwkeys.pgp.net
E167 67FD A291 2BEA 73BD 4537 78B9 A9F9 E407 1346