Global and local variables in function combined with tkinter - python

Why is this possible? When I click on the button it switches to "I have been clicked". However, "action" is a local object of the function. How can the function cause a global change?
I'd expected that I need to set action global in the function via "global action".
import tkinter as tk
from tkinter import ttk
#Creates tk object
win = tk.Tk()
win.title("TEST")
alabel = ttk.Label(win, text = "A Label")
alabel.grid(column=0, row=0)
#function
def click_me():
action.configure(text="I have been clicked")
alable.configure(foreground='red')
alable.configure(text='a red label')
#adding a button
action = ttk.Button(win, text="Click me", command = click_me)
action.grid(column=1, row=0)
win.mainloop()

However, "action" is a local object of the function.
That is incorrect. Until you assign something to action within the function, it refers to the global variable action.
Because you are calling a method on action rather than setting action to a new value, you are modifying the object that action points to.

Related

Properly assigning a function with arguments to a button in Tkinter

I have two files:
functions.py
import tkinter as tk
class funcs():
def func1(entry):
entry.delete(0, tk.END)
main.py
import tkinter as tk
import functions as f
root = tk.Tk()
entrybox = tk.Entry(master=root).grid()
button = tk.Button(master=root, command=f.funcs.func1(entrybox)).grid()
root.mainloop()
In main.py, I have assigned the command func1 with the argument entrybox to the widget button.
My intent is to have the entry argument represent an entry widget I want to manipulate.
This line of code is broken:
button = tk.Button(master=root, command=f.funcs.func1(entrybox)).grid()
The problem is that when I run the program, the function is called immediately and does not get assigned to the button.
I am looking for a way to assign a function with arguments to a button in tkinter.
You can use an anonymous function:
tk.Button(
master=root,
command=lambda: f.funcs.func1(entrybox)
)
Python recognizes the broken line of code as an immediate call, so you have to do lambda:
button = tk.Button(master=root, command=lambda: f.funcs.func1(entrybox)).grid()
and as far as I know that will get rid of the problem.

Scope Error In Python (Tkinter): "name 'Sample_Name' is not defined", even though it is declared as global

I am trying to create a Python GUI using Tkinter. I first create a window displaying options to the user, as buttons. When a button is clicked, I call a function to create a a new window with Toplevel() function. In the new window, I have a button and a label. By clicking the button I want the text of the label to be changed. However, I get an error about the scope of the label. Here is an example of the code's concept:
import tkinter as tk
# function called by popWin()
def func():
global win_lbl # declaring label as global so that I can edit its text
win_lbl['text'] = 'new text' # Here, I get scope error (name 'win_lbl' is not defined)
def popWin():
window = tk.Toplevel()
win_btn = tk.Button(window, command = func) # A button
win_lbl = tk.Label(window, text = 'initial text') # A label whose name I want to change with func()
win_btn.grid()
win_lbl.grid()
window.mainloop()
# Main Code
root = tk.Tk()
frame = tk.Frame(root)
btn = tk.Button(frame, text = 'Option 1', command = popWin) # calls popWin, which creates a new window with Toplevel()
btn.grid()
frame.grid()
root.mainloop()
Full Error text:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python\Python39\lib\tkinter\__init__.py", line 1885, in __call__
return self.func(*args)
File "c:\Users\Me\Desktop\proj\Menu.py", line 15, in func
win_lbl['text'] = 'new text'
NameError: name 'win_lbl' is not defined
Any help will be much appreciated. Thank you in advance.
Defining a global means you have to define the variable on global scope, i.e. outside of any function. The global keyword means that you're telling Python to use the globally defined variable with that name. So, to fix your issue, you have to either put the definition of win_lbl at the top of your code outside of any function, pass it to func as an argument, or store your functions and everything global in a class and reference that class variable instead.

Tkinter: KeyError when assigning function to a button

So, I have rather complicated program, and I ran into an issue with it that I can't seem to solve.
Here's the problematic part of my program:
import tkinter as tk
window = tk.Tk()
variable = "enter"
vars()[variable] = tk.Entry()
vars()[variable].insert(0, "hello")
vars()[variable].pack()
def hi():
text = vars()[variable].get()
button = tk.Button(text = "Click", command = hi)
button.pack()
I need to get the content of the entry called "enter" with the press of a button. Because of how my program works, this name, "enter" must be stored in a variable, that I called "variable" here.
What happens, is that when I press the button, I get a KeyError.
What's even weirder is that when I do the following, the program actualy works:
import tkinter as tk
window = tk.Tk()
variable = "enter"
vars()[variable] = tk.Entry()
vars()[variable].insert(0, "hello")
vars()[variable].pack()
text = vars()[variable].get()
button = tk.Button(text = "Click")
button.pack()
Here getting the content of "enter" isn't done with a button, but it's done automatically as the program runs. This is not what I want, but for some reason it works.
What can I do to make the 1st code work properly?
When you execute vars locally within hi function, a new dict object is created, that is different than the dict object created globally.
You can save the reference to the variable and use the variable within your hi function.
import tkinter as tk
window = tk.Tk()
variable = "enter"
vars()[variable] = tk.Entry()
vars()[variable].insert(0, "hello")
vars()[variable].pack()
d = vars()
def hi():
text = d[variable].get()
button = tk.Button(text="Click", command=hi)
button.pack()
window.mainloop()
I need to get the content of the entry called "enter" with the press of a button. Because of how my program works, this name, "enter" must be stored in a variable,
A better solution than using vars()[variable] is to store your widgets in a dictionary. The use of vars() provides very little value at the expense of making the code harder to understand.
import tkinter as tk
window = tk.Tk()
variable = "enter"
widgets = {}
widgets[variable] = tk.Entry()
widgets[variable].insert(0, "hello")
widgets[variable].pack()
def hi():
text = widgets[variable].get()
print(text)
button = tk.Button(text = "Click", command = hi)
button.pack()

Python - Simple tkinter menu

I need help from you.
I want to code a simple menu with tkinter, but i have problem with that.
What I want to do - In my menu,there are 2 items: "first", "second". When i click on the first, program must write 'The first' and then when I click on the second, it must write second, but the first one there will be not yet.
Can anybody help me? Thx.
I mean something like this
from tkinter import *
root = Tk()
def do_something():
# this function e.g. write 'The first'
pass
def do_something_other():
# this function e.g. write 'The second' (but 'The first' there will be not yet)
main_menu = Menu(root)
root["menu"] = main_menu
submenu1 = Menu(main_menu)
submenu1.add_command(label="Item1", command=do_something)
submenu1.add_command(label="Item2", command=do_something_other)
main_menu.add_cascade(label="Program", menu=submenu1)
My goal is, that the canvas will be changing after clicking on the Item1/Item2
You can use a Tkinter Label widget to display text in your GUI. The Label widget has a method called config that you can use to access options of the widget, to include its text attribute.
Here's a simple example. You'll have to modify it to work with your menus and specific needs:
root = Tk()
def callback(): # this function will access the
label.config(text='Updated Text') # config method of label to change it
label = Label(root, text='Original text') # make the label and set default text
btn = Button(root, text='Change text', command=callback) # make the button, which executes the callback func
label.pack()
btn.pack()
mainloop()

Call the same function when clicking the Button and pressing enter

I have a GUI that has Entry widget and a submit Button.
I am basically trying to use get() and print the values that are inside the Entry widget. I wanted to do this by clicking the submit Button or by pressing enter or return on keyboard.
I tried to bind the "<Return>" event with the same function that is called when I press the submit Button:
self.bind("<Return>", self.enterSubmit)
But I got an error:
needs 2 arguments
But self.enterSubmit function only accepts one, since for the command option of the Button is required just one.
To solve this, I tried to create 2 functions with identical functionalities, they just have different number of arguments.
Is there a more efficient way of solving this?
You can create a function that takes any number of arguments like this:
def clickOrEnterSubmit(self, *args):
#code goes here
This is called an arbitrary argument list. The caller is free to pass in as many arguments as they wish, and they will all be packed into the args tuple. The Enter binding may pass in its 1 event object, and the click command may pass in no arguments.
Here is a minimal Tkinter example:
from tkinter import *
def on_click(*args):
print("frob called with {} arguments".format(len(args)))
root = Tk()
root.bind("<Return>", on_click)
b = Button(root, text="Click Me", command=on_click)
b.pack()
root.mainloop()
Result, after pressing Enter and clicking the button:
frob called with 1 arguments
frob called with 0 arguments
If you're unwilling to change the signature of the callback function, you can wrap the function you want to bind in a lambda expression, and discard the unused variable:
from tkinter import *
def on_click():
print("on_click was called!")
root = Tk()
# The callback will pass in the Event variable,
# but we won't send it to `on_click`
root.bind("<Return>", lambda event: on_click())
b = Button(root, text="Click Me", command=frob)
b.pack()
root.mainloop()
You could also assign a default value (for example None) for the parameter event. For example:
import tkinter as tk
def on_click(event=None):
if event is None:
print("You clicked the button")
else:
print("You pressed enter")
root = tk.Tk()
root.bind("<Return>", on_click)
b = tk.Button(root, text='Click Me!', command=on_click)
b.pack()
root.mainloop()

Categories