2013-06-11 52 views
5

Làm cách nào để sinh ra các cửa sổ con Toplevel() trong tkinter không đóng khi cha mẹ đóng?Làm cửa sổ tokinter tkinter không sát với bố mẹ

Tôi có cần cha mẹ giữ 'số lượng tham chiếu' của cửa sổ con, chặn WM_DELETE_WINDOW và chỉ gọi root.destroy() khi tất cả các trẻ em đã mất?

Hoặc thực tiễn có thể chấp nhận để sinh ra một quy trình chủ đề khác với tk mainloop của riêng mình?

Hoặc có cách nào thanh lịch hơn không?

EDIT

Tôi hiện đang làm việc theo cách này

root = Tk() 
app = App(root) # doesn't call Toplevel() 
root.mainloop() 

nơi App.__init__() thêm widget để root mà không gọi Toplevel(), và tại một số điểm spawns một cửa sổ mới với chức năng này:

def new_window(): 
    root = Tk() 
    window = App2(root) # doesn't call Toplevel() either 

Lưu ý rằng root trong new_window() là một biến khác với số gốc root, thu được bằng một cuộc gọi khác đến Tk().

Tất cả điều này dường như làm điều đúng nghĩa là cửa sổ con sống độc lập với cha mẹ và quá trình python chết sau khi cả hai được đóng lại.

Vì vậy, câu hỏi của tôi trở nên, điều đó có ý nghĩa hay tôi đang làm điều gì đó khủng khiếp sai ở đây?

Trả lời

1

Thay vì phải theo dõi Toplevels nào còn sống, bạn có thể sử dụng weakref trên một sentinel - chỉ một số đối tượng được truyền cho mỗi Toplevel và được lưu trong tham chiếu. Khi mỗi Toplevel chết (được đóng), hãy để nó xóa tham chiếu của nó đến phần tử gửi. Khi tham chiếu cuối cùng đến sentinel bị xóa, gọi lại yếu, self.no_sentinel sẽ được gọi tự động, lần lượt gọi root.destroy cho bạn.

import Tkinter as tk 
import weakref 


class Sentinel(object): 
    pass 


class Window(tk.Toplevel): 
    def __init__(self, master, sentinel, **kwargs): 
     title = kwargs.pop('title') 
     self.sentinel = sentinel 
     tk.Toplevel.__init__(self, master, **kwargs) 
     self.protocol("WM_DELETE_WINDOW", self.ondelete) 
     self.label = tk.Label(self, text=title) 
     self.label.pack(padx=10, pady=10) 

    def ondelete(self): 
     self.destroy() 
     del self.sentinel 


class App(object): 
    def __init__(self, master, **kwargs): 
     self.master = master 
     sentinel = Sentinel() 
     parent = Window(master, sentinel, title='Parent') 
     child = Window(master, sentinel, title='Child') 
     self._ref = weakref.ref(sentinel, self.no_sentinel)    
     # When we exit `__init__` only two strong references to sentinal 
     # remain -- in parent and child. When both strong references are 
     # deleted, `self.no_sentinel` gets called. 
    def no_sentinel(self, *args): 
     self.master.destroy() 

root = tk.Tk() 
root.withdraw() 
app = App(root) 
root.mainloop() 

Ngoài ra, bạn thể sử dụng các mô-đun multiprocessing để đẻ trứng một quá trình để thực hiện một cửa sổ Tkinter và mainloop, nhưng sẽ là người tiêu dùng nhiều bộ nhớ hơn so với giải pháp trên, và sẽ yêu cầu bạn thiết lập một số hình thức interprocess giao tiếp nếu bạn muốn các quy trình riêng biệt chia sẻ thông tin.

+0

Tôi hiện đang có được một thư mục gốc mới với 'tk.Tk()' nhưng không gọi lại 'mainloop()' - điều này dường như hoạt động trong khi đơn giản hơn nhiều - bất kỳ ý tưởng nào có thể là? Bạn sẽ nghĩ rằng 'Tk()' sẽ là một singleton trở về cùng một bậc thầy, nhưng việc tạo ra các widget trên nó dường như không ảnh hưởng đến cửa sổ đầu tiên. –

+0

Btw xem chỉnh sửa của tôi đối với câu hỏi gốc - tôi có nghĩa là quá trình không phải là chuỗi. –

+1

Tôi không hoàn toàn chắc chắn rằng tôi hiểu câu hỏi của bạn. Có một cách đơn giản hơn nhiều so với những gì tôi hiển thị ở trên - chỉ cần sử dụng Toplevels và gọi 'root.withdraw()' - nhưng sau đó bạn có thể đóng tất cả các Toplevels và chương trình vẫn chạy trong nền. Bạn sẽ tích lũy các quá trình zombie theo cách đó. Mục đích của rigmarole ở trên là làm cho chương trình kết thúc khi Toplevel cuối cùng được đóng lại. Nếu tôi không trả lời câu hỏi của bạn, vui lòng đăng mã của bạn. – unutbu

Các vấn đề liên quan