Peter Herndon wrote:
For an auto-updating monitoring application, run a timer, when it
expires check the values of the data, then update the GUI control
values. Lather, rinse, repeat. I seem to recall running across an
event specifically for that purpose (wx.EVT_UPDATE_UI). At least, I
*think* that's what it is for, I can't seem to find any documentation
on it for use in Python, but the wxWidgets reference has some stuff on
it.Has anyone else had occasion to work on this kind of problem?
I am not sure if my situation is the same as Andrew's, but FWIW this is how
I do it.
My application is database intensive. Most of my windows are made up of
widgets (usually wx.TextCtrl) which contain data from a particular column
from a particular row from the database.
For each table used for a particular window, I create an instance of a
'table' class, and for each column in the table I create multiple instances
of a 'column' class. Each column instance has a 'data' attribute that
contains the value of that column for the current row. Every text control
must point to a specific column instance, but not every column instance
necessarily has its own text control.
It used to work as follows. When a row is 'selected' from the database, I
populate the data attribute for each column, and then loop through all the
controls on the window, telling them to refresh themselves from their
associated column instance. If the user changes the value in the control, I
update the data attribute for the relevant column, so that the database can
be updated with the new value if the user selects 'Save'.
I had a problem. If I change a data attribute for some reason other than
user input, I need to check if there is an associated text control, and if
so, refresh the value. As my screens were getting more complex, my logic was
getting more and more tortuous.
My solution was to turn the problem on its head. Now, as I create each
control, it calls a method of its associated column instance, and passes it
'self'. The column instance adds 'self' to a list, so it knows which
control(s) are linked to it. Now every time a column's data attribute is
changed, I loop through the list, and call a refresh method on each control,
passing it the data value, telling it to redraw itself (eg using
SetValue() ). This has transformed my application, as the windows now
maintain themselves.
I will give one example of how this has made my life easier. For most
database tables, I show a 'list view' (using wx.Grid), and a 'form view',
using a panel on a wx.Dialog. Initially I display the contents of the table
using the list view, using only a subset of the available columns. If the
user clicks a particular button, I display a form view of the current row,
which is laid out with controls representing all the columns. Normally the
form view overlays the list view, but if you manually move the two windows,
you can see the list view and the form view side-by-side. Now if you are in
form view, and change a value which happens to be visible on the list view,
the value on the list view changes automatically. I was quite surprised when
I saw this happening, because I had never tried to code for this in the
first place. It was just a natural consequence of my new approach.
One minor complication is that, if the user closes the form view, each
control must inform its associated column instance so that it can be deleted
from the list, otherwise it may try to refresh a control that no longer
exists. This is easy to do by trapping the Close event.
Hope this is of interest.
Frank Millman