Tkinter window 即使使用线程也不响应

Tkinter window does not respond even with threading

我正在 Python 中使用 TKinter 构建一个简单的 GUI。我有一个浏览按钮,可以浏览计算机上的文件并打开所选文件。选择文件后,将调用一个函数来打开文件并开始读取它。但是,在我单击按钮后,window 不再响应。当我搜索时,我发现这是因为 TKinter 是单线程的,主 gui 线程可能会因某些任务而卡住,但即使在我使用了一些简单的线程后,window 仍然会冻结。

这是我正在做的示例代码,

   import threading


from Tkinter import *
from PyQt4 import *
from tkFileDialog import askopenfilename
import numpy as np
import xlrd

global columnList

def open_file (file_name):
    #fileName=input ("Enter file name (example.dat)")
    #colCount= input ("Enter number of columns in the file")

    try:
        workbook = xlrd.open_workbook(file_name)
        sheet=workbook.sheet_by_index(0)
        columns = []
        for i in range (0,sheet.ncols-1):
           columns.append(np.array (sheet.col_values(i,1))) # make a list, each index has a numpy array that represnts a column.
           if (i!=0):
               columns[i]= columns[i].astype(np.float)
        #Preprocessing depth:
        m= columns [0]
        for i in range (m.shape[0]):
            m[i]= m[i]*2 +1

        m=m.astype(np.int)
        columns[0]=m

        print( sheet.row_values(0,sheet.ncols) )
        # removing nans:
        index=input("enter the column index to interpolate: ")
        m= columns [index]
        for i in range (m.shape[0]-1, -1, -1):
            if (np.isnan(m[i])):
                m=np.delete(m,i)
                columns[0]=np.delete(columns[0],i)
                columns [index]= np.delete(columns[index],i)

    except IOError:
        print ("The specified file was not found")

    return columns [0], columns [index]


class Interface:
    def __init__(self, master):
        #frame= Frame (master)
        #frame.grid (sticky=Y)

        self.title= Label(master,text="Kriging Missing data Imputation", fg="blue", font=("Helvetica", 18))
        self.select_file= Label (master, text="Select the file that contains the data (must be an excel file): ", font=("Helvetica", 12))


        self.title.grid (row=1, column=5, columnspan= 4, pady= (20,0))
        self.select_file.grid (row=3, column=1, sticky=W, pady=(20,0), padx=(5,2))
        self.browse_button= Button (master, text="Browse", command=self.browser, font=("Helvetica", 12), width=12)
        self.browse_button.grid (row=3, column=3, pady=(20,0))

        self.varColumn= StringVar(master)
        self.varColumn.set("depth")
        self.columnLabel= Label(master,text="Select a column to process", font=("Helvetica", 12))

        self.columnList= OptionMenu (master, self.varColumn,"nan", "?", "*")

        self.columnLabel.grid (row=5, column=1, pady=(20,0), sticky=W, padx=(5,0))
        self.columnList.grid(row=5, column= 3, pady= (20,0))


        self.missing_label= Label(master, text="Select missing data indicator: ", font=("Helvetica", 12))
        self.var = StringVar (master)
        self.var.set("nan")
        self.menu= OptionMenu (master, self.var,"nan", "?", "*")

        self.missing_label.grid (row=7, column=1, padx=(5,2), pady= (20,0), sticky=W)
        self.menu.grid(row=7, column=3, pady= (20,0))

        self.extrapolate= Label (master, text="Select a range for extrapolation (max=800): ", font=("Helvetica", 12))
        self.max_extra= Entry (master)

        self.extrapolate.grid (row=9, column=1, padx=(5,2), pady= (20,0),  sticky=W)
        self.max_extra.grid (row=9, column=3, pady=(20,0))

        self.a_label= Label (master, text="enter the value of a (range): ", font=("Helvetica", 12))
        self.a_value= Entry (master)

        self.a_label.grid (row=11, column=1, padx=(5,2), pady=(20,0),  sticky=W)
        self.a_value.grid (row=11, column=3,  pady=(20,0))


        self.start_button= Button (master, text="Start", font=("Helvetica", 12), width=12)
        self.pause_button= Button (master, text= "Pause", font=("Helvetica", 12),width=12)
        self.stop_button= Button (master, text="stop", font=("Helvetica", 12),width=12)

        self.start_button.grid (row=13, column=1, pady=(30,0) )
        self.pause_button.grid (row=13, column=2, pady=(30,0))
        self.stop_button.grid (row=13, column=3, pady=(30,0))



    def browser (self):
        filename = askopenfilename()
        x,v= threading.Thread (target=open_file(filename))
        #open_file(filename)
        # we must then send the file name to the function that  reads it somehow.

window= Tk () #main window.
starter= Interface (window)


window.mainloop() #keep the window open until the user decides to close it.

我读到Tkinter不是线程安全的,我可能在其他一些函数中使用了一些线程,那么如何解决使用线程冻结的问题?或者,我应该使用另一个 GUI 构建器,如 PyQt4 吗?

感谢任何帮助。

谢谢。

你没有使用线程。您正在调用 open_file 并尝试从其 return 值开始一个新线程。您必须使用该函数作为参数,而不是调用它:

th = threading.Thread(target=open_file, args=(filename,))
th.start()

下一点是,线程没有 return 值。当线程结束时,您的 browser-函数早就结束了。所以你无法获得 return 值 xv。如果你想在线程和 GUI 之间进行通信,你必须使用队列和一个单独的事件循环,它检查队列并用 after.

再次调用自己

甚至 Qt 也不是线程安全的,某些线程可以更改 GUI。但是它有signal-slot-concept,它以更方便的方式代替队列进行通信。