【问题标题】:Tkinter window does not respond even with threading即使使用线程,Tkinter 窗口也不响应
【发布时间】:2015-09-22 13:52:57
【问题描述】:

我正在用 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 构建器吗?

感谢任何帮助。

谢谢。

【问题讨论】:

    标签: python multithreading user-interface tkinter thread-safety


    【解决方案1】:

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

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

    下一点是,线程没有返回值。线程完成后,您的 browser-function 早就完成了。所以你不能得到xv的返回值。如果你想在线程和 GUI 之间进行通信,你必须使用队列和一个单独的事件循环,它会检查队列并再次使用 after 调用自身。

    即使 Qt 也不是线程安全的,某些线程可以改变 GUI。但它有信号槽的概念,它以更方便的方式代替了通信队列。

    【讨论】:

    • 谢谢你现在它没有冻结,但我得到这个错误,x,v= threading.Thread (target=open_file, args=(filename)) TypeError: 'Thread' object is not iterable .你能告诉我如何解决这个错误吗?谢谢。
    • 感谢您提供这个有用的答案。
    • @Dania 请注意,在@Daniels 的回答中,他使用了args=(filename,)(文件名后有逗号)而不是args=(filename))。这样做的目的是传递一个元组而不是单个字符串值。
    • 谢谢保罗,我在写这个帖子时删除了那个逗号。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-18
    • 2021-03-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多