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 值 x
和 v
。如果你想在线程和 GUI 之间进行通信,你必须使用队列和一个单独的事件循环,它检查队列并用 after
.
再次调用自己
甚至 Qt 也不是线程安全的,某些线程可以更改 GUI。但是它有signal-slot-concept,它以更方便的方式代替队列进行通信。
我正在 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 值 x
和 v
。如果你想在线程和 GUI 之间进行通信,你必须使用队列和一个单独的事件循环,它检查队列并用 after
.
甚至 Qt 也不是线程安全的,某些线程可以更改 GUI。但是它有signal-slot-concept,它以更方便的方式代替队列进行通信。