首页 文章

Tkinter Toplevel窗口不可移动

提问于
浏览
0

在我的Tkinter应用程序中,我有一个按钮,打开一个Toplevel窗口,用于显示事件日志 . 我需要Toplevel Window能够做的一些事情:

  • 打开时显示以前的日志条目,以及使用新条目更新 .

  • 禁用用户随时移动窗口的能力,同时使用户能够关闭窗口

  • 窗口始终用它固定's top right corner being at the root window' s右上角

我想出了#1 . 我可以打开窗口并显示以前的条目,并在窗口打开时更新这些条目 . 我的问题是#2和#3 .

对于#2我不知道如何禁用用户_1756127的关闭窗口的能力,所以我不知道如何保持该功能完好无损 . 也许是一个带有 self.quit() 按钮的按钮?

至于#3,我不知道该怎么做 . 也许我像谷歌搜索一样,但我似乎无法找到如何实现这一目标 .

这是我目前的代码,它能够正确实现功能#1 .

import tkinter as tk

class guiapp(tk.Frame):

    def __init__(self, master):
        tk.Frame.__init__(self, master)
        self.master = master
        self.value = 0.0
        self.alive = True
        self.list_for_toplevel = []
        btn = tk.Button(self.master, text = "Click", command = self.TextWindow)
        btn.pack()

    def TextWindow(self):
        self.textWindow = tk.Toplevel(self.master)
        self.textFrame = tk.Frame(self.textWindow)
        self.textFrame.pack()
        self.textArea = tk.Text(self.textWindow, height = 10, width = 30)
        self.textArea.pack(side = "left", fill = "y")

        bar = tk.Scrollbar(self.textWindow)
        bar.pack(side = "right", fill = "y")
        bar.config(command = self.textArea.yview)
        self.alive = True
        self.timed_loop()

    def timed_loop(self):
        if self.alive == True and tk.Toplevel.winfo_exists(self.textWindow):
            self.master.after(1000, self.timed_loop)
            self.value += 1
            self.list_for_toplevel.append(self.value)
            self.textArea.delete(1.0, "end-1c")
            for item in self.list_for_toplevel:
                self.textArea.insert('end', "{}\n".format(item))
                self.textArea.see('end')
        else:
            self.alive = False

if __name__ == "__main__":

    root = tk.Tk()
    root.geometry("800x480")
    myapp = guiapp(root)
    root.mainloop()

1 回答

  • 1

    我们可以从 toplevel 窗口的顶部删除工具栏,并阻止用户使用 self.textWindow.overrideredirect(True) 移动窗口 .

    然后我们可以通过获取根窗口位置确保 toplevel 窗口位于右上角,然后将 toplevel 窗口设置为 self.master.winfo_x()self.master.winfo_y() 的相同位置 .

    最后我会添加一个关闭窗口的按钮,因为我们不再拥有 toplevel 窗口的工具栏 .

    更新:我已经添加了 toplevel 窗口保持在根窗口顶部的功能,并在拖动root时使用根窗口移动 .

    我们可以使用 bind() 来跟踪移动根窗口的时间,然后使用一个函数来更新 toplevel 窗口位置以匹配根窗口 .

    我们也可以使用 self.textWindow.attributes("-topmost", True) 告诉tkinter在所有其他窗口之上保留 toplevel 窗口 .

    请查看下面代码的修改版本 . 让我知道您的想法或者您是否有任何疑问 .

    import tkinter as tk
    
    class guiapp(tk.Frame):
    
        def __init__(self, master):
            tk.Frame.__init__(self, master)
            self.master = master
            self.textWindow = None
            self.master.bind("<Configure>", self.move_me)
            self.value = 0.0
            self.list_for_toplevel = []
            btn = tk.Button(self.master, text = "Click", command = self.TextWindow)
            btn.pack()
    
        def TextWindow(self):
            x = self.master.winfo_x()
            y = self.master.winfo_y()
    
            self.textWindow = tk.Toplevel(self.master)
            self.textFrame = tk.Frame(self.textWindow)
            self.textWindow.overrideredirect(True)
            self.textFrame.pack()
            self.textWindow.attributes("-topmost", True)
    
            self.textWindow.geometry('+{}+{}'.format(x+10, y+30))
            self.close_toplevel = tk.Button(self.textWindow, text = "close", command = self.close_textWindow)
            self.close_toplevel.pack()
            self.textArea = tk.Text(self.textWindow, height = 10, width = 30)
            self.textArea.pack(side = "left", fill = "y")
    
            bar = tk.Scrollbar(self.textWindow)
            bar.pack(side = "right", fill = "y")
            bar.config(command = self.textArea.yview)
            self.alive = True
            self.timed_loop()
    
        def close_textWindow(self):
            self.textWindow.destroy()
            self.textWindow = None
    
        def move_me(self, event):
            if self.textWindow != None:
                x = self.master.winfo_x()
                y = self.master.winfo_y()
                self.textWindow.geometry('+{}+{}'.format(x+10, y+30))
    
        def timed_loop(self):
            if self.textWindow != None:
                self.master.after(1000, self.timed_loop)
                self.value += 1
                self.list_for_toplevel.append(self.value)
                self.textArea.delete(1.0, "end-1c")
                for item in self.list_for_toplevel:
                    self.textArea.insert('end', "{}\n".format(item))
                    self.textArea.see('end')
    
    
    if __name__ == "__main__":
    
        root = tk.Tk()
        root.geometry("800x480")
        myapp = guiapp(root)
        root.mainloop()
    

相关问题