【问题标题】:threading tkinter add label in frame during function execution线程 tkinter 在函数执行期间在框架中添加标签
【发布时间】:2015-05-15 15:08:27
【问题描述】:

我为实验室写了一个管道,所以我知道在 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)):

使用打印功能,我看到该功能运行,但迭代完成时标签没有进入框架。循环完成后,我会在框架中看到我的标签。 在我的函数在我的循环中运行的同时,将我的标签放在我的框架中的正确代码是什么?

【问题讨论】:

  • 阅读量很大。请创建一个MCVE
  • 您不能从创建它们的线程以外的任何线程访问 tkinter 小部件。通过在此站点上搜索 [tkinter] threading 进行更多研究。这是一个复杂的主题,可能会使您的问题过于宽泛。
  • 非常感谢您的建议,问候 yoan

标签: python multithreading tkinter


【解决方案1】:

您有时必须手动更新小部件。您已经发布了太多代码,因此这个简单的示例应该可以显示问题。按原样运行,标签在函数返回之前不会显示。使用未注释的 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()

【讨论】:

  • 您好!非常感谢您的帮助!在那里我错过了代码行:@ 987654322@ 在我得到我想要的东西之后:) 这是我的第一篇真正的帖子我正在学习生物信息学,我是法国人 感谢那些更正信息的人 感谢那些阅读的人并回复了非常感谢Yoan
猜你喜欢
  • 2012-06-06
  • 1970-01-01
  • 1970-01-01
  • 2016-08-11
  • 2018-05-08
  • 1970-01-01
  • 1970-01-01
  • 2021-11-13
  • 1970-01-01
相关资源
最近更新 更多