I cannot make the checkbox to give a "1" value when its marked and the button is clicked. I don't know if the problem is within the checkbutton code or I am transferring the data between functions wrong
import tkinter as tk
from tkinter import ttk as ttk
var_koszula1=2
class Aplikacja(tk.Frame):
def __init__(self, *args, **kwargs):
tk.Frame.__init__(self, *args, **kwargs)
self.grid()
self.var_koszula1=tk.IntVar(self)
tk.Checkbutton(self, text='MARK', variable=var_koszula1).grid()
print(self.var_koszula1.get())
tk.Button(self, height=1, width=15, text=("Click"), command= self.create_window_edit).grid()
def create_window_edit(self):
t = tk.Toplevel(self)
tk.Label(t, text=("Done")).grid()
print(self.var_koszula1.get())
root= tk.Tk()
root.title("Szaffa")
app= Aplikacja(root)
root.mainloop()
You cannot use a normal variable with the variable attribute. It must be one of the special tkinter variables StringVar, IntVar, DoubleVar or BooleanVar.
You probably just need to change this:
tk.Checkbutton(..., variable=var_koszula1).grid()
To this:
tk.Checkbutton(..., variable=self.var_koszula1).grid()
Related
I was curious if it is possible to create an clickable element that contains multiple elements?
ttk.Button appears to take text or an image.
I would like to have a clickable element that will have 8 text items and 2 images inside it. Clicking anywhere in that element will trigger the same backend method.
Any code examples would be helpful as still wading through TKinter -- only my second project to use it.
Use bindtags and give the same tag for all widgets that you want to be clickable, then use bind_class to bind all the widgets.
Here's an example
import tkinter as tk
def clicked(event):
print("Clicked !")
class ClickableElement(tk.Frame):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.bindtags('Click') # or pass a list if you want to have multiple tag names
for x in range(8):
lbl = tk.Label(self, text=f"Text {x}")
lbl.bindtags('Click')
lbl.pack()
root = tk.Tk()
root.geometry("200x200")
frame = ClickableElement(root) # or tk.Frame(root, class_='Click')
frame.pack(fill='both', expand=True)
frame2 = tk.Frame(root, bg='red')
frame2.pack(expand=True, fill='both')
root.bind_class('Click', "<Button-1>", clicked)
root.mainloop()
The above example will make both text and Frame clickable. You can expand on this to include images. Alternatively, You can use bind on each widget inside the frame.
What you can do is get the children of the tk.Frame and bind them to a function.
from tkinter import *
from tkinter import messagebox
class ClickFrame:
def __init__(self,root):
self.root = root
self.root.geometry("700x500")
Label(self.root,text="Clickable Frame!",font=("arial",15)).pack(fill=X,side=TOP)
self.Frame1 = Frame(self.root,bg="light grey")
self.Frame1.pack(fill=BOTH,expand=1,padx=100,pady=100)
for i in range(8):
Label(self.Frame1,text=f"This is Label {i}").pack(pady=5,anchor="w",padx=5)
self.Frame1.bind("<Button-1>",self.detect_click)
for wid in self.Frame1.winfo_children():
wid.bind("<Button-1>",self.detect_click)
def detect_click(self,event,*args):
messagebox.showerror("Clicked",f"Clicked the widget {event.widget}")
print(event.widget,type(event.widget))
root=Tk()
ob=ClickFrame(root)
root.mainloop()
You also can use bind_all() to bind . However, this will bind everything in the window.
from tkinter import *
from tkinter import messagebox
class ClickFrame:
def __init__(self,root):
self.root = root
self.root.geometry("700x500")
Label(self.root,text="Clickable Frame!",font=("arial",15)).pack(fill=X,side=TOP)
self.Frame1 = Frame(self.root,bg="light grey")
self.Frame1.pack(fill=BOTH,expand=1,padx=100,pady=100)
for i in range(8):
Label(self.Frame1,text=f"This is Labe {i}").pack(pady=5,anchor="w",padx=5)
self.Frame1.bind_all("<Button-1>",self.detect_click)
def detect_click(self,event,*args):
messagebox.showerror("Clicked",f"Clicked the widget {event.widget}")
root=Tk()
ob=ClickFrame(root)
root.mainloop()
I am working on simple application trying to utilize MVC pattern. The problem I found (which I predict is a really silly one, but I lost my rubber duck) is two tkinter apps are created where I expect just a single one. Moreover, second one is instantiated but is not visible what made me mad initially as I didn't know it exists ;-)
Smells to me like another Tk() instance is being created, but donno when, where and why.
When I replace root = Main() with root = tk.Tk() in AppDelegte everything works like a charm and just one app window is created, as intended.
App is created on following code:
App delegate
from controller.main import Main
root = Main()
root.mainloop()
Main controller
import tkinter as tk
from tkinter import ttk
from view.actual_readings import ActualReadings
class Main(tk.Tk):
actual_readings = ActualReadings(None)
def __init__(self):
super().__init__()
main_frame = ttk.Frame(self, padding="25")
main_frame.grid(column=0, row=0)
self.actual_readings.master = main_frame
self.actual_readings.grid(column=0, row=0)
Readings view
from tkinter import *
from tkinter import ttk
class ActualReadings(ttk.Frame):
def __init__(self, master, **kwargs):
super().__init__(master, **kwargs)
header = ttk.Label(self, text="header text", font="TkFixedFont", padding="75 25 75 10")
current_value_lbl = ttk.Label(self, text="current value",
font="TkFixedFont")
current_value_val = ttk.Label(self, text="here comes reading", font="TkFixedFont")
header.grid(column=0, row=0, columnspan=2)
current_value_lbl.grid(column=0, row=1, sticky=E)
current_value_val.grid(column=1, row=1, sticky=W)
It is because when you create Main (a Tk() instance), its class member actual_readings is created first. Since its parent is None which causes a default instance of Tk() being created. So there will be two Tk() instances.
To fix the issue, you should create actual_readings inside __init__() function:
class Main(tk.Tk):
actual_readings = None
def __init__(self):
super().__init__()
main_frame = ttk.Frame(self, padding='25')
main_frame.grid(row=0, column=0)
if self.actual_readings is None:
self.actual_readings = ActualReadings(main_frame)
self.actual_readings.grid(row=0, column=0)
I'd like to have a button, which is only performing a command after some criterion is fulfilled.
This is our button :
import tkinter as tk
from matplotlib import *
from tkinter import ttk, messagebox, filedialog
class Hauptmenu(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
ttk.Button(self, text='Button', command=self.doSomething).grid(row=7,column=4, sticky="w")
clickability_criterion=False
So I want the button to be functional after I set the criterion to True.
Is there any elegant way to achieve this?
There's a state field when you define a button, that you can set to either ENABLED or DISABLED. You can define your button do be DISABLED at startup, like that:
import tkinter as tk
from matplotlib import *
from tkinter import ttk, messagebox, filedialog
tk = tk.Tk()
myButton = ttk.Button(tk, text='Button', command=self.doSomething, state = 'disabled')
myButton.grid(row=7,column=4, sticky="w")
When some condition is met you can change the status to NORMAL:
myButton['state'] = 'normal'
This should do the trick.
EDIT: as for the runtime update I'd define a method in your class updating the status for you, something like that:
class Hauptmenu:
def __init__(self, parent):
self.myParent = parent
self.myContainer = tk.Frame(parent)
self.myContainer.pack()
self.button = tk.Button(self.myContainer)
self.button.configure(text="Button", command=self.doSomething, state = 'disabled')
self.button.pack()
def doSomething(self):
print('This button has been pressed')
def changeButtonState(self, state):
self.button['state'] = state
root = tk.Tk()
c = Hauptmenu(root)
c.changeButtonState('normal')
tk.mainloop()
you can create a disabled button like so:
ttk.Button(self, text='Button', state = ttk.DISABLED, command=self.doSomething).grid(row=7,column=4, sticky="w")
and then enable it like so:
variable_inwhich_button_is_saved.configure(state=ttk.ENABLED)
I have a small GUI app in Python that uses Tk. It has several filters --- a text entries (they set filter values) with checkboxes (which set filter on/off). I create filters as a class inhetrited from ttk's Labelframe:
from tkinter.ttk import Labelframe
import tkinter as tk
class FilterWidget(Labelframe):
def __init__(self, parent, label):
Labelframe.__init__(self, parent, text=label)
self.grid()
self._entry = tk.Entry(self)
self._entry.grid(row=0, column=0)
self._checkbox = tk.Checkbutton(self, command=lambda: print(self))
self._checkbox.grid(row=0, column=1)
Then I create several instances of this class and place them in GUI:
root = tk.Tk()
source_filter = FilterWidget(root, "Source")
source_filter.grid(row=0, column=0)
level_filter = FilterWidget(root, "Severity")
level_filter.grid(row=0, column=1)
root.mainloop()
The widgets are created and correctly displayed. However, when one of the checkboxes is clicked and changes state, the other changes state as well!
When diffrent checkboxes are clicked, print command outputs .!filterwidget and .!filterwidget2, so those are separate objects. It seems that they are somehow implicitly syncronized, but I have no idea how did this happend.
So, the question is: how to remove this dependancy and make checkboxes independant of each other?
As the docs mention,
To use a Checkbutton, you must create a Tkinter variable. To inspect
the button state, query the variable.
Here's your code updated to use an IntVar to store the Checkbutton state.
from tkinter.ttk import Labelframe
import tkinter as tk
class FilterWidget(Labelframe):
def __init__(self, parent, label):
Labelframe.__init__(self, parent, text=label)
self._entry = tk.Entry(self)
self._entry.grid(row=0, column=0)
self._var = tk.IntVar()
callback = lambda: print(self._entry.get(), self._var.get())
checkbox = tk.Checkbutton(self, variable=self._var, command=callback)
checkbox.grid(row=0, column=1)
root = tk.Tk()
source_filter = FilterWidget(root, "Source")
source_filter.grid(row=0, column=0)
level_filter = FilterWidget(root, "Severity")
level_filter.grid(row=0, column=1)
root.mainloop()
I'm working on my very first Python GUI and I'm trying to modify this tkinter example, but I simply cannot figure out how to write a callback function for the OK button that will pass on the entered value to the main program.
#!/usr/bin/python
# -*- coding: utf-8 -*-
from Tkinter import Tk, BOTH, StringVar, IntVar
from ttk import Frame, Button, Style, Label, Entry
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Get Value")
self.style = Style()
self.style.theme_use("default")
self.pack(fill=BOTH, expand=1)
valueLabel = Label(self, text="Value: ")
valueLabel.place(x=10, y=10)
value=StringVar(None)
value.set("this is the default value")
valueEntry=Entry(self, textvariable=value)
valueEntry.place(x=70, y=10)
quitButton = Button(self, text="Quit", command=self.quit)
quitButton.place(x=10, y=50)
okButton = Button(self, text="OK", command=self.quit)
okButton.place(x=120, y=50)
def main():
root = Tk()
root.geometry("220x100+300+300")
app = Example(root)
root.mainloop()
if __name__ == '__main__':
main()
I've read a gazillion of tutorials, but none of them explains this clearly. Theoretically, I should be able to get the selected value with value.get(), but I keep getting error messages no matter where I put it. Also, AFAIK, I should be able to define a default value with value.set(), but this doesn't seem to have an effect, since the text box is empty when I run the program.
What is the easiest way to pass on values to the main python program after root.mainloop() terminates? (The actual dialog box contains several entry boxes for entering string and integer values.)
I.e. I want to be able to use something like:
root = Tk()
root.geometry("220x100+300+300")
app = Example(root)
root.mainloop()
print value
print value2
print value3
How do I define default values for entry boxes?
Change every occurrence of the value variable with self.value. This should fix it and the default value will be displayed.
UPDATE
from Tkinter import Tk, BOTH, StringVar, IntVar
from ttk import Frame, Button, Style, Label, Entry
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def showMe(self):
print(self.value.get())
def initUI(self):
self.parent.title("Get Value")
self.style = Style()
self.style.theme_use("default")
self.pack(fill=BOTH, expand=1)
valueLabel = Label(self, text="Value: ")
valueLabel.place(x=10, y=10)
self.value=StringVar(None)
self.value.set("this is the default value")
valueEntry=Entry(self, textvariable=self.value)
valueEntry.place(x=70, y=10)
quitButton = Button(self, text="Quit", command=self.quit)
quitButton.place(x=10, y=50)
okButton = Button(self, text="OK", command=self.showMe)
okButton.place(x=120, y=50)
def main():
root = Tk()
root.geometry("220x100+300+300")
app = Example(root)
root.mainloop()
if __name__ == '__main__':
main()
Both your quitButton and okButton call the self.quit functions. So no mater what value you enter when you press the OK button you are calling the quit function which has its own problems as well outside the scope of your question.
Try to define value as self.value and make the okButton call a function that does: print self.value.get().