Spinner handling

This is rather trivial but I got stuck. I simplified my program to
just show problem.
I basically want to get the value of spinner. However with such code

···

############################
import wx

class MyMainClass(wx.Frame):
    def __init__(self,parent,id):
        wx.Frame.__init__(self,parent,id,'My window',size=(400,400))
        panel = wx.Panel(self)

        spiner = wx.SpinCtrl(panel,1,'spinner',(40,40), (90,-1))
        spiner.SetRange(1,100)
        spiner.SetValue(10)
        wx.EVT_SPINCTRL(self, 1, self.OnChange)

    def OnChange(self, event):
        a = event.GetValue()
        print a

if __name__=='__main__':
    app = wx.PySimpleApp()
    frame = MyMainClass(parent=None,id=-1)
    frame.Show()
    app.MainLoop()
###########################

I get error

line 19, in OnChange
    a = event.GetValue()
AttributeError: 'CommandEvent' object has no attribute 'GetValue'

while here it clearly states that spinctrl has GetValue!

http://docs.wxwidgets.org/stable/wx_wxspinctrl.html#wxspinctrlgetvalue

where is my mistake? How should it look like to return the value of
spinner?

yes, but you don't have the spinner, you have the event object. YOu need a reference to the spinner itself.

a couple ways to do that:

I recomend:

keep a reference to your spinner in "self":

        self.spiner = wx.SpinCtrl(panel,1,'spinner',(40,40), (90,-1))

then your OnChange:

       def OnChange(self, event):
           a = self.spiner.GetValue()
           print a

Another option isto retriee the object that generated the event from the event:

       def OnChange(self, event):
           a = event..GetEventObject.GetValue()
           print a

(untested...)

-Chris

···

On 5/16/11 10:45 AM, kafooster wrote:

This is rather trivial but I got stuck. I simplified my program to
just show problem.
I basically want to get the value of spinner. However with such code
############################
import wx

class MyMainClass(wx.Frame):
     def __init__(self,parent,id):
         wx.Frame.__init__(self,parent,id,'My window',size=(400,400))
         panel = wx.Panel(self)

         spiner = wx.SpinCtrl(panel,1,'spinner',(40,40), (90,-1))
         spiner.SetRange(1,100)
         spiner.SetValue(10)
         wx.EVT_SPINCTRL(self, 1, self.OnChange)

     def OnChange(self, event):
         a = event.GetValue()
         print a

if __name__=='__main__':
     app = wx.PySimpleApp()
     frame = MyMainClass(parent=None,id=-1)
     frame.Show()
     app.MainLoop()
###########################

  I get error

line 19, in OnChange
     a = event.GetValue()
AttributeError: 'CommandEvent' object has no attribute 'GetValue'

while here it clearly states that spinctrl has GetValue!

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (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

As implied by the exception message, the event object passed to the handler is not an instance of wx.SpinCtrl as you seem to be expecting, but rather an instance of wx.CommandEvent whose purpose is to trnasport information about the event to your handler. There are a couple other ways to get the value you want. You could save a reference to the spinctrl in self, and then use self.spinner.GetValue(). Or you could use the event object passed to the handler to get access to the source of the event, with event.GetEventObject().GetValue().

···

On 5/16/11 10:45 AM, kafooster wrote:

This is rather trivial but I got stuck. I simplified my program to
just show problem.
I basically want to get the value of spinner. However with such code
############################
import wx

class MyMainClass(wx.Frame):
     def __init__(self,parent,id):
         wx.Frame.__init__(self,parent,id,'My window',size=(400,400))
         panel = wx.Panel(self)

         spiner = wx.SpinCtrl(panel,1,'spinner',(40,40), (90,-1))
         spiner.SetRange(1,100)
         spiner.SetValue(10)
         wx.EVT_SPINCTRL(self, 1, self.OnChange)

     def OnChange(self, event):
         a = event.GetValue()
         print a

if __name__=='__main__':
     app = wx.PySimpleApp()
     frame = MyMainClass(parent=None,id=-1)
     frame.Show()
     app.MainLoop()
###########################

  I get error

line 19, in OnChange
     a = event.GetValue()
AttributeError: 'CommandEvent' object has no attribute 'GetValue'

while here it clearly states that spinctrl has GetValue!

http://docs.wxwidgets.org/stable/wx_wxspinctrl.html#wxspinctrlgetvalue

where is my mistake? How should it look like to return the value of
spinner?

--
Robin Dunn
Software Craftsman

Robin,

Beat you by five minutes!

:wink:

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (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

sorry for the delay,

many thanks for your help! I get it now

···

On 16 Maj, 20:15, Christopher Barker <Chris.Bar...@noaa.gov> wrote:

Robin,

Beat you by five minutes!

:wink:

-Chris

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Bar...@noaa.gov

I seem to have similar problem again,

I want one class to take information from another class's action and
I'm missing something while addressing it. Here is simplified code

···

###################################################
import wx

class One(wx.Frame):
    def __init__(self,parent,id):
        wx.Frame.__init__(self,parent,id,'Frame one',size=(300,200))

        self.button1 = wx.Button(self, 99, 'Action',(50, 50), (50,50))
        self.button1.Bind(wx.EVT_BUTTON, self.Action, id=99)

    def Action(self,event):
        self.second = Two(self, -1)
        self.second.Show()
        self.c = self.second.a + self.second.b
        if self.c >2:
            print 'success!'

class Two(wx.Frame):
    def __init__(self,parent,id):
        wx.Frame.__init__(self,parent,id,'Frame
two',size=(300,200))

        self.button2 = wx.Button(self, 88, 'Action2',(50, 50),
(50,50))
        self.button2.Bind(wx.EVT_BUTTON, self.Action2, id=88)

        self.a = 1

    def Action2(self,event):
        self.b = 2

if __name__=='__main__':
    app=wx.PySimpleApp()
    frame = One(parent=None,id=-1)
    frame.Show()
    app.MainLoop()

#########################################################

an error is once again attribute error.
AttributeError: 'Two' object has no attribute 'b'

I would very much appreciate your help.

At this point in time the only part of the Two class that has been run is its __init__ method. It is not going to wait here until its button is clicked and its Action2 method is called. This is part of the nature of event driven programming, snippets of code are executed in response to user or system events, and most of the time you can't depend on the sequence that those snippets are executed. In your case if you need to do something in response to the Two's button being clicked then you should either do it in Two.Action2 or send a message from there to the instance of the One class or wherever else you may need it. (Perhaps like self.GetParent().doSomething(), or you can use wx.lib.pubsub to do it more OOP-ly.)

···

On 6/4/11 5:52 PM, kafooster wrote:

I seem to have similar problem again,

I want one class to take information from another class's action and
I'm missing something while addressing it.

an error is once again attribute error.
AttributeError: 'Two' object has no attribute 'b'

Here is simplified code

     def Action(self,event):
         self.second = Two(self, -1)
         self.second.Show()
         self.c = self.second.a + self.second.b

--
Robin Dunn
Software Craftsman

kafooster wrote:

I seem to have similar problem again,
import wx

class One(wx.Frame):
    def __init__(self,parent,id):
        wx.Frame.__init__(self,parent,id,'Frame one',size=(300,200))

        self.button1 = wx.Button(self, 99, 'Action',(50, 50), (50,50))
        self.button1.Bind(wx.EVT_BUTTON, self.Action, id=99)

    def Action(self,event):
        self.second = Two(self, -1)
        self.second.Show()
        self.c = self.second.a + self.second.b

here, you are referencing the "Two" object's "b" attribute right after Show()int it...

        if self.c >2:
            print 'success!'

class Two(wx.Frame):
    def __init__(self,parent,id):
        wx.Frame.__init__(self,parent,id,'Frame
two',size=(300,200))

        self.button2 = wx.Button(self, 88, 'Action2',(50, 50),
(50,50))
        self.button2.Bind(wx.EVT_BUTTON, self.Action2, id=88)

        self.a = 1

    def Action2(self,event):
        self.b = 2

but here, Two's b attribute doesn't get defined until Action2 is called, i.e. after the button on the Two Frame is clicked.

you'll need to make sure a default value for b is defined in the __init__, or something like that --exactly what and how depends in the use case.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (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

Robin,

This time you beat me my 5 minutes.:wink:

-Chris

···

On 6/4/11 5:52 PM, kafooster wrote:

I seem to have similar problem again,

I want one class to take information from another class's action and
I'm missing something while addressing it.

an error is once again attribute error.
AttributeError: 'Two' object has no attribute 'b'

Here is simplified code

     def Action(self,event):
         self.second = Two(self, -1)
         self.second.Show()
         self.c = self.second.a + self.second.b

At this point in time the only part of the Two class that has been run is its __init__ method. It is not going to wait here until its button is clicked and its Action2 method is called. This is part of the nature of event driven programming, snippets of code are executed in response to user or system events, and most of the time you can't depend on the sequence that those snippets are executed. In your case if you need to do something in response to the Two's button being clicked then you should either do it in Two.Action2 or send a message from there to the instance of the One class or wherever else you may need it. (Perhaps like self.GetParent().doSomething(), or you can use wx.lib.pubsub to do it more OOP-ly.)

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (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

ok, thanks, I understand it and solved it, but how to bring up
something defined in other class in a method? like here?

class One

    def Action(self,event):
        self.a = 1
        self.second = Two(self, -1)
        self.second.Show()

class Two

        self.b = 1

    def Action2(self,event):
        self.first = One(self, -1)
        print self.first.a + self.b # a is adressed wrong

ok, I found that if I SEND(or well, create variable for different
class in first class) the variable from one class to other, it works

class One

    def Action(self,event):
        self.a = 1
        self.second = Two(self, -1)
        self.second.Show()
        self.second.b = self.a

class Two

    def Action2(self,event):

        print self.b

kafooster wrote:

ok, thanks, I understand it and solved it, but how to bring up
something defined in other class in a method? like here?
class One

    def Action(self,event):
        self.a = 1
        self.second = Two(self, -1)
        self.second.Show()

class Two

        self.b = 1

    def Action2(self,event):
        self.first = One(self, -1)
        print self.first.a + self.b # a is adressed wrong

this is infinitely recursive -- One creates a Two, which creates a One, which creates a Two......

not good.

kafooster wrote:

class One

    def Action(self,event):
        self.a = 1
        self.second = Two(self, -1)
        self.second.Show()
        self.second.b = self.a

class Two

    def Action2(self,event):

        print self.b

much more what you probably want, but do take some time to study up on Python namespaces, and classes, etc. It seems you have classes, instances of classes, and attributes, all a bit mixed up.

a class is a type of object, like a cat.

an instance of class cat is a particular one -- my cat, named sesame.

an attribute is piece of information held by an instance -- sesame.fur_color == 'grey'

In the above, you probably don't want to do:

> self.second.b = self.a

here -- b should probably be assigned in the constructor of Two, or at least before Show().

Also, it seems unlikely that you really want to create a new Two instance inside the Action() method -- I suspect it's more likely that you want to create a Two ahead of time, and Show() it in that action -- but all that depends on your use case.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (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

kafooster wrote:

ok, I found that if I SEND(or well, create variable for different
class in first class) the variable from one class to other, it works.

It can work, but in a project like this, you need to sit back and think
about the overall architecture. It is unusual and somewhat error-prone
to have two peer objects communicating directly with each other like
that. You don't really want the code in class One to know anything
about the implementation inside class Two, and vice versa.

Typically, in a case like this, one object is naturally the master, and
one object is naturally the slave. So, if One creates the Two, then the
One object can pass information to the Two object and ask for
information back again. But if you do it that way, then you probably
don't want the Two object to be demanding information from One. That
gets hard to track.

If there is common information that both objects need to have, then you
should probably create an object at a higher level to hold that, and
pass it to both. That way, the shared data remains nicely
encapsulated. You can change that implementation without rewriting
everything.

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

Thank you both for explanations.
These problems came up when I was writing an event to open .raw
images. after selecting data in wx.FileDialog , I wanted a window to
pop up, where one can input data type and dimensions, and I decided to
make that window as separate class which will give the data back to
the event and continue creating image for display.
It seems that I overcomplicated my solution unnecessarily I guess

kafooster wrote:

Thank you both for explanations.
These problems came up when I was writing an event to open .raw
images. after selecting data in wx.FileDialog , I wanted a window to
pop up, where one can input data type and dimensions, and I decided to
make that window as separate class which will give the data back to
the event and continue creating image for display.

That sounds like a classic application of a modal dialog.

You would normally:

create the dialog

call it with ShowModel()

when it returns, query it for the data that the use input.

maybe Destroy() it.

Your dialog would have attributes for the data you need. Actually, if I was doing it, I would most likely have a class that holds the data you need. When the user fills out the dialog, an instance of the class would get filled in. After closing, you can query the dialog for an instance of that class;

UsersData = Mydialog.GetTheData()

Or keep it really simple, Mydialog.GetTheData could pass back a simple (width, height, dtype) tuple.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (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