Tkinter窗口即使使用线程也不会响应



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

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

   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不是线程安全的,我可能在其他一些函数中使用了一些线程,那么我如何解决使用线程冻结的问题呢?或者,我应该使用另一个像PyQt4这样的GUI构建器吗?

感谢您的帮助。

谢谢。

您不使用线程。您正在调用open_file,并尝试从它的返回值开始一个新线程。您必须将函数用作参数,而不是调用它:

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

下一点是,线程没有返回值。当线程完成时,browser-函数早就完成了。因此无法获得返回值xv。如果要在线程和GUI之间进行通信,则必须使用队列和单独的事件循环,该循环检查队列并使用after再次调用自身。

即使Qt在某种程度上也不是线程安全的,某些线程可以更改GUI。但它有信号槽的概念,它以一种更方便的方式取代了队列进行通信。

相关内容

  • 没有找到相关文章

最新更新