这是GUI编程中的新功能,我正在尝试为我的python解析器之一创建GUI。
我知道 :
Tkinter是单线程的。屏幕更新在整个事件循环中每次旅行时发生。每当您使用长时间运行的命令时,都在阻止事件循环完成迭代,从而阻止了事件的处理,从而阻止了重绘。
我的程序调用了一个大函数,大约需要5分钟才能完全运行它。因此,我猜唯一的解决方案是针对长期运行的命令使用线程。但是,我长期运行的命令已经在线程中,所以我真的不知道如何继续。
->在GUI中单击BUT1后,程序将冻结,直到功能完全完成。我想 在backgroung中 运行此功能,因此程序不会冻结。
->我不是在寻找完整的解决方案,但是如果有人可以让我走上一个好的轨道,那就太好了!
先感谢您 !
这是Main.py-> GUI
#!/usr/bin/python # -*- coding: utf-8 -*- from Tkinter import * import sys import tkMessageBox import tkFileDialog import Module_1 import csv from time import strftime, gmtime DATE = strftime("_%d_%b_%Y") class App: def __init__(self, master): self.frame = Frame(master, borderwidth=5, relief=RIDGE) self.frame.grid() class IORedirector(object): def __init__(self,TEXT_INFO): self.TEXT_INFO = TEXT_INFO class StdoutRedirector(IORedirector): def write(self,str): self.TEXT_INFO.config(text=self.TEXT_INFO.cget('text') + str) self.TEXT_HEADER = self.text_intro = Label(self.frame, bg="lightblue",text="THIS IS \n MY SUPER PROGRAM") self.TEXT_HEADER.grid(row=0, column=0, columnspan=2, sticky=W+E+N+S) self.MENU = Frame(self.frame, borderwidth=5, relief=RIDGE, height=12) self.MENU.grid(row=1, column=0, sticky=N) self.button = Button(self.MENU, text="QUIT", bg="red", command=self.frame.quit) self.button.grid(row=4, column=0) self.BUT1 = Button(self.MENU, text="BUT1", command=self.BUT1) self.BUT1.grid(row=0, column=0,sticky=W+E) self.TEXT_INFO = Label(self.frame, height=12, width=40, text="SOME TEXT", bg="grey",borderwidth=5, relief=RIDGE) self.TEXT_INFO.grid(row=1, column=1, sticky = N+W) sys.stdout = StdoutRedirector(self.TEXT_INFO) def BUT1(self): self.BUT1.config(text="RUNNING") self.TEXT_INFO.config(text="BUT1 LAUNCHED") Module_1.main("BUT1") ## HERE WE NEED TO RUN THE FUNCTION ## THE PROGRAMM FREEZE HERE UNTIL THE FUNCTION IS ENTIRELY RUN self.TEXT_INFO.config(text="BUT1 FINISHED") self.BUT1.config(text="DONE") root = Tk() app = App(root) root.mainloop()
这是Module_1.py->包含big函数
#!/usr/bin/python # -*- coding: utf-8 -*- import Queue import threading import urllib2 import time from bs4 import BeautifulSoup as soup from urllib2 import urlopen import re import os import random import sys import logging import csv from time import strftime, gmtime import os import random import shutil import sys import re import logging from threading import RLock from time import strftime, gmtime import csv import urllib from urllib import urlretrieve from grab.spider import Spider, Task logging.basicConfig(level=logging.CRITICAL) # Loggin to DEBUG / INFO log = logging.getLogger() DATE = strftime("_%d_%b_%Y") class SPIDER1(Spider): initial_urls = ['URL_THAT_I_NEED_TO_PARSE'] def __init__(self): super(SPIDER1, self).__init__( thread_number=20, network_try_limit=20, task_try_limit=20 ) self.result = {} def task_initial(self, grab, task): for opt in grab.css_list("select[name='Template$TestCentreSearch1$SubRegionList'] option")[1:]: grab.set_input('Template$TestCentreSearch1$SubRegionList', opt.attrib['value']) grab.submit(extra_post={ '__EVENTTARGET': 'Template$TestCentreSearch1$SubRegionList' }, make_request=False) yield Task('parse', grab=grab, country=opt.text_content()) def task_parse(self, grab, task): log.info('downloaded %s' % task.country) city_gen = (x.text_content() for x in grab.css_list(".TestCentreSearchLabel+br+span")) title_gen = (x.text_content() for x in grab.css_list(".TestCentreSearchTitle")) id_gen = (x.attrib['href'][-36:] for x in grab.css_list(".TestCentreSearchLink")) for x in zip(city_gen, title_gen, id_gen): self.result[x[2]] = { 'country': task.country, 'city': x[0], 'name': x[1], 'id': x[2], 'price':'', 'currency':'', 'fee':'' } yield Task('info', 'URL_URL=%s' % x[2], id=x[2]) def task_info(self, grab, task): for label in grab.css_list(".TestCentreViewLabel"): if label.text_content().strip()=="Test Fee:": fees = label.getnext().text_content().strip() self.result[task.id]['fee'] = fees price = re.findall('\d[\d\., ]+\d',fees) if price: price = re.findall('\d[\d\., ]+\d',fees)[0] self.result[task.id]['price'] = price.replace(' ','').replace(',','.') currency = re.findall('[A-Z]{2,3}[$|€|£]?',fees) if not currency: currency = re.findall('[$|€|£]',fees) if not currency: currency = fees.replace(price,'').strip().replace(' ','') if isinstance(currency,list): currency = currency[0] self.result[task.id]['currency'] = currency #log.info(' %(price)s %(currency)s - %(fee)s ' % self.result[task.id]) break def dump(self, path): """ Save result as csv into the path """ with open(path, 'w') as file: file.write("ID;Country;State;City;Name;Price;Currency;Original Fee\n") for test_center in sorted(self.result.values(), key=lambda x: "%(country)s%(city)s%(name)s" % x): file.write(("%(id)s;%(country)s;;%(country)s;%(name)s;%(price)s;%(currency)s;%(fee)s\n" % test_center).encode('utf8')) def main(choice): parser, path, name = None, None, None def run(name,parser,path): log.info('Parsing %s...' % name) parser.run() parser.dump(path) log.info('Parsing %s completed, data was dumped into %s' % (name, path)) log.info(parser.render_stats()) if choice == "NONE": # DO NOTHING # HERE I'D LIKE TO HAVE ANOTHER CALL TO ANOTHER THREADED FUNCTION elif choice == "BUT1": run('Function1',SPIDER1(),'C:\LOL\Output1'+DATE+'.csv')
因此,通过单击BUT1,我们运行Module_1.py文件中包含的main(“ BUT1”)函数,并带有参数BUT1,然后启动-> run(’Function1’,SPIDER1(),’C:\ LOL \ Output1’+ DATE + ‘.csv’),然后程序冻结,直到解析器完成工作为止.. :)
问题很简单:BUT1在调用return之前不会main返回。只要main(因此BUT1)不返回,您的GUI就会被冻结。
BUT1
main
为此,您必须放入main一个单独的线程。main如果所有其他线程正在等待这些线程,则生成其他线程是不够的。