Simple Question: How do you use the same variables in separate frames?

This should be a pretty easy question but I can't really find any docs or examples on how to do this. I'm just trying to learn wxPython here so this code is very amatuerish, generated using wxglade. I've basically got two frames, one which asks the questions, another which displays the answers but the variables from the first frame don't work in the second. I'm pretty new to python as well so...

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# generated by wxGlade 0.6.3 on Mon Jun 9 20:06:46 2008

import wx

# begin wxGlade: extracode
# end wxGlade

class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        # begin wxGlade: MyFrame.__init__
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.label_1 = wx.StaticText(self, -1, "Number")
        self.spin_ctrl_1 = wx.SpinCtrl(self, -1, "", min=0, max=1000)
        self.label_2 = wx.StaticText(self, -1, "Text")
        self.text_ctrl_1 = wx.TextCtrl(self, -1, "Enter some text")
        self.label_3 = wx.StaticText(self, -1, "Yes or No?")
        self.radio_btn_1 = wx.RadioButton(self, -1, "Yes")
        self.radio_btn_2 = wx.RadioButton(self, -1, "No")
        self.label_4 = wx.StaticText(self, -1, "Click")
        self.button_1 = wx.Button(self, -1, "Submit Everything!")

        self.__set_properties()
        self.__do_layout()

        self.Bind(wx.EVT_TEXT_ENTER, self.OnSubmit, self.text_ctrl_1)
        self.Bind(wx.EVT_BUTTON, self.OnSubmit, self.button_1)
        # end wxGlade

    def __set_properties(self):
        # begin wxGlade: MyFrame.__set_properties
        self.SetTitle("Some Questions...")
        # end wxGlade

    def __do_layout(self):
        # begin wxGlade: MyFrame.__do_layout
        grid_sizer_1 = wx.GridSizer(4, 2, 0, 0)
        sizer_2 = wx.BoxSizer(wx.VERTICAL)
        grid_sizer_1.Add(self.label_1, 0, 0, 0)
        grid_sizer_1.Add(self.spin_ctrl_1, 0, 0, 0)
        grid_sizer_1.Add(self.label_2, 0, 0, 0)
        grid_sizer_1.Add(self.text_ctrl_1, 0, 0, 0)
        grid_sizer_1.Add(self.label_3, 0, 0, 0)
        sizer_2.Add(self.radio_btn_1, 0, 0, 0)
        sizer_2.Add(self.radio_btn_2, 0, 0, 0)
        grid_sizer_1.Add(sizer_2, 1, wx.EXPAND, 0)
        grid_sizer_1.Add(self.label_4, 0, 0, 0)
        grid_sizer_1.Add(self.button_1, 0, 0, 0)
        self.SetSizer(grid_sizer_1)
        grid_sizer_1.Fit(self)
        self.Layout()
        # end wxGlade

    def OnSubmit(self, event): # wxGlade: MyFrame.<event_handler>
        NumberValue = self.spin_ctrl_1.GetValue()
        TextValue = self.text_ctrl_1.GetValue()
        YesValue = self.radio_btn_1.GetValue()
        NoValue = self.radio_btn_2.GetValue()
        if YesValue == True:
            YesNo = "Yes"
        else:
            YesNo = "No"
        print "Number: %s\nText: %s\nYes or No: %s" %(NumberValue,TextValue,YesNo)
        self.Close()
        MyFrame2(None, -1, "").Show()
        event.Skip()

# end of class MyFrame

class MyFrame2(wx.Frame):
    def __init__(self, *args, **kwds):
        # begin wxGlade: MyFrame.__init__
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.label_5 = wx.StaticText(self, -1, "Number")
        self.label_9 = wx.StaticText(self, -1, NumberValue)
        self.label_6 = wx.StaticText(self, -1, "Text")
        self.label_8 = wx.StaticText(self, -1, TextValue)
        self.label_7 = wx.StaticText(self, -1, "Yes or No?")
        self.label_10 = wx.StaticText(self, -1, YesNo)
        self.button_2 = wx.Button(self, wx.ID_CLOSE, "", style=wx.BU_RIGHT)

        self.__set_properties()
        self.__do_layout()

        self.Bind(wx.EVT_BUTTON, self.OnClose, self.button_2)
        # end wxGlade

    def __set_properties(self):
        # begin wxGlade: MyFrame.__set_properties
        self.SetTitle("frame_2")
        # end wxGlade

    def __do_layout(self):
        # begin wxGlade: MyFrame.__do_layout
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        grid_sizer_2 = wx.GridSizer(4, 2, 0, 0)
        grid_sizer_2.Add(self.label_5, 0, 0, 0)
        grid_sizer_2.Add(self.label_9, 0, 0, 0)
        grid_sizer_2.Add(self.label_6, 0, 0, 0)
        grid_sizer_2.Add(self.label_8, 0, 0, 0)
        grid_sizer_2.Add(self.label_7, 0, 0, 0)
        grid_sizer_2.Add(self.label_10, 0, 0, 0)
        sizer_1.Add(grid_sizer_2, 1, wx.EXPAND, 0)
        sizer_1.Add(self.button_2, 0, 0, 0)
        self.SetSizer(sizer_1)
        sizer_1.Fit(self)
        self.Layout()
        # end wxGlade

    def OnClose(self, event): # wxGlade: MyFrame.<event_handler>
        self.Close()
        event.Skip()

# end of class MyFrame2

if __name__ == "__main__":
    app = wx.PySimpleApp(0)
    wx.InitAllImageHandlers()
    frame_1 = MyFrame(None, -1, "")
    app.SetTopWindow(frame_1)
    frame_1.Show()
    app.MainLoop()

Thanks for your time :slight_smile:

[snip]

This isn't so much a wxPython question as much as a regular Python
question. In your one frame, you collect some values. In your other
frame, you need to use those values. In order to use those values,
you need to pass the data. This can be done by the frame with the
data keeping a reference to the frame wanting the data, setting a "new
data" attribute of somesuch (this is generally bad style), you could
use globals (also bad style), you could use events to pass the data
around (wx.PostEvent), or you could even use wx.lib.pubsub (this would
actually be my suggestion); the one frame subscribes to the "got new
data" topic, while the other publishes updates to that same topic.

- Josiah

···

On Fri, Jun 20, 2008 at 1:52 PM, Durand <durand1@gmail.com> wrote:

This should be a pretty easy question but I can't really find any docs or examples on how to do this. I'm just trying to learn wxPython here so this code is very amatuerish, generated using wxglade. I've basically got two frames, one which asks the questions, another which displays the answers but the variables from the first frame don't work in the second. I'm pretty new to python as well so...

Okay, I'll look into what that actually means, I'm new to python and wxwidgets so I'm not really sure I understand that.
Thanks.

···

On Fri, 20 Jun 2008 22:33:36 +0100, Timothy Grant <timothy.grant@gmail.com> wrote:

MyFrame2.GetParent().MyFrame.MyWidget

But the variables are set in one frame...

···

On Fri, 20 Jun 2008 22:50:38 +0100, Rich Shepard <rshepard@appl-ecosys.com> wrote:

On Fri, Jun 20, 2008 at 1:52 PM, Durand <durand1@gmail.com> wrote:

This should be a pretty easy question but I can't really find any docs or
examples on how to do this. I'm just trying to learn wxPython here so this
code is very amatuerish, generated using wxglade. I've basically got two
frames, one which asks the questions, another which displays the answers
but the variables from the first frame don't work in the second. I'm
pretty new to python as well so...

   Josiah's suggestion of using the wx.lib.pubsub is excellent. I use it to
notify modules of changes in another module, similar to what you describe as
a need.

   The other side of this effort is sharing the actual data; written to a
variable by one module and read by another module. This is separate from the
notification of data availability or change.

   Since a global variable has scope only within a single module, you need to
create a separate module that holds all the variables and their data that
you wish to share among modules (or frames) in your application. Call this
module anything you wish (I use config.py), then import it into each module
wanting access to the shared data.

HTH,

Rich

Lots of good input, Chris, thank you.

I agree that in vast majority of situations what you propose is the correct route, but I don’t agree that it’s the correct situation in all circumstances. I think it’s something of an inverse to the law of Diminishing Returns.

If I have two frames one with OneQuestion, one with OneAnswer and I want them to communicate, I will code it as I originally replied, because it’s quick, easy, and solves the problem right now. Now if I have more than X number of those situations (X being completely arbitrary) I will do something neater and tidier (the references to pub-sub were quite enlightening for me as that is something I have not investigated at all until I saw the reference on this thread).

My current toy project started off with code that looked like the above, quickly became unwieldy and is now on its second re-factor (which will likely morph into a third re-factor now that I know about pub-sub). If I had had to learn pub-sub and some other things before I started on it I would likely have never started.

···

On Fri, Jun 20, 2008 at 3:15 PM, Christopher Barker Chris.Barker@noaa.gov wrote:

Timothy Grant wrote:

I always store a reference to a widgets’s parent in everything I subclass, though it’s quite possible to simply use self.GetParent().

I don’t recommend this – it’s fragile to re-factoring, as it counts on the parent/child relationship to not change.

If two Objects need to know about each other, you should tell them about each-other explicitly, Something like:

I’ve basically got two frames, one which asks the questions, another

which displays the answers

AnswerFrame.QuestionFrame = TheQuestionFrameInstance

(probably set in init)

or better yet, use message passing of some sort, like wx.lib.pubsub

or the way I generally do it:

MyFrame2.parent.MyFrame.MyWidget

ouch! now MyFrame2 is counting on it’s parent being a MyFrame, which has a Widget Called MyWidget.

Read up on “The law of Demeter” for why this isn’t such a good idea.

Reading up on MVC/MVP is not a bad idea either.

(there was a recent discussion on this list about MVC that had some good stuff in it)

-Chris


Stand Fast,
tjg.

Thank you very much, that thread looked very similar. The examples of pub-sub were just what I needed.

···

On Fri, Jun 20, 2008 at 10:31 PM, C M cmpython@gmail.com wrote:

I just had to add that while I stand by what I wrote based on the maxim that

“Simple and fast is often good.” The conversation caused me to go back to my

project and re-factor VAST swathes of it (still not using pub-sub yet but

I’m sure that will come).

You might want to check out this thread that I asked about 10 weeks ago:

http://thread.gmane.org/gmane.comp.python.wxpython/57651

There’s also this wxpywiki page:

http://wiki.wxpython.org/PubSub

I did finally use pubsub it and it worked out well.

Che


Stand Fast,
tjg.

Hi,

I use global variables as singletons to communicate between frames notably to
avoid using multiple GetParent. This was before I know about pubsub.
I found this method there:
http://article.gmane.org/gmane.comp.python.wxpython/13175/match=globals
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/102187

class Singleton(type):
    def __init__(cls,name,bases,dic):
        super(Singleton,cls).__init__(name,bases,dic)
        cls.instance=None
    def __call__(cls,*args,**kw):
        if cls.instance is None:
            cls.instance=super(Singleton,cls).__call__(*args,**kw)
        return cls.instance

class MyGlobals(dict):
    __metaclass__ = Singleton

From now on, I think I will only use pubsub unless some experienced guy

recommend the Singleton method for certain purposes (which ones?).
Am I right ?

Dominique