2017-07-12 86 views
0

我想用Tkinter UI創建一個python應用程序,並且當前出現以下問題。我正在嘗試設置用戶界面,以使日誌保存在後臺,並且當用戶按下按鈕時,將出現一個「Toplevel」窗口。該窗口顯示日誌,並實時追加更新。到目前爲止,所有這些工作都正常。只有在不存在的情況下才打開Tkniter Toplevel

但是,我想這樣做,如果Toplevel窗口是打開的,那麼它不能再次打開。

此外,主程序在運行時會全屏顯示。這意味着如果日誌窗口打開並且用戶再次與主程序交互,則日誌窗口不再可見。有沒有辦法將Toplevel窗口保持在根窗口之上,即使用戶正在與根窗口進行交互?

這是我一直在擺弄的代碼:

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): 
     #if not tk.Toplevel.winfo_exists(self.textWindow): 
      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() 
    myapp = guiapp(root) 
    root.mainloop() 

我在TextWindow方法(if not tk.Toplevel.winfo_exists(self.textWindow))註釋掉該生產線是什麼,我試圖爲「如果存在的話,不要使用不要讓窗戶「成交。但是運行它,我得到的錯誤:

'guiapp' has no attribute ''textWindow' 

我的意思我明白,程序沒有屬性textWindow存在之前。這就是我首先嚐試使用winfo_exists()的全部原因。

我想知道如果我應該創建一個isOpen布爾值,但問題是我不知道如何檢測窗口關閉時。

任何幫助都是有幫助的。

回答

2

作爲一個簡單的修復,我也只是在構造函數創建self.topLevel。然後,因爲tk.Toplevel.winfo_exists()顯然不能採取無作爲參數,你可以讓你的條件:

if self.textWindow == None or not tk.Toplevel.winfo_exists(self.textWindow): 

那麼不管你總是通過一個有效的頂層到winfo_exists(),和在第一次單擊按鈕時仍會創建TopLevel。

最終的結果是這樣的:

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.textWindow = None 
     self.list_for_toplevel = [] 
     btn = tk.Button(self.master, text = "Click", command = self.TextWindow) 
     btn.pack() 

    def TextWindow(self): 
     if self.textWindow == None or not tk.Toplevel.winfo_exists(self.textWindow): 
      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() 
    myapp = guiapp(root) 
    root.mainloop() 
0

我首先想到的是做一個版本的Toplevel可以對被破壞的反應:

class Skitzafreak(tk.Toplevel): 
    def destroy(self): 
     print('destroyed toplevel') # plus any other code you want to add 
     tk.Toplevel.destroy(self) 

我會禁用單擊該按鈕,使用上面的其他代碼來重新啓用它。

import tkinter as tk 
from tkinter.scrolledtext import ScrolledText 

class Skitzafreak(tk.Toplevel): 
    def destroy(self): 
     self.master.alive = False 
     self.master.btn.config(state=tk.NORMAL) 
     tk.Toplevel.destroy(self) 

class guiapp(tk.Frame): 
    def __init__(self, master): 
     tk.Frame.__init__(self, master) 
     # self.master = master # this line is baked into tkinter widgets; you don't have to repeat it. 
     self.value = 0.0 
     self.btn = tk.Button(self, text = "Click", command = self.open_text_window) 
     self.btn.pack() 
     self.alive = False 

    def open_text_window(self): 
     textWindow = Skitzafreak(self) 
     self.textArea = ScrolledText(textWindow, height = 10, width = 30) 
     self.textArea.pack(side = "left", fill = "y") 
     self.btn.config(state=tk.DISABLED) 
     self.alive = True 
     self.timed_loop() 

    def timed_loop(self): 
     if self.alive: 
      self.after(1000, self.timed_loop) 
      self.value += 1 
      self.textArea.insert('end', "{}\n".format(self.value)) 
      self.textArea.see('end') 

if __name__ == "__main__": 
    root = tk.Tk() 
    myapp = guiapp(root) 
    myapp.pack() 
    root.mainloop() 

另外,請記住使用'self'作爲您的小部件的主人,而不是'self.master'。

1

你只需要在除了初始化self.textWindow來檢查它是否存在:

class guiapp(tk.Frame): 
    ... 
    self.textWindow = None 
    ... 

    def TextWindow(self): 
     if self.textWindow is None or not self.textWindow.winfo_exists(): 
      self.textWindow = tk.Toplevel(self.master) 
      ... 
相關問題