updating tabs in notebook

Hi,
Im having a problem with the notebook widget in wxpython.In each tab
Im opening and updating the same csv file depending on what the user
does. Now suppose the user changes the file through some actions in
tab2, when I click on tab1 , the data in the tab that comes from the
csv file is not updated. How do I pass control onto some event which i
can call when the tab changes so that i can reread the csv file and
update my data?
Thanks
Harsha

You can use EVT_NOTEBOOK_PAGE_CHANGING and EVT_NOTEBOOK_PAGE_CHANGED to get notified when the page is about to change and when it has been changed.

Or you can have just one instance of the data in memory that all pages share, and when any page changes the data then it can tell all the other pages to refresh their views of the data. This way you can avoid rereading it from the file. You'll need to write a bit of extra code to be able to do that but it is a common design pattern and wx.lib.pubsub can be helpful.

···

On 10/17/11 3:36 AM, harsha wrote:

Hi,
Im having a problem with the notebook widget in wxpython.In each tab
Im opening and updating the same csv file depending on what the user
does. Now suppose the user changes the file through some actions in
tab2, when I click on tab1 , the data in the tab that comes from the
csv file is not updated. How do I pass control onto some event which i
can call when the tab changes so that i can reread the csv file and
update my data?

--
Robin Dunn
Software Craftsman

Hi Robin,

I've been struggling with this same problem for a couple of days now.
I'm using EVT_NOTEBOOK_PAGE_CHANGING and I've tried self.Refresh()
and
self.Update() but when I go back to the Tab Page, its not updated.

Refresh and Update only deal with repainting the windows, they do not change the values that the widgets display. To do that you need to actually call each widget's SetValue method (or similar, depending on the type of widget) giving it the new value to display.

When you say a little extra code, where exactly is this code going --
on the 'main' page, or on the 'tabs' page. I have a tab.py file for
each
of my tabs and I import them into the 'main' module.

For a simple but typical implementation of the design pattern there would be some centrally located list, and some code to manage it. In every part of the rest of the application that wants to be notified of changes it would call a method that adds their notification callback function to that list. When a change happens in the data then the code that makes the change also calls a method which will call every callback in that list perhaps passing some appropriate information about the change.

For simple use cases this approach is a bit more overkill than is really necessary, but it helps the application be flexible and if it ever grows to the point where more than 1 or 2 places are interested in updates to the data then it makes it much easier to expand and adapt the application.

The wx.lib.pubsub module can be used for the "centrally located list" and the code that calls each of the registered callback functions, but as you can see it is very simple to implement something yourself if you don't need the advanced capabilities of pubsub.

···

On 10/17/11 2:17 PM, Bernie Nick wrote:

--
Robin Dunn
Software Craftsman

Hi Robin,

I used your suggestion of PubSub and it works quite well. Now, when
the User
selects a record from the 'grid' table on Tab1, the program goes to
the Database
(SQLite3), collects detailed information based on the Record ID
selected above
and populates a series of Text Ctrl Fields on Tab2 through the
messaging service
of Publisher (PubSub). So when the User clicks on Tab2 the detailed
information
on the selected Record is successfully displayed.

However, for some reason, the Image Field doesn't want to co-operate.
I've tried
passing the new name of an Image File which contains the JPG to Tab2
and it does seem
to be successfully accepted. But, the image displayed remains the
original one -- it
doesn't want to switch to -- and read from -- the newly selected file.

Again, I seem to be lacking some kind of a 're-set' or 're-initialize'
button for the
panel. Perhaps someone has some good ideas, which would be much
appreciated. As you
can tell, I'm just starting out with wxPython, but its going pretty
well so far.

Thanks, Bernie.

···

On Oct 17, 5:55 pm, Robin Dunn <ro...@alldunn.com> wrote:

On 10/17/11 2:17 PM, Bernie Nick wrote:

> Hi Robin,

> I've been struggling with this same problem for a couple of days now.
> I'm using EVT_NOTEBOOK_PAGE_CHANGING and I've tried self.Refresh()
> and
> self.Update() but when I go back to the Tab Page, its not updated.

Refresh and Update only deal with repainting the windows, they do not
change the values that the widgets display. To do that you need to
actually call each widget's SetValue method (or similar, depending on
the type of widget) giving it the new value to display.

> When you say a little extra code, where exactly is this code going --
> on the 'main' page, or on the 'tabs' page. I have a tab.py file for
> each
> of my tabs and I import them into the 'main' module.

For a simple but typical implementation of the design pattern there
would be some centrally located list, and some code to manage it. In
every part of the rest of the application that wants to be notified of
changes it would call a method that adds their notification callback
function to that list. When a change happens in the data then the code
that makes the change also calls a method which will call every callback
in that list perhaps passing some appropriate information about the
change.

For simple use cases this approach is a bit more overkill than is really
necessary, but it helps the application be flexible and if it ever grows
to the point where more than 1 or 2 places are interested in updates to
the data then it makes it much easier to expand and adapt the application.

The wx.lib.pubsub module can be used for the "centrally located list"
and the code that calls each of the registered callback functions, but
as you can see it is very simple to implement something yourself if you
don't need the advanced capabilities of pubsub.

--
Robin Dunn
Software Craftsmanhttp://wxPython.org

You might need to call Layout() on the notebook’s parent or the frame itself. Does it suddenly change if you resize the frame? If so, Layout will probably do the trick.

···

Mike Driscoll

Blog: http://blog.pythonlibrary.org

What kind of widget are you using to display the image? What code are you using to tell it to switch to the new image?

···

On 10/18/11 3:50 PM, Bernie Nick wrote:

However, for some reason, the Image Field doesn't want to co-operate.
I've tried
passing the new name of an Image File which contains the JPG to Tab2
and it does seem
to be successfully accepted. But, the image displayed remains the
original one -- it
doesn't want to switch to -- and read from -- the newly selected file.

--
Robin Dunn
Software Craftsman

Sorry for the late reply.
Basically, in Tab2, I've got,

        self.posterFileName = 'folder.jpg'
        self.poster = wx.StaticBitmap(self, -1,
wx.Image.ConvertToBitmap( \
                                (wx.Image.Rescale \
                                ((wx.Image(self.posterFileName,
wx.BITMAP_TYPE_JPEG)), \
                                  390, 585, wx.IMAGE_QUALITY_NORMAL)),
-1))

    def setPosterFileName(self, posterFileName):
         self.posterFile = posterFileName.data[0]

For the Text Control it seems to work fine, but I'm able to use
SetValue, ie.

def setEmpData(self, empRecord):
        self.id.SetValue(str(empRecord.data[0]))

Note(1): It seems I'm not allowed to use SetValue for the
posterFileName.
Note(2): The code is not exactly as shown -- I 'cobbled' it together
somewhat
for this example.
Question: Is the 'action' of 'setting' the value in the widget the
'trigger' which
signals the system to re-do the widget? If so, should I be using a
SetBitmap
(or similar) type approach to this problem?

Thanks much, Bernie.

···

On Oct 19, 12:34 pm, Robin Dunn <ro...@alldunn.com> wrote:

On 10/18/11 3:50 PM, Bernie Nick wrote:

> However, for some reason, the Image Field doesn't want to co-operate.
> I've tried
> passing the new name of an Image File which contains the JPG to Tab2
> and it does seem
> to be successfully accepted. But, the image displayed remains the
> original one -- it
> doesn't want to switch to -- and read from -- the newly selected file.

What kind of widget are you using to display the image? What code are
you using to tell it to switch to the new image?

--
Robin Dunn
Software Craftsmanhttp://wxPython.org

Hi Mike,

No it doesn't. I've tried many times with Layout, Update, Refresh,
ForceRefresh, etc.
From what Robin has told me (and from what I've discovered with
PubSub) it seems
as if I actually have to 'tweak' the individual widgets with a prod of
some sort,
like a SetValue statement, otherwise they (individually) don't
'refresh'.
See my comments below. Thanks for your comments. Bernie.

···

On Oct 19, 9:54 am, Mike Driscoll <kyoso...@gmail.com> wrote:

You might need to call Layout() on the notebook's parent or the frame
itself. Does it suddenly change if you resize the frame? If so, Layout will
probably do the trick.

-------------------
Mike Driscoll

Blog: http://blog.pythonlibrary.org

Sorry for the late reply.
Basically, in Tab2, I've got,

         self.posterFileName = 'folder.jpg'
         self.poster = wx.StaticBitmap(self, -1,
wx.Image.ConvertToBitmap( \
                                 (wx.Image.Rescale \
                                 ((wx.Image(self.posterFileName,
wx.BITMAP_TYPE_JPEG)), \
                                   390, 585, wx.IMAGE_QUALITY_NORMAL)),
-1))

     def setPosterFileName(self, posterFileName):
          self.posterFile = posterFileName.data[0]

For the Text Control it seems to work fine, but I'm able to use
SetValue, ie.

  def setEmpData(self, empRecord):
         self.id.SetValue(str(empRecord.data[0]))

Note(1): It seems I'm not allowed to use SetValue for the
posterFileName.

Because it's not an object that has a SetValue method. According to the code above it is a string object.

Note(2): The code is not exactly as shown -- I 'cobbled' it together
somewhat
for this example.
Question: Is the 'action' of 'setting' the value in the widget the
'trigger' which
signals the system to re-do the widget?

Uh, sorta... But your terminology is probably part of what is confusing you. A widget is a thing that appears on screen and provides some functionality and/or displays some value or some other thing. The widget and the "value or some other thing" are usually two separate and distinct objects. For example for a StaticText or a Button then it's a label represented by a string or unicode object, for StaticBitmap it is a bitmap object.

Each widget is responsible for itself and responding to user or system events, including drawing/painting itself including its "value or some other thing". Setting the value tells the widget to use a different value when it paints itself the next time, and usually they will do something to repaint themselves at that time as well.

If so, should I be using a
SetBitmap

Yes. You want to be modifying the existing widget objects, not creating new instances of those objects. self.poster = wx.StaticBimap(...) creates a new instance of the StaticBitmap class. self.poster.SetBitmap(...) tells the existing widget to display a different bitmap.

···

On 10/19/11 12:54 PM, Bernie Nick wrote:

--
Robin Dunn
Software Craftsman