Calling a function from a checkbox issues - python

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

Related

Tkinter: How do I properly set parameters of extended Button class?

I am experimenting with creating a customer relationship management program using tkinter and python and would like to have buttons generated based on tables in the database.
The idea is that there is a button for each table in the database, so that the table can be viewed and edited if needed.
I want to have each button look the same and, when clicked, generate a list of table entries into the main frame of my program. To do this, I want to extend the Button() class so that I can keep some attributes concurrent while also defining the display_items function:
class TabButton(Button):
def __init__(self, *args, **kwargs):
super().__init__(Button)
self['bg'] = '#a1a1a1'
self['font'] = ('Agency', 24)
def display_items(self, tab):
pass
#mycursor.execute('SELECT * FROM (%s)', tab)
This last line (above) is what selects data from the correct table in my database - I have commented it out while I figure out the rest of the class. I know what *args and **kwargs do, but I'm not sure what purpose they have in this __init__ function (I'm not very familiar with classes and copied this class from another Stack Overflow post).
To generate the buttons, I referenced a dict instance and assigned each key to a button:
tabs = {
'Table1': '',
'Table2': '',
'Table3': '',
}
for tab in tabs:
row = 0
tabs[tab] = TabButton(side_frame, command=lambda: TabButton.display_items(tab))
tabs[tab].grid(row=row, column=0)
row += 1
The problem is, when I run the program I get this error:
AttributeError: type object 'Button' has no attribute 'tk'
Any and all guidance is welcome!
If you notice any other mistakes in my code, could you please point them out? I'm very new to programming and it will save me making another post on Stack Overflow. :p
Thanks,
J
Super returns a temporary object of that class and let you access its content. Super itself dosent accept any arguments.
Also see the prupose of self in that context.
self represents the instance of the class
Often, the first argument of a method is called self. This is nothing
more than a convention: the name self has absolutely no special
meaning to Python. Note, however, that by not following the convention
your code may be less readable to other Python programmers
Another issue is your use of lambda. Your argument tab will be overwritten (if it isnt stored) by each iteration of your loop. Another issue that you might not intent to use the class for this method you rather want to be calles by the instance, therefor I added the argument self to your method and changed your lambda to make use of the instance.
import tkinter as tk
tabs = {'Table1': '',
'Table2': '',
'Table3': '',
}
root=tk.Tk()
class TabButton(tk.Button):
def __init__(self,master, *args, **kwargs):
#self is a reference to the instance of that object
super().__init__(master)#super dosent need a reference
self['bg'] = kwargs.get('bg','#a1a1a1')
self['font'] = kwargs.get('font',('Agency', 24))
def display_items(self,item):
print(f'{item} to show')
for tab in tabs:
b = TabButton(root) #returns a reference to that object
b.configure(command=lambda btn=b, argument=tab:btn.display_items(argument))
b.pack()
root.mainloop()

Using a variable from one function onto another

I got a problem using variables from one function onto another.
This is my code:
import tkinter as tk
def form ():
textVar = tk.StringVar()
entry0 = tk.Entry(self, textvariable = textVar).pack()
def toPrint():
texto = textVar.get()
print(texto)
def button():
button0 = tk.Button(text="Summit", command = toPrint).pack()
Now the variable being called in toPrint() is local from form(), therefore I can not use it without using global, but that is causing issues with the rest of my code since I'm using form() more than once, is there any other way to solve it?
I would appreciate if the explanation is simple, I'm still a beginner.
I already have searched for this in SO, but I did not manage to understand the answers.
I am a foreigner to English, so firlstly I apologized for my impolite or wrong use of English word. Just want to say I really do not mean it.
And for this question, maybe you could try to put these in the same class. And try to make the variables you want to called several times the attribute of the class.
For example:
class myclass():
def __init__ (self):
self.textVar = tk.StringVar()
self.entry0 = tk.Entry(self, textvariable = textVar).pack()
def toPrint(self):
texto = self.textVar.get()
print(texto)

Tkinter: change class variable when pressing a button

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.

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.

Tkinter button calling method on an object

I have some objects which are all instances of the same class; each object has (as one of its attributes) a tkinter button, and I want each tkinter button to perform a method on the object to which it belongs. I'm not really sure how to go about doing this. I've tried tinkering with lambda functions, and replacing "self" with "self_" in case tkinter was already passing "self" to the button's command, but none of this worked; I'm new to classes and hadn't come across lambda functions before today so it didn't surprise me. Example code is below - please could someone explain how to make it work in a way which is both simple, concise and pythonic, or if such a solution does not exist then provide a work around? Thanks in advance
import tkinter as tk
from tkinter import ttk
class SpecialButton():
def __init__(self, row):
self.button = ttk.Button(root, text="button", command=self.delete)
self.button.grid(row=row, column=1)
self.label = ttk.Label(root, text="label")
self.label.grid(row=row, column=2)
def delete(self):
self.button.forget()
self.label.forget()
#some other stuff
root = tk.Tk()
for row in range(3):
SpecialButton(row)
root.mainloop()
The only problem with your code is that you need to be calling grid_forget instead of forget.
Also, the code is a bit misleading -- the delete method doesn't actually delete anything, it just removes it from view. The widgets still exist and take up memory. Are you aware of that? If you truly want to delete the widgets, call the destroy method.

Categories

Resources