我为实验室编写了一个管道,所以我知道在GUI中插入一个“控制台”是不可能的,所以我用一个Frame制作它并在上面贴上标签。
但问题是,我是线程的初学者,我不知道在循环函数执行后如何使用它将我的标签放入我的框架中。
所以这是我的代码(python 3.x):
########
# IMPORTS #
########
from tkinter import *
from tkinter import ttk
from tkinter.filedialog import *
from tkinter.messagebox import *
import os
import glob
from datetime import date, time, datetime
#########
# FUNCTION #
#########
def OneFile(path1,DB,path2,seq,seq2,typ,path3):
"""
This function is very long, take all the sequences of the input file and BLAST it to the Library DATABASE
path : path to the library databse
DB : library database name
path2 : path of the file with the query sequences
seq : name of the file with the query sequences append with a job ID
seq2 : name of the file with the query sequence
Typ : Nucleotide or Proteine
"""
from datetime import date, time, datetime
import subprocess
import platform
import time
OS = platform.system()
if OS == 'Linux' or OS == 'Darwin':
pathLibrary = path1+'/'
pathSequence = path2+'/'
pathFolder = path3+'/'
if OS == 'Windows':
pathLibrary = path1+'\\'
pathSequence = path2+'\\'
if typ not in [(1,1),(2,2),(1,2),(2,1)]:
showerror('Error : Missing Type !', "You do not choose your type\n(nucleotides or proteins)")
else:
library = DB
if os.path.isfile(pathLibrary+library) != True:
showerror('Error : Missing File !', "You must choose a Library Database file")
else:
if os.path.isfile(pathSequence+seq2) != True:
showerror('Error : Missing File !', "You must choose your sequence file")
else:
if typ == (1,1):
typ = "blastn"
if typ == (2,2):
typ = "blastp"
if typ == (1,2):
typ = "blastx"
if typ == (2,1):
typ = "tblastn"
if OS == 'Linux' or OS == 'Darwin':
t0 = time.time()
query = str(seq2)
blast = str(seq)+'_Blast.txt'
seqs = str(seq)+'_seqs.txt'
subprocess.call(typ+" -query "+pathSequence+query+" -db "+pathLibrary+library+" -evalue 1e-10 -out "+pathFolder+blast, shell=True)
subprocess.call("grep '\(Sbjct\|>\)' "+pathFolder+blast+" > "+pathFolder+seqs, shell=True)
t1 = time.time()
print('Job finish in '+str(round(t1-t0,2))+' seconds')
if OS == 'Windows':
t0 = time.time()
query = str(seq2)
blast = str(seq)+'_Blast.txt'
seqs = str(seq)+'_seqs.txt'
subprocess.call(typ+' -query '+pathSequence+query+' -db '+pathLibrary+library+' -evalue 1e-10 -out '+pathSequence+blast, shell=True)
print('Fichier n° '+str(1)+' '+str(seq2))
subprocess.Popen('findstr "Sbjct >" '+pathSequence+blast+' > '+pathSequence+seqs, shell=True)
t1 = time.time()
print('Job finish in '+str(round(t1-t0,2))+' seconds')
#######
# CLASS #
#######
class GraphicalUserInterface():
#principal application
def __init__(self):
#constructor
self.fen = Tk()
self.fen.title("Starch Enzyme Pipeline")
#first label
self.label1 = Label(self.fen, text="Folder with your set(s) : ")
self.label1.grid(row=0, columnspan=2, sticky="W")
#first button
self.browse1 = Button(self.fen)
self.browse1.config(text="Browse",command=self.folderPath)
self.browse1.grid(row=1,column=0, sticky="W")
#label to show the path
self.varLabel1 = StringVar()
self.pathLabel1 = Label(self.fen, textvariable=self.varLabel1, relief=SUNKEN)
self.pathLabel1.grid(row=1,column=1, sticky="EW")
#second title
self.label2 = Label(self.fen, text="Folder with your library database(s) ")
self.label2.grid(row=2,column = 0, columnspan=2 , sticky="W")
#second button
self.browse2 = Button(self.fen)
self.browse2.config(text="Browse",command=self.folderPath2)
self.browse2.grid(row=3,column=0, sticky="W")
#label to show the path for database
self.varLabel2 = StringVar()
self.pathLabel2 = Label(self.fen, textvariable=self.varLabel2, relief=SUNKEN)
self.pathLabel2.grid(row=3,column=1, sticky = "EW")
#Frame wrappe listBox and other
self.frameListBoxAll = Frame(self.fen)
self.frameListBoxAll.grid(row=6,columnspan=2)
#list box label
self.labListBox1 = Label(self.frameListBoxAll, text="Your sets :",padx=10)
self.labListBox1.grid(row=0,column=0)
self.labListBox2 = Label(self.frameListBoxAll, text="Your library database :",padx=10)
self.labListBox2.grid(row=0,column=1)
#frame with listbox1
self.frame1 = Frame(self.frameListBoxAll, bd=2, relief=SUNKEN)
self.frame1.grid(row=1,column=0)
#frame with listbox1
self.frame2 = Frame(self.frameListBoxAll, bd=2, relief=SUNKEN)
self.frame2.grid(row=1,column=1)
#scrollbar listbox1
self.scrollbar1 = Scrollbar(self.frame1)
self.scrollbar1.grid(row=0,column=1, sticky="NS")
self.scrollbar2 = Scrollbar(self.frame2)
self.scrollbar2.grid(row=0,column=3, sticky="NS")
self.scrollbar3 = Scrollbar(self.frame1, orient=HORIZONTAL)
self.scrollbar3.grid(row=1,column=0, sticky="WE")
self.scrollbar4 = Scrollbar(self.frame2, orient=HORIZONTAL)
self.scrollbar4.grid(row=1,column=2, sticky="WE")
#liste box
self.listeBox1 = Listbox(self.frame1, selectmode=EXTENDED, exportselection=0, yscrollcommand=self.scrollbar1.set, xscrollcommand=self.scrollbar3.set)
self.listeBox1.grid(row=0,column = 0)
self.scrollbar1.config(command=self.listeBox1.yview)
self.scrollbar3.config(command=self.listeBox1.xview)
#liste box2
self.listeBox2 = Listbox(self.frame2, selectmode=EXTENDED, exportselection=0, yscrollcommand=self.scrollbar2.set, xscrollcommand=self.scrollbar4.set)
self.listeBox2.grid(row=0,column = 2)
self.scrollbar2.config(command=self.listeBox2.yview)
self.scrollbar4.config(command=self.listeBox2.xview)
#radioboutton list box 1
self.var = IntVar()
for item in [1,2]:
if item == 1:
self.rb = Radiobutton(self.frameListBoxAll, text='Nucleotides',value=item,variable=self.var)
self.rb.grid(row=2, column=0)
if item == 2:
self.rb = Radiobutton(self.frameListBoxAll, text='Proteins',value=item,variable=self.var)
self.rb.grid(row=3, column=0)
#radioboutton list box 2
self.var2 = IntVar()
for item in [1,2]:
if item == 1:
self.rb2 = Radiobutton(self.frameListBoxAll, text='Nucleotides',value=item,variable=self.var2)
self.rb2.grid(row=2, column=1)
if item == 2:
self.rb2 = Radiobutton(self.frameListBoxAll, text='Proteins',value=item,variable=self.var2)
self.rb2.grid(row=3, column=1)
#variables
self.path1 = str()
self.path2 = str()
self.path3 = str()
#RUN Buttun
self.runbutton = Button(self.fen, text="RUN",command=self.start_foo_thread).grid(row=7,column=0,columnspan=2)
#FRAME CONSOLE
self.console = Frame(self.fen)
self.console.config(relief=SUNKEN, bg="black", height=200, width=400)
self.console.grid(row=8, columnspan=10)
self.console.grid_propagate(False) #to block the size of the frame
#QUIT BUTTON
self.quitButton = Button(self.fen)
self.quitButton.config(text="QUIT", command=self.fen.destroy)
self.quitButton.grid(row=100,column=0)
def folderPath(self):
path = askdirectory(title='Choose your set folder')
self.varLabel1.set(path)
self.listeBox1.delete(0, END)
for filename in sorted(glob.glob(path+'/*')):
if os.path.isfile(filename):
#stockage of path
self.path1 = os.path.split(filename)[0]
name = os.path.split(filename)[1]
self.listeBox1.insert(END, name)
def folderPath2(self):
path = askdirectory(title="Choose your library database folder")
self.varLabel2.set(path)
self.listeBox2.delete(0, END)
for filename in sorted(glob.glob(path+'/*')):
if os.path.isfile(filename):
#stockage of path
self.path2 = os.path.split(filename)[0]
name = os.path.split(filename)[1]
self.listeBox2.insert(END, name)
def run(self):
self.fen.mainloop()
def createJobName():
job = str(datetime.now())
job = job.replace(" ","-")
return job
def typeNP(self):
liste = []
#selection of query files
valListBox1 = [self.listeBox1.get(idx) for idx in self.listeBox1.curselection()]
#selection of database file
valListBox2 = [self.listeBox2.get(idx) for idx in self.listeBox2.curselection()]
#selection of sequence type
typ = (self.var.get(),self.var2.get())
# loop
for i in range(len(valListBox2)):
job = GraphicalUserInterface.createJobName()
path1 = self.path2
path2 = self.path1
DB = valListBox2[i]
path3 = os.getcwd()+"/"+DB+job
if os.path.isdir(DB+job) == True:
showwarning('Warning', "The folder already exist \n or they are no folder name !\nChange or get the folder name")
else:
os.mkdir(DB+job)
for filename in valListBox1:
seq = filename+job
seq2 = filename
#stock data for OneFile function
liste.append([path1,DB,path2,seq,seq2,typ,path3])
return liste
def start_foo_thread(self):
liste = self.typeNP()
for i in range(len(liste)):
global foo_thread
import threading
print('Fichier n°'+str(i+1)+' '+str(liste[i][4]))
stringLabel = Label(self.console,text='Fichier n°'+str(i+1)+' '+str(liste[i][4]),bg='black', fg='white')
stringLabel.grid(row=i,sticky="W")
foo_thread = threading.Thread(target=OneFile(liste[i][0],liste[i][1],liste[i][2],liste[i][3],liste[i][4],liste[i][5],liste[i][6]))
foo_thread.daemon = True
foo_thread.start()
#########
# AUTORUN #
#########
if __name__ == '__main__':
app = GraphicalUserInterface()
app.run()
问题是当循环开始时:
def start_foo_thread(self):
liste = self.typeNP()
for i in range(len(liste)):
使用print函数,我看到函数运行,但迭代完成后标签不会进入框架。循环完成后,我在框架中看到了我的标签。 在我的循环中我的函数运行的同时,在我的框架中使用我的标签的正确代码是什么?
答案 0 :(得分:0)
您有时必须手动更新小部件。你发布了太多的代码,所以这个简单的例子应该显示问题。按原样运行,标签不会显示,直到函数返回。使用update_idletasks()运行取消注释执行我认为你想要的。另请注意,程序会停止,直到调用子进程返回。
import sys
if sys.version_info[0] < 3:
import Tkinter as tk ## Python 2.x
else:
import tkinter as tk ## Python 3.x
class GraphicalUserInterface():
def __init__(self):
#constructor
self.fen = tk.Tk()
self.fen.title("Starch Enzyme Pipeline")
self.console=tk.Frame(self.fen)
self.console.grid()
self.liste=["one", "two", "three"]
tk.Button(self.fen, text="Exit", command=self.fen.quit).grid(row=1)
self.start_foo_thread()
self.fen.mainloop()
def start_foo_thread(self):
for ctr in range(len(self.liste)):
lit='Fichier n %s' % (ctr)
print(lit)
stringLabel = tk.Label(self.console, text=lit,
bg='black', fg='white')
stringLabel.grid(row=ctr,sticky="W")
##self.console.update_idletasks()
print("Waiting 2 seconds")
self.fen.after(2000) ## wait 2 seconds to show effect
print("Return from function")
if __name__ == '__main__':
app = GraphicalUserInterface()