tags:

views:

34

answers:

2

For a small timer app I want to write a GTK interface where I can set the desired time. Here is a picture of the interface:

alt text

However, I am having trouble reading out the fields of the spin buttons. My envisaged procedure for this is the following:

  1. Read out the buttons using methods for each button

Here is one of the methods that does this:

# Get the fields of the spinbuttons
def get_seconds(self, widget, spin):
    self.rSeconds = spin.get_value_as_int()

It is then called like this:

    button = gtk.Button("Start")
    button.connect("clicked", self.get_seconds, spinnerS)
  1. Create a timer object with the data from the buttons

This is planned to be accomplished using this method:

    # Create the timer object ...
   def prepare_timer(self, widget, hours, minutes, seconds, title, text):
     self.timer = eggTimer(hours, minutes, seconds, title, text)

Which is called here:

button.connect("clicked", self.prepare_timer, self.rHours, self.rMinutes, self.rSeconds, "some title", "some text")

Unfortunately, when running the script I get the following error message:

Traceback (most recent call last):
File "GTKInterface.py", line 140, in <module>
SpinButtonExample()
File "GTKInterface.py", line 126, in __init__
button.connect("clicked", self.prepare_timer, self.rHours, self.rMinutes, self.rSeconds, "Title", "Text")
AttributeError: SpinButtonExample instance has no attribute 'rSeconds'

To check whether there really is no instance of that variable, I programmed a short method to print it:

   def returnS(self, widget):
       print self.rSeconds

And surprisingly this method can "see" self.rSeconds. This makes me wonder what determines the visibility of the variable. What am I doing wrong to read this out?

+2  A: 

You try to pass the attribute self.rHours to the connect method, but at that point the attribute doesn't exist yet (the clicked handlers haven't executed yet).

Note that even if you fill in self.rHours before calling connect, it will pass the value at the time of connecting, not at the time of the handler executing.

You can solve this by passing self.rHours etc directly to eggTimer in prepare_timer.

But it would be even easier to just combine all the click handlers into one, and use local variables instead of self.rHours etc. There's no reason to split your code over many click handlers like this.

Edit: BTW, you can also use nested functions instead of methods:

...
def prepare_timer(widget):
    self.timer = eggTimer(
        spinnerH.get_value_as_int(),
        spinnerM.get_value_as_int(),
        spinnerS.get_value_as_int(),
        "Title", "Text")
button.connect("clicked", prepare_timer)
...

Keep it simple!

adw
Thanks for your reply, "keep it simple" is really something I should keep in mind ;). It's difficult at times however, as this is my first program in Python...
Ingo
Thanks for your thoughts, but it seems like that code doesn't solve my problem, or rather creates new ones. When I paste your proposal I get the following error message: `NameError: global name 'prepare_timer' is not defined` I think this is because you did not add "self" to the arguments of `prepare_timer`. So when doing this and adjusting the remaining code as such, I get this error: `NameError: global name 'eggTimer' is not defined` I'm destitute :(
Ingo
This would be the corresponding code: http://pastie.org/1257453
Ingo
@Ingo: "I get this error: ..." Read the error again, it makes perfect sense. You don't define `eggTimer` anywhere in the module. Assuming `eggTimer` exists in `Time_Calculation`, you can use `Time_Calculation.eggTimer` instead, or you can replace the import with `from Time_Calculation import eggTimer`.
adw
Thanks so much for helping out a dumb pythn newbie! Managed to solve my problem in the end :).
Ingo
+1  A: 

Going off of adw's answer recommending one click handler, a simple addition to your pastebin code would be:

def read_and_prepare(self,spinnerS,spinnerM,spinnerH,title,text):
    self.get_seconds(spinnerS)
    self.get_minutes(spinnerM)
    self.get_hours(spinnerH)
    self.prepare_timer(elf.rHours, self.rMinutes, self.rSeconds, title, text)

and only have

button.connect("clicked", self.read_and_prepare,spinnerS,spinnerM,spinnerH,"Title","Text")

for the connection code.

You could also probably redesign a bit to avoid all the get_* calls and just read the values in the click handler.

Benn
Thanks for this proposal, however, it dos not work. I noticed that you do not include "widget" as an argument in the function definition above, so I included it. But either way I get the following error message:`TypeError: get_seconds() takes exactly 3 arguments (2 given)`I think this is because get_seconds etc. have the argument "widget" and they never get that. Why do I actually need "widget" as an argument?
Ingo
Code: http://pastie.org/1257457
Ingo
To be honest I'm not entirely sure, as I've only done pyQT and straight python so I'm not sure of some of the assumptions pyGTK makes. In any case, it looks like you should be able to remove the widget argument from the get_* and prepare_timer call. If I had to guess, I'd guess that gobject.connect passes along the referring widget when it calls the handler? Which wouldn't apply in our case (though it may mean that read_and_prepare should take 'widget' as the first argument even if it doesn't use it.
Benn
I think that is what happens, widget is passed automatically. Well, I'll keep on searching for the problem!
Ingo