2009-07-29 15 views
5

Dưới đây là các trường hợp thử nghiệm ...Tkinter khóa Python khi một biểu tượng được tải và tk.mainloop là trong một thread

import Tkinter as tk 
import thread 
from time import sleep 

if __name__ == '__main__': 
    t = tk.Tk() 
    thread.start_new_thread(t.mainloop,()) 
    # t.iconbitmap('icon.ico') 

    b = tk.Button(text='test', command=exit) 
    b.grid(row=0) 

    while 1: 
     sleep(1) 

Mã này hoạt động. Bỏ ghi chú dòng t.iconbitmap và nó khóa. Sắp xếp lại nó theo bất kỳ cách nào bạn thích; nó sẽ khóa.

Làm cách nào để ngăn chặn tk.mainloop khóa GIL khi có biểu tượng?

Mục tiêu là win32 và Python 2.6.2.

Trả lời

16

Tôi tin rằng bạn không nên thực hiện vòng lặp chính trên một chuỗi khác. AFAIK, vòng lặp chính sẽ được thực hiện trên cùng một luồng tạo tiện ích con.

Bộ công cụ GUI mà tôi quen thuộc (Tkinter, .NET Windows Forms) là như vậy: Bạn chỉ có thể thao tác GUI từ một chuỗi.

Trên Linux, mã của bạn đặt ra một ngoại lệ:

 
self.tk.mainloop(n) 
RuntimeError: Calling Tcl from different appartment 

Một trong những điều sau đây sẽ làm việc (không đề phụ):

if __name__ == '__main__': 
    t = tk.Tk() 
    t.iconbitmap('icon.ico') 

    b = tk.Button(text='test', command=exit) 
    b.grid(row=0) 

    t.mainloop() 

Với chủ đề phụ:

def threadmain(): 
    t = tk.Tk() 
    t.iconbitmap('icon.ico') 
    b = tk.Button(text='test', command=exit) 
    b.grid(row=0) 
    t.mainloop() 


if __name__ == '__main__': 
    thread.start_new_thread(threadmain,()) 

    while 1: 
     sleep(1) 

Nếu bạn cần giao tiếp với tkinter từ bên ngoài sợi tkinter, tôi đề nghị bạn thiết lập một bộ đếm thời gian kiểm tra hàng đợi cho công việc.

Dưới đây là một ví dụ:

import Tkinter as tk 
import thread 
from time import sleep 
import Queue 

request_queue = Queue.Queue() 
result_queue = Queue.Queue() 

def submit_to_tkinter(callable, *args, **kwargs): 
    request_queue.put((callable, args, kwargs)) 
    return result_queue.get() 

t = None 
def threadmain(): 
    global t 

    def timertick(): 
     try: 
      callable, args, kwargs = request_queue.get_nowait() 
     except Queue.Empty: 
      pass 
     else: 
      print "something in queue" 
      retval = callable(*args, **kwargs) 
      result_queue.put(retval) 

     t.after(500, timertick) 

    t = tk.Tk() 
    t.configure(width=640, height=480) 
    b = tk.Button(text='test', name='button', command=exit) 
    b.place(x=0, y=0) 
    timertick() 
    t.mainloop() 

def foo(): 
    t.title("Hello world") 

def bar(button_text): 
    t.children["button"].configure(text=button_text) 

def get_button_text(): 
    return t.children["button"]["text"] 

if __name__ == '__main__': 
    thread.start_new_thread(threadmain,()) 

    trigger = 0 
    while 1: 
     trigger += 1 

     if trigger == 3: 
      submit_to_tkinter(foo) 

     if trigger == 5: 
      submit_to_tkinter(bar, "changed") 

     if trigger == 7: 
      print submit_to_tkinter(get_button_text) 

     sleep(1) 
+2

Vâng, bạn đã nhấn đinh trên đầu, nó hoạt động ... nhưng tôi đã phải chịu đựng từ việc không cung cấp đủ thông tin. Lý do của tôi là tôi muốn có thể làm những việc để tìm kiếm nơi vòng lặp trong ... Có một chút mới đối với SO, tôi có nên chấp nhận câu trả lời của bạn và hỏi một câu hỏi dài dòng hơn không? – burito

+2

Xin chào, tôi đã cập nhật câu trả lời của tôi với một đề xuất và ví dụ mã để thực hiện điều này. Vòng lặp while bây giờ gọi một vài phương thức trên chuỗi tkinter, sử dụng hàng đợi yêu cầu/đáp ứng. – codeape

+2

BTW, cho mã sản xuất Tôi đề nghị bạn đóng gói cửa sổ, chuỗi và hàng đợi Tkinter trong một lớp. Điều này để tránh các globals chúng ta có: request_queue, response_queue và t. Bạn cũng cần xử lý lỗi xung quanh có thể gọi (* args, ** kwargs). – codeape

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