Tkinter: change class variable when pressing a button - python

I am writing a function that get called when I click a button, but before calling this function, I would like to change a class variable.
How do you do that in a button ? As now I did declare the button as following:
calculatebutton = Button(self, text="run function", command=self.calculate_total(self.totals))
calculatebutton.place(x=150, y=600)
This run my function, but I want to change also a class variable, and I want to change it before I run the function.

You can wrap your method with new one and in it, before calling your method, you can do whatever you want.
def wrapper(self):
self.your_value = new_value
self.calculate_total(self.totals)
calculatebutton = Button(self, text="run function", command=self.wrapper)
calculatebutton.place(x=150, y=600)
Also note that, if you want to pass an argument to your method when calling from button, you should use lambdas.

Related

It’s working but I don’t understand why. It's about arguments to callbacks

It’s working but I don’t understand why. I was able to play around until I found something that works and it depends upon hidden “default” arguments in callbacks, but I thought the “event” was the only hidden argument. I wanted to pass the class “self” also. I want an event in a tkinter class to call an external function (external to the class) and I want to pass the event and the class (“self”) as arguments. To do this I call internal functions which then call the external functions.
The confusing point is that I must do it differently for a call from a bind and a call from a button command. It works and does what I want but I also want to understand what is happening. I also would like to know if there is a better way. The following code is all within the class.
self.B1 = Button(self.frame_controls, text = "Go", command=lambda: self.process_go_internal(self))
self.canvas.bind('<Configure>', self.process_configure_internal)
def process_go_internal(event, rt):
process_go_external(rt, event)
def process_configure_internal(self, event):
process_configure(self, event)
Hmmm, it's difficult to see what you are doing when you are not supplying working code. However I'll provide an example of how you could do what I think you are trying to do:
The bind() function generates an event but the Button() does not, so you will have to treat them accordingly. I have them call different methods within the class.
In the button_press() method I supply a default value for event as there is no event passed by the Button.
As for passing a reference to the instance you can just pass it as you would any name.
from tkinter import *
root = Tk()
def external_function(instance, event):
print('external_function instance:', instance)
print('external_functionevent:', event)
print()
instance.do_it() # Try to call the Cheese instance
class Cheese():
def __init__(self):
root.bind('<Configure>', self.configure)
B1 = Button(root, text='Go', command=self.button_press)
B1.pack(padx=100, pady=20)
def configure(self, event):
print('<Configure>')
external_function(self, event) # Passing instance ref and event
def button_press(self, event=None):
print('Button press')
print()
external_function(self, event) # Passing instance ref and event
def do_it(self):
print("I'm doing it!")
print()
c = Cheese()
root.mainloop()
Was this helpful?

Calling a function from a checkbox issues

So I'm really fresh into python and perhaps in over my head. I have created a tkinter checkbox inside the mainloop of my gui that is to call a function outside (aulocale1). When clicking the checkbox I get the global name aulocale1 is not defined error. I know this is easily resolved but I've tried googling it and the results don't really make sense. My apologies for the post as I know its something silly.
aulocale = IntVar()
aucheck = Checkbutton(self.master, variable=aulocale, onvalue=1, offvalue=0, text="AU",command=aulocale1)
aucheck.pack(in_=top, side=LEFT)
Function :
def aulocale1(self,master):
self.master.base.replace = "http://www.adidas.com.au/on/demandware.store/Sites-adidas-AU-Site/en_AU"
self.master.replace = ('','AU')
self.master.headers = ('REPLACETHISPLIZZZ','en-AU,en;q=0.8')
It looks like aulocale1 is not global function but method in class so you need self
command=self.aulocale1
if this method and checkbox are in the same class
Or
command=some_object.aulocale1
if method is in different object some_object

How to reassign object to a variable in python?

If I assign a variable (in this case b) to a button and put it on screen with pack(), then later reassign b to another data type, how do I access that button so that it can be deleted or otherwise referred to? I guess the question could be asked about any data type or object, but this is case stands out because the button is left on the screen. Example:
import tkinter as tk
root=tk.Tk()
root.geometry('300x300')
b=tk.Button(root, text="button b")
b.pack()
b=1
root.mainloop()
... then later reassign b to another data type, how do I access that button so that it can be deleted or otherwise referred to?
Short answer: you can't. In order to refer to something you must keep a reference. That being said,tkinter provides some alternatives.
If you're wanting to refer to the button in the callback, you can pass it in. This requires creating the button and then defining the callback in a separate step:
b = tk.Button(...)
b.configure(command=lambda button=b: do_something)
...
def do_something(button):
print("the widget is:", button)
Also, if you're using bindings, when the bound function is called it will be passed an event object that has an attribute that contains a reference to the widget.
b.bind("<1>", do_something)
...
def do_something(event):
print("the widget is:", event.widget)
Finally, you can ask tkinter for a list of child widgets (eg: root.winfo_children), and if you know whether you've used pack, place or grid, you can use the slaves method to query all of the widgets being managed inside a particular container (eg: root.grid_slaves(), root.pack_slaves(), root.place_slaves())
Save a reference somewhere with another assignment.
b = tk.Button(root, text="button b")
saved = b
b = 1
saved.pack()
You can access all widgets of the root window with the method:
list_of_widgets = root.pack_slaves()
and then check for the type of the object. ( Which is not a good practice ... )
Thus, i would recommend you to save the required references in a separeate object, for clearly seperating the interface to tkinter from your application. From then on, you should only access the widgets through your interface object. This creates much cleaner code.

Can I recognize label content in popup menu as an argument?

I created a lots of menu in tkinter,every menu has its corresponding command,so I have to creat a number of command functions.
If the label content can be an argument then I can pass it to only one function.How can I make it become an argument?
def show_rc_menu(self,event):
self.menu.post(event.x_root, event.y_root)
def creat_right_click_menu(self):
self.menu=Menu()
self.menu.add_command(label='hereiam1',command=self.hello)
self.menu.add_command(label='hereiam2',command=self.hello)
self.menu.add_command(label='hereiam3',command=self.hello)
...
self.menu.add_command(label='hereiam100',command=self.hello)
def resize(self,e):
print e
Use lambda just with one command:
def hello(text=None):
if text:
# Do some things
self.menu=Menu()
self.menu.add_command(label='hereiam1',command=lambda :self.hello('some_text'))
self.menu.add_command(label='hereiam2',command=self.hello)
self.menu.add_command(label='hereiam3',command=self.hello)
You can not influence the parameters that the menu button or another widget will pass into the callback function by itself (none, in this case), but you can use a lambda function to pass a parameter:
self.menu.add_command(label='hereiam1', command=lambda: self.hello('hereiam1'))
and similarly for the other buttons. Then, in your callback function, you test this parameter and execute the different actions:
def hello(self, hint):
if hint == "hereiam1":
print("do stuff for hereiam1")
elif hint == ...:
...
However, unless all those callbacks are very similar, I'd suggest actually using different callback functions for the different menu buttons.

How to return instance of button pressed in Python-based TKinter

I am trying to access the label of a button in Tkinter, when the button is pressed. This involves returning a reference to the target button pressed.
Currently, as I have to input arguments, this is done by binding the command option to the lambda function i.e.
button['command'] = lambda: fun_to_call(arg)
Is there any way to return the instance? I have checked the TKDocs and it does not cover. Also, I have tried using a separate list of strings instead to get the label. However, it only returns the last element of the list (I believe this is due to the lambda function not binding the specific element to the list when creating the button instance. I have previously used this list to generate the list of buttons.)
In short, an event-based function bound to the button which returns its parent (the button being pressed).
def add_callback(control, fun):
def inner():
return fun(control)
control['command'] = inner
...
def test_callback(button):
print "button instance:", button
b = Button(text="click me")
add_callback(b, test_callback)
more declarative:
def with_callback(control, fun):
def inner():
return fun(control)
control['command'] = inner
return control
...
b = with_callback(Button(text="click me"), test_callback)

Categories

Resources