Defined a window as a class, but unable to call mainloop function - python

I am so trash at coding that I have no idea how to utilise classes to make cool stuff :( --- I'm really new to GUI development, and I'm trying to make a simple maze game with a level selector. I have the maze program squared away, but I am somehow hopeless at Tkinter apparently, since I've been trying constantly for the last hour to find a solution online. As you might have noticed, this is my first post here.
I'm running this in PyCharm, using my decent computer on Windows 10. I'm especially trash at this IDE since I, for some reason, cannot install any libraries/ use any libraries that I see clearly installed in my list of libraries... but that's for another post. As I've mentioned, I've been trying to figure out a simple program for the past hour, but nothing seems to be working.
Nothing I find online is particularly useful, either, and the ones that might be are so hopelessly complex that I cannot understand what they are trying to achieve. I'm looking for a simple solution to a simple problem, and hopefully, this great community can help me out.
import tkinter as tk
class Window():
def __init__(self):
self = tk.Tk()
self.geometry("%dx%d+0+0" % (1920,1080))
root = Window()
root.mainloop()
Expected: Window appears
Observed: Program abruptly ends
Error:
Traceback (most recent call last):
File "C:/Users/(GD) ShadowPlague/PycharmProjects/GameDesign/Main.py", line 12, in <module>
root.mainloop()
AttributeError: 'Window' object has no attribute 'mainloop'

You create class in wrong way. You can't assign Tk() to self to create correctly class. External root will have nothing to do with internal self. First you create instance Window() and assign to variable root but later you create instance Tk() and assign to self but it will not change instance assigned to root.
First method: create Tk() inside class as self.root and then you use win.root
import tkinter as tk
class Window():
def __init__(self):
self.root = tk.Tk()
self.root.geometry("%dx%d+0+0" % (1920,1080))
win = Window()
win.root.mainloop()
Second method: inherit from Tk(). It needs Window(tk.Tk) and super().__init__
import tkinter as tk
class Window(tk.Tk):
def __init__(self):
super().__init__()
self.geometry("%dx%d+0+0" % (1920,1080))
root = Window()
root.mainloop()

Related

Continue a code after calling a class method which opens a tkinter window

I have created a class "Node" which creates a binary tree. (I know i can use binarytree module but its a project given to me in DSA subject.)
class Node:
def __init__(self, data) -> None:
#initialisation
def addNode(self, data):
# Code to add data.
def traverse(self):
#traverses the tree and returns a dict
def view(
self,
length=500,
width=1000,
yDist=50,
xDistScale=0.25,
title='Tree View',
):
# shows the tree in a tkinter window as in the screenshot attached
tree = self.traverse()
root = tk.Tk()
self.root=root
root.geometry(str(width)+'x'+str(length))
root.title(title)
# ........ some code which places the nodes on the window using the place() method
root.mainloop()
Now, I import the code in an another file, create an instance of the class add some nodes and call the view() method it works fine but the code after the view() methd does not run till I close the tkinter window.
How can I make the code after view() run without the window being closed?
Its ok if the window is not able to update.
Code where I import and use the node class :
t1 = Node(15)
t1.addNode(12)
t1.addNode(27)
t1.addNode(7)
t1.addNode(14)
t1.addNode(20)
t1.addNode(88)
t1.addNode(23)
t1.view()
# The code here does not run until I close the window.
Output of the above code :
Link to image
I tried googling and also viewed following stackoverflow posts:
Calling a tkinter application from a different class in python,
A code needs to be continued...(Python with Tkinter)
How would I continue to run code after importing a Tkinter file?
Few other websites and guides...
But nothing was helpful.
Please help/guide me.
I am new to StackOverflow and Python.
Thanks in Advance :)
Method 1: Don't update window
You could replace the root.mainloop() with root.update(). This will stop showing any changes to the window. The window will only and always close if the program stops running.
Method 2: using threading
You could useimport threading to run t1.view() in another thread: threading.Thread(target=t1.view).start(). This may result in a Tcl_AsyncDelete error.

Why can't I place this class using the tkinter grid method?

I have an existing Python 3 program which I wrote quick-and-dirty without any object-oriented techniques (it was my first Python program). It's time I clean it up, and I'm having problems making tkinter work in my classes.
Here is a simplified example. It is only attempting to place a ttk.Entry widget into the class, which is inheriting from ttk.Frame:
import tkinter as tk
from tkinter import ttk
class MyClass(ttk.Frame):
def __init__(self, parent):
self.frame = ttk.Frame(parent)
# Entry widget
self.entValue = ttk.Entry(self.frame)
self.entValue.grid(column=0, row=0)
# tkinter init
root = tk.Tk()
# Make the class instance and place it
test = MyClass(root)
test.grid(column=0, row=0)
It gives me the following error:
Traceback (most recent call last):
File "{path_to_code}/so.py", line 17, in <module>
test.grid(column=0, row=0)
File "{path_to_python}\Python35-32\lib\tkinter\__init__.py", line 2072, in grid_configure
self.tk.call(
AttributeError: 'MyClass' object has no attribute 'tk'
What am I missing?
Your Frame hasn't been initialized. Add super().__init__(parent) to the top of your MyClass.__init__ method to allow ttk to initialize the frame.
Also, I think you can get rid of self.frame. Set self as the parent for the widgets in MyClass instead of self.frame.
Please Don't use the GRID method in Tkinter. It's the worst method in Tkinter.
Please use the Place() method to design your GUI. It's very easy to implement.
For more check details over Place() refer to this post how to i position buttons in tkinter?
The place method is not complex like grid(). Check the post to make your GUI better in Python.

Simple Python GUI program won't run, says RESTART

I'm trying to create a python program that pulls up a simple window that displays the text "Hello World?" I've imported tkinter and have created a class called MyGUI that should create a simple window. Then I create an instance of the MyGUI class. When I hit "F5" or run the programming after saving it, I get an error:
RESTART: C:....my filepath.....
>>>
Here is the code:
import tkinter
class MyGUI:
def init (self):
# Create the main window widget.
self.main_window = tkinter.tk()
# Create a Label widget containing the
# text 'Hello World!'
self.label = tkinter.Label(self.main_window, text="Hello World!")
# Call the Label widget's pack method.
self.label.pack()
# Enter the tkinter main loop.
tkinter.mainloop()
# Create an instance of the MyGUI class
my_gui = MyGUI()
What causes the "RESTART" error? Does where I save my .py file matter for this program?
Any help would be greatly appreciated. Thanks
The good news:
Your code works (in that it doesn't crash in python3, as is)!
The bad news:
Your code doesn't do anything :( Your only function would raise an exception if called
You have a code-unrelated problem
To resolve problem #1, change init to __init__ and tkinter.tk to tkinter.Tk()
__init__ is the function called by default on instance construction. The underscores are important if you want to override it. The other issue is just a typo.
You're broader problem is... broader. yes it matters where you save your file. If you don't save it in the place you are running python from, you need to supply an absolute path to it, or a relative path from the place you are running from. This is a broad topic, but pretty important and not too challenging. Maybe try here, or any python tutorial.
I don't know what type F5 does on your computer. I would not in general expect it to run python code. Are you in an IDE, then maybe it does run python code? Are you playing call of duty, because then it's more likely to lob a virtual grenade? F5 is app-dependent, probably not a universal binding on your machine

Multiple application/file/windows instances running on tkinter

Here is a sample situation:
I have written a tk GUI that opens and edits e.g. .txt files. I'm currently on a mac, but I might also want to run this on windows. Currently the main Application class creates its own internal tk.Tk() like so
import tkinter as tk
class App:
def __init__(self):
self.root = tk.Tk()
tk.Label(master=self.root,text="content").pack()
if __name__ == '__main__':
a=App()
a.root.mainloop()
I want to add multi file capabilities to the application. In the current system this would result in 2 tk.Tk() instances running which I couldn't get to work and people say is unpredictable.
I want to be able to close any of the multiple files and still have the application running until the last window is closed and then the application quit or stays without a window (like on a mac).
My problem is that if I use tk.Toplevel() for each of my windows I have a ugly default tk.Tk() window which I would need to hide which seams inelegant. It would also be messy to determine which file is currently in focus for actions with the menubar.
I'm also considering each file being it's own application instance like on Windows, but that would fill the dock with repeated icons and be inconsistent with the rest of the system.
Here are the possible way I came up with:
Multiple Tks (Works but more complex examples are unpredictable):
import tkinter as tk
class App:
def __init__(self):
self.root = tk.Tk()
tk.Label(master=self.root,text="content").pack()
tk.Button(master=self.root,text="new_window",command=self.open).pack()
def open(self):
App()
if __name__ == '__main__':
a=App()
a.root.mainloop()
Hidden tk window and multiple Toplevels (Needs hiding the Tk and the osx menubar commands like view->change_colors would need to manaly decide where to direct comands):
import tkinter as tk
class App:
def __init__(self):
self.root = tk.Toplevel()
tk.Label(master=self.root,text="content").pack()
tk.Button(master=self.root,text="new_window",command=self.open).pack()
def open(self):
App()
if __name__ == '__main__':
tk.Tk()
a=App()
a.root.mainloop()
Each Window is its own Application and fully independant (Dosn't fit in with the other mac applications, the implementation is ugly):
#!/usr/local/bin/python3
import tkinter as tk
import sys,os
class App:
def __init__(self):
self.root = tk.Tk()
tk.Label(master=self.root,text="content").pack()
tk.Button(master=self.root,text="new_window",command=self.open).pack()
def open(self):
os.system(sys.argv[0]+"&")
if __name__ == '__main__':
a=App()
a.root.mainloop()
I was alos think of maybe doing it with threads but I think I must be over thinking it so I came here.
Is there a generally accepted way of doing this in tk?
The generally accepted way is just like you describe: use Toplevel for additional windows, and hide the root window if you don't want to see it.
Another choice is to make your main program a non-GYI app, and each window is created by spawning a new process.
Hidden tk window and multyple Toplevels (Needs hiding the Tk and the osx menubar commands like view->change_colors would need to manaly decide where to direct comands):
It is easy to get into "which goes with what" hell with multiple Toplevels. Instead create a separate class for each new Toplevel with built in responses to button clicks, etc. Pass "root" to the class and let it create, update, and destroy as necessary, and keep track of it's own variables. If you want to use variables elsewhere, then store the class instance when the Toplevel classes are called and create the variables within the class as instance attributes.

Make Tkinter window not always on top

I have a simple program as follows:
from Tkinter import *
class Run:
def __init__(self,parent):
parent.overrideredirect(True)
root = Tk()
app = Run(root)
root.mainloop()
When I run this program, the undecorated root window always stays on top.
How can I make it so any other window can be on top of it, whilst having no decorations?
I have tried setting 'topmost' to 'False' as well, but to no avail.
I am running Ubuntu 13.04.
Thanks in advance
This code below, will put your window on the background on every 100ms, no matter what, so everything will be in the front of it all the time. I think this is what you were asking for:
from tkinter import *
class Run:
def __init__(self):
self.root = Tk()
self.root.overrideredirect(True)
def put_back(self):
# this method will put the window to the background
self.root.lower()
# recursive calling of put_back method
self.root.after(100, self.put_back)
app = Run()
# Start the recursion
app.put_back()
app.root.mainloop()
Seems like this should happen automatically if I click a different window.

Categories

Resources