By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
439,930 Members | 2,018 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 439,930 IT Pros & Developers. It's quick & easy.

problem with tkinter

P: n/a
hello.

the following code:

1 from Tkinter import *
2
3 class MiaApp:
4 def __init__(self, genitore):
5 self.mioGenitore = genitore
6 self.i = IntVar()
7 self.i.set(42)
8 self.s = StringVar()
9 self.s.set("Baobab")
10 self.lab = {}
11 self.lab["self.i"] = Label(self.mioGenitore)
12 self.lab["self.i"].configure(width = 30, relief = RIDGE,
13 text = "[vuota]")
14 self.lab["self.i"].pack()
15 self.lab["self.s"] = Label(self.mioGenitore)
16 self.lab["self.s"].configure(width = 30, relief = RIDGE,
17 text = "[vuota]")
18 self.lab["self.s"].pack()
19 self.but = Button(self.mioGenitore)
20 self.but.configure(text = "Vai!", command = self.procedi)
21 self.but.pack()
22 def procedi(self):
23 for var in ("self.i", "self.s"):
24 self.lab[var].configure(textvariable = var)
25
26 radice = Tk()
27 miaApp = MiaApp(radice)
28 radice.mainloop()

is intended to make a window with 2 labels and a button, such that
pressin the button you get the labels display the content of two
variables. it does not work, of course, as intended. is there anybody
who can point me in the right direction? (the problem seems to be that
the command option wants a variable name, not a string containing that
name).

hopefully

macs
Jul 18 '05 #1
Share this Question
Share on Google+
5 Replies


P: n/a
Instead of indexing self.lab by strings, you can index them by the
attributes themselves : self.lab[self.i], and change line 23 into

for var in (self.s, self,i)

For your example, I wouldn't have used the "text" option in the
definition of the labels, then "textvariable" in the callback method
(procedi) ; I would have used only "text" and no IntVar or StringVar,
just an integer and a string :

class MiaApp:
def __init__(self, genitore):
self.mioGenitore = genitore
self.i = 42
self.s = "Baobab"
self.lab = {}
self.lab[self.i] = Label(self.mioGenitore)
self.lab[self.i].configure(width = 30, relief = RIDGE,
text = "[vuota]")
self.lab[self.i].pack()
self.lab[self.s] = Label(self.mioGenitore)
self.lab[self.s].configure(width = 30, relief = RIDGE,
text = "[vuota]")
self.lab[self.s].pack()
self.but = Button(self.mioGenitore)
self.but.configure(text = "Vai!", command = self.procedi)
self.but.pack()
def procedi(self):
for var in (self.i, self.s):
self.lab[var].configure(text = var)

Regards,
Pierre
Jul 18 '05 #2

P: n/a
On Tue, 29 Mar 2005 22:32:59 +0200, Pierre Quentel <qu************@wanadoo.fr> wrote:
Instead of indexing self.lab by strings, you can index them by the
attributes themselves : self.lab[self.i], and change line 23 into

for var in (self.s, self,i)
I really think this is asking for trouble: I suppose that the i and s attributes are meant to change at some point in the future, and you're mapping their *values* to the corresponding labels. So if the value changes, you won't be able to get the label again.
For your example, I wouldn't have used the "text" option in the
definition of the labels, then "textvariable" in the callback method
(procedi) ; I would have used only "text" and no IntVar or StringVar,
just an integer and a string :


I would have done exactly the contrary, as it is far more easier to use. Using the textvariable option in Label's does not require you to remember the labels, but only the variables used to hold their contents. I'd also use two mappings: the first mapping a name to a Tkinter variable for the label variables, and the second for the values to give to these variables later.

Here is my version of the class code:

class MiaApp:
def __init__(self, genitore):
self.mioGenitore = genitore
## Mapping for variables
self.variables = {
"i" : StringVar(),
"s" : StringVar()
}
## Mapping for future variable values
self.values = {
"i" : 42,
"s" : "Baobab"
}
## Now, create the labels
for var in self.variables.values():
## Default text
var.set("[vuota]")
## Create label
lb = Label(self.mioGenitore, width=30, relief=RIDGE, textvariable=var)
lb.pack()
## The button is no more remembered in an attribute, as it does not seem to be needed
but = Button(self.mioGenitore, text = "Vai!", command = self.procedi)
but.pack()

def procedi(self):
## Just change the variable values
for varName in self.variables.keys():
self.variables[varName].set(self.values[varName])

Note that I only used StringVar's: since the variable holds the *text* for a Label, it is not a good idea to use anything else. I tend to use IntVar, BooleanVar or DoubleVar only when I'm sure it won't ever be set to anything else than an integer, a boolean or a float respectively. So for Label and Entry text variables, I always use a StringVar. In spite of their name, these variable can actually hold anything; you will just get the value you've given to them as text rather than as their original type:
v = StringVar()
v.set(42)
v.get()

'42'

So if you want to get the integer back, you'll need to convert the value explicitely. This is in fact what is done by Tkinter when using an IntVar, but by doing it yourself, you'll be able to decide what to do if the conversion fails instead of just getting a generic TclError.

HTH
--
python -c 'print "".join([chr(154 - ord(c)) for c in "U(17zX(%,5.z^5(17l8(%,5.Z*(93-965$l7+-"])'
Jul 18 '05 #3

P: n/a
Pierre Quentel wrote:
Instead of indexing self.lab by strings, you can index them by the
attributes themselves : self.lab[self.i], and change line 23 into

for var in (self.s, self,i)

For your example, I wouldn't have used the "text" option in the
definition of the labels, then "textvariable" in the callback method
(procedi) ; I would have used only "text" and no IntVar or StringVar,
just an integer and a string :

class MiaApp:
def __init__(self, genitore):
self.mioGenitore = genitore
self.i = 42
self.s = "Baobab"
self.lab = {}
self.lab[self.i] = Label(self.mioGenitore)
self.lab[self.i].configure(width = 30, relief = RIDGE,
text = "[vuota]")
self.lab[self.i].pack()
self.lab[self.s] = Label(self.mioGenitore)
self.lab[self.s].configure(width = 30, relief = RIDGE,
text = "[vuota]")
self.lab[self.s].pack()
self.but = Button(self.mioGenitore)
self.but.configure(text = "Vai!", command = self.procedi)
self.but.pack()
def procedi(self):
for var in (self.i, self.s):
self.lab[var].configure(text = var)

Regards,
Pierre


hi pierre.

i don't think this would not have worked as expected (by me). in my
intentions, the text of the label must be slaved to a variable, so that
it would change dynamically during the mainloop execution if another
part of the code had chenged the content of the variable.

maybe here is a more convincing example (the previous one was contrived
too hastily i guess):

1 from Tkinter import *
2
3 class MiaApp:
4 def __init__(self, genitore):
5 self.mioGenitore = genitore
6 self.var = {0: 42, 1: "Baobab"}
7 self.lab = {}
8 self.lab[0] = Label(self.mioGenitore)
9 self.lab[0].configure(width = 30, relief = RIDGE,
10 text = "[vuota]")
11 self.lab[0].pack()
12 self.lab[1] = Label(self.mioGenitore)
13 self.lab[1].configure(width = 30, relief = RIDGE,
14 text = "[vuota]")
15 self.lab[1].pack()
16 self.but = Button(self.mioGenitore)
17 self.but.configure(text = "Vai!", command = self.procedi)
18 self.but.pack()
19 self.but2 = Button(self.mioGenitore)
20 self.but2.configure(text = "Torna!", command =
self.procedi2)
21 self.but2.pack()
22 def procedi(self):
23 for var in self.lab.keys():
24 self.lab[var].configure(text = self.var[var])
25 def procedi2(self):
26 self.var[0] = 24
27 self.var[1] = "Cactus"
28
29 radice = Tk()
30 miaApp = MiaApp(radice)
31 radice.mainloop()

in this example, when user presses "Torna!", the labels are not updated
as i expect; they only will be when user presses "Vai!" again (not what
i want).

thanks again

macs
Jul 18 '05 #4

P: n/a
Eric Brunel wrote:
On Tue, 29 Mar 2005 22:32:59 +0200, Pierre Quentel
<qu************@wanadoo.fr> wrote:
[...]


mr brunel,

i thank you for prompt reply. i will take my time to read it carefully.

meanwhile, i inform you and the ng that someone else gave me a quick and
dirty answer to my problem, namely subststuting line #24 like this:

24 self.lab[var].configure(textvariable = eval(var))

which seems to work as desired.

thanks again

bye

macs
Jul 18 '05 #5

P: n/a
Eric Brunel wrote:
On Tue, 29 Mar 2005 22:32:59 +0200, Pierre Quentel
<qu************@wanadoo.fr> wrote:
Instead of indexing self.lab by strings, you can index them by the
attributes themselves : self.lab[self.i], and change line 23 into

for var in (self.s, self,i)

I really think this is asking for trouble: I suppose that the i and s
attributes are meant to change at some point in the future, and you're
mapping their *values* to the corresponding labels. So if the value
changes, you won't be able to get the label again.
For your example, I wouldn't have used the "text" option in the
definition of the labels, then "textvariable" in the callback method
(procedi) ; I would have used only "text" and no IntVar or StringVar,
just an integer and a string :

I would have done exactly the contrary, as it is far more easier to use.
Using the textvariable option in Label's does not require you to
remember the labels, but only the variables used to hold their contents.
I'd also use two mappings: the first mapping a name to a Tkinter
variable for the label variables, and the second for the values to give
to these variables later.

Here is my version of the class code:

class MiaApp:
def __init__(self, genitore):
self.mioGenitore = genitore
## Mapping for variables
self.variables = {
"i" : StringVar(),
"s" : StringVar()
}
## Mapping for future variable values
self.values = {
"i" : 42,
"s" : "Baobab"
}
## Now, create the labels
for var in self.variables.values():
## Default text
var.set("[vuota]")
## Create label
lb = Label(self.mioGenitore, width=30, relief=RIDGE,
textvariable=var)
lb.pack()
## The button is no more remembered in an attribute, as it does
not seem to be needed
but = Button(self.mioGenitore, text = "Vai!", command =
self.procedi)
but.pack()

def procedi(self):
## Just change the variable values
for varName in self.variables.keys():
self.variables[varName].set(self.values[varName])


your technique is most interirting and clean, i must say.

nevertheless, i cannot find a natural way to "modularize" it, in such a
way that the machinery of the method might be isolated from the code
that uses it.

consider for example the following two programs:

.....

$ cat Miodialogo.py
from Tkinter import *

class MioDialogo(Toplevel):
def __init__(self, genitore, chiamante):
Toplevel.__init__(self, genitore)
self.wm_title("Valori delle variabili")

self.mioGenitore = genitore
self.mioChiamante = chiamante

self.fonteVar = ("Helvetica", 14)

self.quadro_grande = Frame(self)
self.quadro_grande.pack(expand = YES, fill = BOTH)

self.titolo = Label(self.quadro_grande)
self.titolo.configure(
text = "Valori delle variabili:",
width = 20,
font = self.fonteVar
)
self.titolo.pack(side = TOP, fill = X)

def mostraVariabili(self, *argomenti):
lung = 1
for i in argomenti:
if len(i) > lung:
lung = len(i)

self.dq = {}
self.dn = {}
self.dv = {}
for i in argomenti:
self.dq[i] = Frame(self.quadro_grande)
self.dq[i].pack(
side = TOP,
anchor = W,
fill = X
)

self.dn[i] = Label(self.dq[i])
self.dn[i].configure(
text = i + ": ",
width = lung + 2,
anchor = W
)
self.dn[i].pack(
side = LEFT
)

self.dv[i] = Label(self.dq[i])
self.dv[i].configure(
textvariable = eval("self.mioChiamante." + i),
anchor = W
)
self.dv[i].pack(
side = LEFT,
expand = YES,
fill = X
)

self.vaBene = Button(self.quadro_grande)
self.vaBene.configure(
text = "Va Bene",
command = self.pulsanteVaBenePremuto,
default = ACTIVE
)
self.vaBene.bind(
"<Return>",
self.pulsanteVaBenePremuto_a
)
self.vaBene.focus_force()
self.vaBene.pack(
side = BOTTOM,
pady = 2
)

def pulsanteVaBenePremuto(self):
self.destroy()
self.mioChiamante.var.configure(state = NORMAL)

def pulsanteVaBenePremuto_a(self, evento):
self.pulsanteVaBenePremuto()

$ cat spunta-4.py
from Tkinter import *
from Miodialogo import *

class MiaApp:
def __init__(self, genitore):

self.mioGenitore = genitore

self.fonte = ("Helvetica", 12)

self.quadro_grande = Frame(genitore)
self.quadro_grande.pack(expand = YES, fill = BOTH)

self.msg = Label(self.quadro_grande)
self.msg.configure(
font = self.fonte,
wraplength = "10c",
justify = LEFT,
text = u"Sono qui sotto presentati tre pulsanti a spunta. \
Premendo un pulsante, se ne varia lo stato di selezione e si \
imposta una variabile a un valore che indica lo stato del \
pulsante stesso. Premendo il pulsante \u00ABMostra \
Variabili\u00BB si possono vedere i valori correnti delle \
variabili."
)
self.msg.pack(side = TOP)

self.pulsanti = Frame(self.quadro_grande)
self.pulsanti.pack(side = BOTTOM, fill = X, padx = "2m")

self.pulsanti_spunta = Frame(self.quadro_grande)
self.pulsanti_spunta.pack(side = TOP, fill = X, padx = "2m")

self.annulla = Button(self.pulsanti)
self.annulla.configure(
text = "Annulla",
command = self.mioGenitore.destroy
)
self.annulla.pack(side = LEFT, expand = YES)
self.var = Button(self.pulsanti)
self.var.configure(
text = "Mostra Variabili",
command = self.pulsanteMostraVariabiliPremuto,
default = NORMAL
)
self.var.pack(side = LEFT, expand = YES)

self.tergicristalli = IntVar()
self.b1 = Checkbutton(self.pulsanti_spunta)
self.b1.configure(
text = "Tergicristalli a posto",
variable = self.tergicristalli,
relief = FLAT
)
self.b1.pack(
side = TOP,
pady = 2,
anchor = W
)

self.freni = IntVar()
self.b2 = Checkbutton(self.pulsanti_spunta)
self.b2.configure(
text = "Freni a posto",
variable = self.freni,
relief = FLAT
)
self.b2.pack(
side = TOP,
pady = 2,
anchor = W
)

self.autista = IntVar()
self.b3 = Checkbutton(self.pulsanti_spunta)
self.b3.configure(
text = "Autista sobrio",
variable = self.autista,
relief = FLAT
)
self.b3.pack(
side = TOP,
pady = 2,
anchor = W
)

def pulsanteMostraVariabiliPremuto(self):
if self.var.cget("state") == ACTIVE:
self.var.configure(state = DISABLED)
self.dialogo = MioDialogo(self.mioGenitore, self)
self.dialogo.mostraVariabili("tergicristalli",
"freni",
"autista")

radice = Tk()
radice.wm_title("Dimostrazione Pulsanti a Spunta")
radice.wm_iconname("spunta")
miaApp = MiaApp(radice)
radice.mainloop()

.....

the program spunta-4.py uses the module Miodialogo.py, which can be
usedby any other program simply passing along strings containing the
names of the attributes to be displayed.

i cannot find a similar way to modularize your technique (maybe it is my
fault).

thanks again

macs
Jul 18 '05 #6

This discussion thread is closed

Replies have been disabled for this discussion.