【问题标题】:How do I run multiple tkinter windows simultaneously in Python?如何在 Python 中同时运行多个 tkinter 窗口?
【发布时间】:2016-07-18 19:55:03
【问题描述】:

所以我正在制作一个记笔记的应用程序(类似于 Windows Sticky Notes)。因为我需要同时显示多个笔记,所以我使用了一个继承自 Thread 的类并创建了一个 tkinter 窗口。问题是我的窗户没有同时打开。第二个在第一个关闭后打开。这是代码。我究竟做错了什么?我可以使用另一种方法吗? [现在我只显示我硬编码的笔记。]

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()

【问题讨论】:

  • 使用Toplevel 小部件?

标签: python multithreading tkinter


【解决方案1】:

如果您只需要多个笔记窗口,那么您绝对不需要线程。 Tkinter 非常有能力管理数十或数百个打开的窗口。

只需为除根窗口之外的每个窗口创建Toplevel 的实例。这是一个设计过度的例子:

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()

【讨论】:

    【解决方案2】:

    tkinter 中的顶层不是子类 Thread 只是子类 Toplevel,而是同一应用程序中的一个单独窗口,这听起来正是您想要完成的:

    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
    

    请注意,您可以调用self.title() 来获取窗口的当前标题并调用self.title("new title") 来更改它,而不是将标题存储为属性。

    【讨论】:

    • 谢谢,这成功了!感谢关于标题的建议,我对python很陌生,我理解得很好:)
    • 通常使用名为 title 的属性就可以了,这只是真正需要更改代码以使其与 Toplevel 的子类兼容的唯一事情
    • 如果它在我测试它时没有引发一堆str object is not callable 错误,我会完全按照你的方式保留它。 :)
    • 我还有另一个问题,你能帮我解决this question
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-18
    • 1970-01-01
    • 1970-01-01
    • 2015-09-30
    • 1970-01-01
    • 2015-10-09
    • 1970-01-01
    相关资源
    最近更新 更多