I am currently stuck on a problem with Python and Tkinter.
I want to create a simple application with its UI made on Tkinter. To do so, I created a class to define my application and I want to create my GUI layout in a separate class function.
However, when I call it, it has no effect on my Tk window (in this particular example, the title is not modified)
Here is the code
from Tkinter import *
fen =Tk()
class test_Tk_class:
def __init__(self):
self.make_title
def make_title(self):
fen.title("Test")
a = test_Tk_class()
fen.mainloop()
Thanks for any help !
You're missing () after self.make_title:
from Tkinter import *
fen =Tk()
class test_Tk_class:
def __init__(self):
self.make_title() # <------------
def make_title(self):
fen.title("Test")
a = test_Tk_class()
fen.mainloop()
Related
When I run my Tkinter code the results end up giving me two Tkinter windows. One has the widgets/items my code says but one is a completely blank window.
file 1-
from tkinter import*
class Screen:
def __init__(self, items):
self.Tk = Tk()
self.items = items
self.Tk.mainloop()
file 2-
from tkinter import*
from Screen import*
class Module1:
def __init__(self):
Test_button = Button(text="Test")
Test_button.pack()
items = Module1()
Mainscreen = Screen(items)
I just want to make a modular Tkinter screen so my code is not that messy 😅
-Just want one/common Tkinter window
I think the trouble is you're going about things backwards a bit. You'll want to import your modules into the Python file containting your "root" window class (aka Screen), rather than the other way around.
The typical way to handle a "root" window class in tkinter usually looks like this, where the class inherits directly from Tk()
# this is the first file...
import tkinter as tk # avoid star imports!
from file2 import Module1 # import your widget classes here
# note that depending on your project structure you may need to do
# 'from .file2 import Module1' instead (this is called a 'relative import')
class Screen(tk.Tk): # the 'Screen' class inherits from 'tk.Tk'
def __init__(self):
super().__init__() # initialize tkinter.Tk()
# instance your module widgets by calling the class like so
# (you'll need to update Module1 as shown below here)
self.mod1 = Module1(self) # 'self' refers to 'Screen', the main window
You'll need to update the Module1 class so it can be bound to your parent Screen
# this is the second file...
import tkinter as tk # again, star imports bad...
class Module1:
def __init__(self, parent): # add the parent parameter
# whenever you instance your 'Module1' class, it will expect a 'parent';
# above, we used self (i.e. 'Screen') - this is where your 'button' is going!
self.parent = parent
test_button = tk.Button(self.parent, text="Test")
test_button.pack()
And you'll run the mainloop() method on an instance of your Screen class at the end of your main Python file like so
# this is the first file again...
if __name__ == '__main__': # if this script is being run at the top level...
app = Screen() # get an instance of your Screen class
app.mainloop() # run the GUI loop
I've built a simple single-script GUI application in Tkinter which works as intended. Since the code for the Tk controls takes up half of the 600 lines script I'm trying to separate the GUI from the main application by putting it in a separate module.
In main.py file I have:
from mytkfile import MainWindow
def main():
"""Main program entry point."""
decks = initialize()
app = App(decks)
app.view.root.mainloop()
if __name__ == '__main__':
main()
In mytkfile.py there is just a huge MainWindow class, which is currently is handling the callbacks to the different interface elements:
import tkinter as tk
from tkinter import ttk
class MainWindow:
def __init__(self, deck):
self.root = tk.Tk()
# ...
The App class in main.py, simplified, looks like this:
class App:
def __init__(self, decks):
self.decks = decks
# ...
self.view = MainWindow(self.deck)
self.updateview()
def updateview(self):
# call several self.view.update_methods
The main window is drawn and basically works as it used to, because MainWindow handles a lot of the data logic itself. However, I would like to change that and have App handle everything and just ask MainWindow to update itself. I am trying to achieve this without App passing itself to MainWindow when instantiating it, because as I understand it a View should not know about its Controller, and should not be calling its own methods to handle data logic.
Problem is, how can I handle e.g. button callbacks in Tk when MainWindow doesn't know anything about App?
After reading various articles on the observer design pattern in Python I've concluded that it's indeed impossible to at least slightly couple the Tkinter view MainWindow class to the model/controller App class in my code. It had been solved by the App class passing itself to the MainWindow, with Tk buttons notifying clicks to callback functions inside App. Works like a charm.
I am relatively new to OOP and I have a problem with my code. In an attempt to arrange my code, I would like to save functions in separate files (here menu.py) and then initialize them through def __init__(self): in class (file name app.py) (better than trying to understand my weird description is to look directly on my code ☻). It returns AttributeError and I have no clue how to repair it. Can anyone help me please? (P.S. if you understand what I am trying to do and you know better way how to do that, please tell me ☻)
app.py
import tkinter
from tkinter import *
from menu import Menu
class App(Menu):
def __init__(self):
self.root = tkinter.Tk()
...
self.Menu_Bar()
...
self.root.mainloop()
menu.py
import tkinter
from tkinter import *
class Menu():
def Menu_Bar(self):
self.menuBar = Menu(self.root)
self.menuBar.add_cascade(label="File", menu = self.fileMenu)
...
self.root.config(menu = self.menuBar)
AttributeError: 'App' object has no attribute 'Menu_Bar'
I want to create a GUI module that I can import in my main program without having to import tkinter there, letting just the module handle everything. Here's how I imagine that it might work:
main.py
import gui as g
def update():
#Update the GUI with new Data from this main program
GUI = g.gui()
gui.after(1000, update)
gui.mainloop()
gui.py
import tkinter as tk
class viewer(tk.Frame):
#Some variables
def __init__(self, parent):
tk.Frame.__init(self, parent)
self.parent = parent
self.initialize(400, 100)
def initialize(self, width, height):
#Initialize some widgets, place them on grid, etc
def start(self):
#Do some other stuff, make a main window, configurations, etc
print('Started!')
Edit: "Don't ask for opinion"
How do I make this work?
import tkinter as tk
import gui as g
root = tk.Tk()
GUI = g.gui(root)
GUI.after(1000, update)
GUI.mainloop()
The above is what I don't want.
I used a workaround that seemed plausible to me:
main.py
import gui
GUI = gui.start()
GUI.after(1000, update)
GUI.mainloop()
gui.py
import tkinter as tk
def start():
root = tk.Tk()
run = viewer(root) # <- The class provided above
return run
I have a question. I thought that a class can be based on an object or previously define class. When I change it into class Application(object): it doesn't work. Can you tell me why it didn't work and why did the code below works or why did class Application(Frame) works? Frame is not a previously define object and not object. Sorry for my English. Here is my code:
# Lazy Buttons
# Demonstrates using a class with tkinter
from tkinter import *
class Application(Frame): #
""" A GUI application with three buttons. """
def __init__(self, master):
super(Application, self).__init__(master)
self.grid()
self.create_widgets()
def create_widgets(self):
""" Create three buttons that do nothing. """
# create the first Button
self.bttn1 = Button(self, text= "I do nothing.")
self.bttn1.grid()
# create second button
self.bttn2 = Button(self)
self.bttn2.grid()
self.bttn2.configure(text="Me too!")
# create third button
self.bttn3 = Button(self)
self.bttn3.grid()
self.bttn3["text"] = "Same here!"
# main
root= Tk()
root.title("Lazy Buttons")
root.geometry("200x85")
app = Application(root)
root.mainloop()
Frame is a previously defined class. It's part of tkinter, which you imported on your first line.
Your Application class extends Frame, which means that it gets methods from Frame and can do everything that a Tk Frame can do, like show widgets. If you don't extend Frame, and only extend object instead, this will not work.
It might be clearer to replace...
from tkinter import *
with...
import tkinter as tk
and fix your references to Tk's classes (they would become tk.Button, tk.Frame and tk.Tk).