Reputation: 45
so I am making an application that takes notes(similar to Windows Sticky Notes). Since I need to display multiple notes simultaneously, I have used a class which inherits from Thread and also creates a tkinter window. The problem is that my windows do not open simultaneously. The second opens up after the first is closed. Here is the code. What am I doing wrong? Is there another method that I can use? [For now I am just displaying notes I have hard-coded.]
from tkinter import *
from threading import Thread
class Note(Thread):
nid = 0
title = ""
message = ""
def __init__(self, nid, title, message):
Thread.__init__(self)
self.nid = nid
self.title = title
self.message = message
def display_note_gui(self):
'''Tkinter to create a note gui window with parameters '''
window = Tk()
window.title(self.title)
window.geometry("200x200")
window.configure(background="#BAD0EF")
title = Entry(relief=FLAT, bg="#BAD0EF", bd=0)
title.pack(side=TOP)
scrollBar = Scrollbar(window, takefocus=0, width=20)
textArea = Text(window, height=4, width=1000, bg="#BAD0EF", font=("Times", "14"))
scrollBar.pack(side=RIGHT, fill=Y)
textArea.pack(side=LEFT, fill=Y)
scrollBar.config(command=textArea.yview)
textArea.config(yscrollcommand=scrollBar.set)
textArea.insert(END, self.message)
window.mainloop()
def run(self):
self.display_note_gui()
new_note1 = Note(0, "Hello", "Hi, how are you?")
new_note1.start()
new_note1.join()
new_note2 = Note(1, "2", "How's everyone else?")
new_note2.start()
new_note2.join()
Upvotes: 2
Views: 7601
Reputation: 1
Problem statement and the Solutions are wonderful for learning. These kinds of examples are needed for Teaching Multithreaded GUI with python's tkinter module.
I faced a similar issue when I created an App with one thread per GUI idea (common idea, I think). BTW, the error is “RuntimeError: main thread is not in main loop”.
There is another solution I came across using PySimpleGUI package. But that requires a big shift in architecture. I recommend to look at the approach using PySimpleGUI package, It gives some ideas for abstraction on the UI elements.
Upvotes: 0
Reputation: 21453
Instead of subclassing Thread
just subclass Toplevel
, a top level in tkinter is a separate window in the same application which sounds like exactly what you are trying to accomplish:
from tkinter import *
#from threading import Thread #no longer needed
class Note(Toplevel):
nid = 0
#title = "" #this would block the method to override the current title
message = ""
def __init__(self, master, nid, title, message):
Toplevel.__init__(self,master)
self.nid = nid
self.title(title) #since toplevel widgets define a method called title you can't store it as an attribute
self.message = message
self.display_note_gui() #maybe just leave that code part of the __init__?
def display_note_gui(self):
'''Tkinter to create a note gui window with parameters '''
#no window, just self
self.geometry("200x200")
self.configure(background="#BAD0EF")
#pass self as the parent to all the child widgets instead of window
title = Entry(self,relief=FLAT, bg="#BAD0EF", bd=0)
title.pack(side=TOP)
scrollBar = Scrollbar(self, takefocus=0, width=20)
textArea = Text(self, height=4, width=1000, bg="#BAD0EF", font=("Times", "14"))
scrollBar.pack(side=RIGHT, fill=Y)
textArea.pack(side=LEFT, fill=Y)
scrollBar.config(command=textArea.yview)
textArea.config(yscrollcommand=scrollBar.set)
textArea.insert(END, self.message)
#self.mainloop() #leave this to the root window
def run(self):
self.display_note_gui()
root = Tk()
root.withdraw() #hide the root so that only the notes will be visible
new_note1 = Note(root, 0, "Hello", "Hi, how are you?")
#new_note1.start()
#new_note1.join()
new_note2 = Note(root, 1, "2", "How's everyone else?")
#new_note2.start()
#new_note2.join()
root.mainloop() #still call mainloop on the root
note that instead of storing the title as an attribute you can call self.title()
to get the current title of the window and self.title("new title")
to change it.
Upvotes: 2
Reputation: 385940
If all you need is multiple note windows then you definitely don't need threads. Tkinter is quite capable of managing dozens or hundreds of open windows.
Just create instances of Toplevel
for every window except the root window. Here's a somewhat over-engineered example:
import Tkinter as tk
class Notepad(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.text = tk.Text(self, wrap="word")
self.vsb = tk.Scrollbar(self, orient="vertical", comman=self.text.yview)
self.text.configure(yscrollcommand=self.vsb.set)
self.vsb.pack(side="right", fill="y")
self.text.pack(side="left", fill="both", expand=True)
def main():
root = tk.Tk()
Notepad(root).pack(fill="both", expand=True)
for i in range(5):
top = tk.Toplevel(root)
Notepad(top).pack(fill="both", expand=True)
root.mainloop()
if __name__ == "__main__":
main()
Upvotes: 2