The idea of this code is, the user presses the first button and enters what they want, then they press the second button and it prints it out. Can someone please tell me why my return statement is not working? It says that 'variable' is not defined. Thanks in advance for taking the time to read my question.
from tkinter import*
def fun():
variable = input('Enter Here:')
return variable
def fun_2():
print(variable)
window = Tk()
button = Button(text = 'Button', command = fun )
button2 = Button(text = 'Button2', command = fun_2 )
button.pack()
button2.pack()
window.mainloop()
In python when you create a variable inside of a function, it is only defined within that function. Therefore other functions will not be able to see it.
In this case, you will probably want some shared state within an object. Something like:
class MyClass:
def fun(self):
self.variable = input('Enter Here:')
def fun_2(self):
print(self.variable)
mc = MyClass()
window = Tk()
button = Button(text = 'Button', command = mc.fun )
button2 = Button(text = 'Button2', command = mc.fun_2 )
button.pack()
button2.pack()
fun() may return a value, but Tkinter buttons don't do anything with that return value.
Note that I used the phrase return a value, not return a variable. The return statement passes back the value of an expression, not the variable variable here. As such, the variable variable is not made into a global that other functions then can access.
Here, you can make variable a global, and tell fun to set that global:
variable = 'No value set just yet'
def fun():
global variable
variable = input('Enter Here:')
Since you did use any assignment in fun2, variable there is already looked up as a global, and it'll now successfully print the value of variable since it now can find that name.
The problem is in in fun2(). It does not get variable as an input parameter.
def fun_2(variable):
print(variable)
But note that you have to call fun_2 now with the appropriate argument. Also, as the function stands right now, there is little point in having the function if you just do a print inside of it.
Take away message: variable is not global in Python, and as such you must pass it to each function that wants to use it.
Related
Still pretty new to Python, so my apologies in advance...
I'm trying to use a button to move thru a List one item at a time.
It works the first time the button is clicked and moves to the second item in the List, but subsequent clicks keep returning the same values
from tkinter import *
window=Tk()
window.title('nextArrItem')
window.geometry("300x200+10+10")
options = ["H9Iu49E6Mxs", "YuWZNV4BkkY", "mBf6kJIbXLg", "Hz-xbM6jaRY"]
print("options[0] = " + options[0])
curItemText = options[0]
nextItemText = options[1]
curItem = 0
print('curItemText = '+curItemText)
print('nextItemText = '+nextItemText)
def nextArrItem(curItem=curItem+1):
print("str(curItem) = "+str(curItem))
try:
curItemText = options[curItem]
nextItemText = options[curItem+1]
print('curItemText = '+curItemText)
print('nextItemText = '+nextItemText)
curItem = curItem + 1
except:
print("End of Array Reached")
nextButton = Button(window, text="Next Item", command=nextArrItem)
nextButton.place(x=130, y=110)
window.mainloop()
When the Window opens initially, these values are returned:
options[0] = H9Iu49E6Mxs
curItemText = H9Iu49E6Mxs
nextItemText = YuWZNV4BkkY
The first click returns the following:
str(curItem) = 1
curItemText = YuWZNV4BkkY
nextItemText = mBf6kJIbXLg
Subsequent clicks keep returning the same values, so it only advances the first time and I'm not sure how to fix it. Although it probably doesn't look like it, this is the culmination of a lot of work just to get it to this point but I'm not sure where to go from here. I have the feeling the solution is going to be a true Homer Simpson "D'oh!" moment but I've steered this boat into shallow waters and need someone to help me from running aground...
Thanks in advance!
Paul
You need to increment the parameter each time to the next highest value. Currently your code just feeds the nextArrItem function the same value each time.
You could also try something to put the curItem inside a mutable data type so that it can be updated from within the scope of the function call like this:
...
options = ["H9Iu49E6Mxs", "YuWZNV4BkkY", "mBf6kJIbXLg", "Hz-xbM6jaRY"]
curItem = [0]
...
def nextArrItem(label=label):
try:
option = options[curItem[0]]
print(option)
label["text"] = option # updates label on each call
curItem[0] += 1 # increments index for option text
except IndexError:
print("End of Array Reached")
...
nextButton = Button(window, text="Next Item", command=nextArrItem)
...
Another way of doing it would be to bind the curItem variable to the window itself like this:
from tkinter import *
window=Tk()
window.curItem = 0
window.title('nextArrItem')
window.geometry("300x200+10+10")
options = ["H9Iu49E6Mxs", "YuWZNV4BkkY", "mBf6kJIbXLg", "Hz-xbM6jaRY"]
label = Label(window, text=options[window.curItem])
label.place(x=130, y=50)
def nextArrItem(label=label):
try:
option = options[window.curItem]
print(option)
label["text"] = option # updates label on each call
window.curItem += 1 # increments index for option text
except IndexError:
print("End of Array Reached")
nextButton = Button(window, text="Next Item", command=nextArrItem)
nextButton.place(x=130, y=110)
window.mainloop()
The issue you have is that curItem is both a global variable and a local variable in your callback function. You only ever update the local variable, so the change doesn't persist.
Here's how you're currently setting up the local variable, as an argument with a default value:
def nextArrItem(curItem=curItem+1):
The default value comes from the global variable, but it is only evaluated once, at the time the function is defined. It does not keep checking the global value, nor do changes to the local variable in the function change the global value either.
There's a better way. You can use a global statement to make it so that your function's code can directly read and write the global variable, so that there's only one curItem that everything is accessing the same way.
def nextArrItem():
global curItem
# the rest can be the same
I am currently working an a snake game, but I first want a settings window to show up.i used tkinter for this. In smaller projekts I just wrote all of the code into the pressButton function, but I want to have non spagetti code now, so im not going with that. The problem is, that I have no idea how to get the entered values in the entry brackets into my main code, as global variables, out of the pressButton function and the settingsWin function. The problem is that I use the function as a command for the Button, so I cannt use "return". Can you change global variables in the main code direcktly from inside of a function? If yes how? Or is there another way to solve this?
My Code:
def settingsWin():
def pressButton():
len = entryLen.get()
wid = entryWid.get()
speed = entrySpeed.get()
print(len+wid+speed)
SettingsWin.destroy()
return len
SettingsWin = Tk()
SettingsWin.geometry("600x600")
SettingsWin.title("Settings")
label1 = Label(SettingsWin, text="playing field [tiles]")
label1.pack()
entryLen = Entry(SettingsWin, bd=2, width=20)
entryLen.pack()
label2 = Label(SettingsWin, text="X")
label2.pack()
entryWid = Entry(SettingsWin, bd=2, width=20)
entryWid.pack()
labelblanc = Label(SettingsWin, text="")
labelblanc.pack()
label3 = Label(SettingsWin, text="Speed [ms per tick]")
label3.pack()
entrySpeed = Entry(SettingsWin, bd=2, width="20")
entrySpeed.pack()
okButton = Button(SettingsWin, text="OK", command=pressButton)
okButton.pack()
SettingsWin.mainloop()
len = "len"
wid = "wid"
speed = "speed"
It is often indicative of code smell to require that a function alter variables at scopes outside the function (except possibly in the case of closures, which are quite useful), it is possible to do so using the global keyword:
greeting = "Hello world!"
def greet():
global greeting
greeting = "Goodbye world!"
print(greeting)
greet()
print(greeting)
By declaring the variable greeting to be of global scope, altering the variable within the function definition allows the function to affect the global variable.
If you are working within nested subs, the nonlocal keyword will provide access within the inner sub, to the variable in the outer sub. It works similar to global, except that it is for broader lexical scope, not global scope.
I want to write a program where I need buttons to return an integer. So my idea was to create a local variable which gets changed.
The problem is, that the global variable value is somehow not defined.
Maybe somebody can help me? Thank you!!
def nb_1():
global value
value=1
def nb_2():
global value
value=2
def valueNumber():
global value
b1=Button(frame_output, text='1', command=nb_1)
b1.pack(side=LEFT)
b2=Button(frame_output, text='2', command=nb_2)
b2.pack(side=LEFT)
x=value
return x
print (valueNumber())
Firstly you need to define your global variable value outside of your functions. Also sice what valueNumber() do is just create buttons and do not call commands nb_1 and nb_2, but just assigns them as buttons commands. So returned value will be value you firstly assigned value to, here 0.
If you want to print value every time you changed it by clicking buttons print value inside this functions like so
from tkinter import Button, Tk, LEFT
frame_output = Tk()
def nb_1():
global value
value=1
print(value)
def nb_2():
global value
value=2
print(value)
def valueNumber():
global value
b1=Button(frame_output, text='1', command=nb_1)
b1.pack(side=LEFT)
b2=Button(frame_output, text='2', command=nb_2)
b2.pack(side=LEFT)
x=value
return x
value = 0
valueNumber()
frame_output.mainloop()
I'm working hard to solve this problem, can someone help me ?
There is what I mean by 'set' an argument:
from tkinter import *
window = Tk()
I=1
def add():
global I
menu1.add_command(label=I, command=lambda:Text(I))
I=I+1
def Text(I):
print(I)
menubar = Menu(window)
menu1 = Menu(menubar, tearoff=0)
menu1.add_command(label="Add", command=add)
menu1.add_separator()
menu1.add_command(label="Quit", command=window.quit)
menubar.add_cascade(label="Files", menu=menu1)
window.config(menu=menubar)
window.mainloop()
I want when we click on add and after on '1' it print '1', and when we add '2' and click on it, it print '2' but it always print the value of I, how can I set the argument by
menu1.add_command(label=I, command=lambda:Text(1))
for exemple ?
I don't know if I'm clear but I don't know how explain it !
Change your Text function to be a closure:
def Text(I):
def inner():
print(I)
return inner
Then change your add function to be this:
def add():
global I
text = Text(I)
menu1.add_command(label=I, command=text)
I=I+1
This will save the I in the text variable. The text variable is actually a function, inner, that will print I when called.
Or you could make your closure inline if you wanted to use the Text function somewhere else:
import functools
...
menu1.add_command(label=I, command=functools.partial(Text, i))
I think your problem is the lambda:Text(I). In this case, you have created a closure, but the closure knows I to be a global and is evaluating it at a later date.
You probably want to immediately evaluate Text(I) and use that as your result:
texti = Text(I) # Immediate evaluation
menu1.add_command(label=I, command=lambda:texti) # Return prior value of "I"
This comes from a button that when pressed generates a radiobutton. I am not able to access to the choice made with radiobutton. Everything works fine, but the output of selected function is zero. I try using both local and global var but the result is the same.
def callback_st(): # RadioButton select technology
var = IntVar()
m=0
for m in range(len(un_tech)):
Radiobutton(radio_frame, text=un_tech[m], value=m, variable=var,
command=selected(var)).pack(anchor=W)
def selected(var):
print(var)
This doesn't work. I solved using lambda:
def selected(jst):
global sel_technology
sel_technology=un_tech[jst]
print(sel_technology)
def callback_st(): #RadioButton select technology
var_st = IntVar()
m=0
for m in range(len(un_tech)):
Radiobutton(radio_frame, text=un_tech[m], value=m, variable=var_st,
command = lambda jst=m: selected(jst)).pack(anchor=W)
This works as i want, but it isn't the solution that i want and i think is not the correct way. So, somebody can help me to find the right way?
In your first try, you call selected immediately, when var has a value of 0. You avoided this with the lambda expression, but you are correct that this is an awkward workaround for the original mistake. Make var global and have selected access it as a global. Modifying your first code:
var = IntVar()
def selected():
print(var.get())
def callback_st():
...
...command=selected...
If you were defining a class and methods, var would be an instance attribute instead of global.