I am building an application where I set up a class 'App' and pass the root when creating an App object.
Class App(root):
.....
.....
def main():
root = Tk()
app = App(root)
Then I seen examples where instead of the above setup, the class was inheriting Tk.
import tkinter as tki
class App(tki.Tk):
"""Project Engineer Release Help Tool"""
def __init__(self):
tki.Tk.__init__(self)
I thought this was much cleaner so I implemented the cleaner version. It all works fine but I have been using ttk.Style() and wanted to inherit ttk. I can't seem to get this to work though. Any help welcome.
Edit for clarity (and typo in the first example):
I was doing the following. Note: using ttk.Entry.
from tkinter import ttk
class App():
def __init__(self, root):
self.root = root
self.entry = ttk.Entry(self.root, width=40)
self.entry.grid(sticky='n', padx=6, pady=12, columnspan=2)
self.entry.bind("<Return>", self.return_click)
self.entry.focus()
root = Tk()
app = App(root)
.......
.......
I changed to inheriting Tk and the style/theme of all my widgets have changed. I would like to stick with inheriting from tkinter but I want to use the ttk themed widgets. How would this be achieved ?
Related
I want to create Buttons with a text and define a function that prints me the text on the monitor when i press the button.
Everything works well without classes:
from tkinter import *
from tkinter import ttk
def PressButton():
print(FirstButton.cget('text'))
root = Tk()
root.title("Simple Calculator")
ButtonsFrame = ttk.Frame(root,relief= "groove").grid()
FirstButton=ttk.Button(ButtonsFrame, text=1, command= PressButton)
FirstButton.grid()
root.mainloop()
"1" is printed on the monitor when I press FirstButton.
Because I want to have a lot of Buttons, I created a class MyButton with the parent ttk.Button:
from tkinter import *
from tkinter import ttk
class MyButton(ttk.Button):
def __init__(self, text):
self.text=text
super().__init__()
self.Button=ttk.Button(ButtonsFrame, text=self.text, command=self.PressButton)
def PressButton(self):
print(self.Button.cget('text'))
root = Tk()
root.title("Simple Calculator")
ButtonsFrame = ttk.Frame(root,relief= "groove").grid()
FirstButton=MyButton(1)
FirstButton.grid()
root.mainloop()
Here a button is created but without text at all.
I found out that if I change the super().__init__() to super()._init__(text=self.text) then I get a Button with the right text but the PressButton command doesnt work. I tried diffent things with *args aswell but had no success.
What am I doing wrong? I would appreciate any help.
The main problem is that you're not specifying the parent widget for the parent in the constructor.
Here's corrected version of code:
from tkinter import *
from tkinter import ttk
class MyButton(ttk.Button):
def __init__(self, parent, text):
self.text=text
super().__init__(parent, text=self.text, command=self.PressButton)
def PressButton(self):
print(self.cget('text'))
root = Tk()
root.title("Simple Calculator")
ButtonsFrame = ttk.Frame(root,relief= "groove").grid()
FirstButton=MyButton(ButtonsFrame, 1)
FirstButton.grid()
root.mainloop()
You could've also swapped super(). with this:
super(MyButton,self).__init__(parent, text=self.text,command=self.PressButton)
Which is equal to super().__init__(parent, text=self.text, command=self.PressButton)
You can read more about it here:
https://docs.python.org/3/library/functions.html#super
Here's the code of a window, using tkinter library and OOP. I want to make methods of class App private. But some of them, like method destroy in code below should be public
from tkinter import *
from tkinter import ttk
class App(Tk):
def __init__(self):
super().__init__()
# window settings
self.title("Private Attributes")
self.resizable(width=False, height=False)
root = App() # create window
root.title("Public Attributes") # this shouldn't work
ttk.Label(root, text="Close this window").pack()
ttk.Button(root, text="Close", command=root.destroy).pack() # this should work
root.mainloop()
If you want something that doesn't expose one or more Tk methods, you should use composition rather than inheritance. For example,
class App:
def __init__(self):
self._root = Tk()
self._root.title("Private Attributes")
self._root.resizable(width=False, height=True)
def mainloop(self):
return self._root.mainloop()
root = App()
root.title("Public Attributes") # AttributeError
root.mainloop() # OK
You'll need to decide if the ability to limit access to various Tk methods (remember, you can still access self._root directly, but the name suggests that you are responsible for any errors stemming from doing so) outweighs the amount of boilerplate you'll need to write to expose the methods you do want access to. (Reducing that boilerplate is beyond the scope of this answer.)
I have little python programs to create html, for example insertMedia.py: this takes the name of the media file, puts it in the html code string and writes it to the output file.
insertMedia.py uses tkinter. I have a window with the buttons "insert audio" and 'insert video".
insertMedia.py works well, no problems. Also, I have some more "makehtml" programs, each for a specific task.
I want to have a master window, with buttons, or maybe a menu item for each "makehtml" program.
How can I open and run insertMedia.py from a master window?
Should I put all the "makehtml" programs in a module and import the module?
This code from Bryan Oakley, here in stackoverflow, opens a new window. Can it be modified to open my insertMedia.py?
import Tkinter as tk
def create_window():
window = tk.Toplevel(root)
root = tk.Tk()
b = tk.Button(root, text="Create new window", command=create_window)
b.pack()
root.mainloop()
To show you just the priciple of a common way to do this.
Frist you create a main file with your stuff in main.py wich looks like for exampel:
main.py
import tkinter as tk
import Mod1
root = tk.Tk()
def callback():
m1 = Mod1.Model(root, var='my_html')
b = tk.Button(text='click me', command=callback)
b.grid(column=0,row=1)
root.mainloop()
Then you are creating another script with your Toplevel and stuff in it like this:
Mod1.py
from __main__ import tk
class Model(tk.Toplevel):
def __init__(self, master, var=None):
tk.Toplevel.__init__(self, master)
self.master = master
self.configure(bg="red", width=300, height=300)
b=tk.Button(self,text='print html', command=lambda:print(var))
b.pack()
So what I did here is to create another script with a class with the parent class tk.Toplevel. This means the class becomes a subclass of it. We pass the parameter master wich is root, as you can see in the main.py to get a reference through the interface.
Also note that we imported the Mod1 script and later we reference the Model by Mod1.Model(). You could just import the Model with from Mod1 import Model instead of import Mod1. Also we imported from the main script the reference of tk to work with.
To pass a variabel like a string of your html, you can pass var through the interface. I made it like a kwarg(keyword argument), to make it necessary for the class to initialize you have to delete =None wich is a default vaulue.
Thats all we need to work it out. Have fun!
For more complex stuff you also could do a dictionary with keys and values.
main.py
import tkinter as tk
import Mod1
root = tk.Tk()
def callback():
data_dict = {'key a':'value a','key b':'value b'}
m1 = Mod1.Model(root, dct= data_dict)
b = tk.Button(text='click me', command=callback)
b.grid(column=0,row=1)
root.mainloop()
and Mod1.py
from __main__ import tk
class Model(tk.Toplevel):
def __init__(self, master, dct=None):
tk.Toplevel.__init__(self, master)
self.master = master
self.configure(bg="red", width=300, height=300)
b=tk.Button(self,text='print html', command=lambda:print(dct['key a']))
b.pack()
I have this simple code with self.btn1
from tkinter import Tk, ttk, messagebox
import tkinter as tk
class Main(tk.Frame):
def __init__(self, root):
super().__init__(root)
self.btn1 = ttk.Button(self, text="test")
self.btn1.pack()
if __name__ == "__main__":
root = tk.Tk()
app = Main(root)
app.pack()
root.mainloop()
and this code without self button
from tkinter import Tk, ttk, messagebox
import tkinter as tk
class Main(tk.Frame):
def __init__(self, root):
super().__init__(root)
btn1 = ttk.Button(self, text="test")
btn1.pack()
if __name__ == "__main__":
root = tk.Tk()
app = Main(root)
app.pack()
root.mainloop()
Both of them work similarly, but what's the difference, which one should I use?
The only real difference lies in how easy it is to retrieve the reference to the Button instance should you need one. With the former, it's just app.btn1. With the latter, it's app.winfo_children()[0].
>>> app.winfo_children()[0] is app.btn1
True
The difference is that btn1 is a local variable that is only available in the function in which it is used. self.btn1 is an instance variable that is available in every function within the class.
I am trying to create a program using tkinter and it keeps on giving me this one error:
in __init__ self.master = TK()
NameError: name 'TK' is not defined
I am not sure why it is saying that TK isn't defined when I am importing tkinter, can someone please explain what I am doing wrong.
Here is my code:
from tkinter import *
class App:
def __init__(self):
self.master = TK()
frame = Frame(self.master)
frame.pack()
self.master.minsize(1080,720)
self.master.maxsize(1080,720)
self.master.title("Music Player")
myapp = App()
myapp.mainloop()
It's Tk, not TK. Take a look at this small code given in the documentation of tkinter. The last three lines are here for you.
import tkinter as tk
...
root = tk.Tk()
app = Application(master=root)
app.mainloop()
As a matter of fact, I think you were trying the code from the documentation page, yet you missed it!
It shouldn't be TK; it should be Tk.