python& Tkinter->关于调用冻结程序的长时间运行的函数 [英] Python & Tkinter -> About calling a long running function that freeze the program

查看:60
本文介绍了python& Tkinter->关于调用冻结程序的长时间运行的函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是GUI编程的一个新功能,我正在尝试为我的python解析器之一创建GUI.

Am a new in GUI programming and I am trying to make a GUI for one of my python parser.

我知道:

  • Tkinter是单线程的.屏幕更新会在事件循环中的每次行程中发生.每当您使用长时间运行的命令时,都在阻止事件循环完成迭代,从而阻止了事件的处理,从而阻止了重绘.

  • Tkinter is single threaded. Screen updates happen on each trip through the event loop. Any time you have a long running command you are preventing the event loop from completing an iteration, thus preventing the processing of events, thus preventing redraws.

我的程序调用了一个大函数,大约需要5分钟才能完全运行它.因此,我猜唯一的解决方案是针对长期运行的命令使用线程. 但是,我长期运行的命令已经在线程中,所以我真的不知道如何继续.

My program call a big function that takes about 5 minutes to be ran entirely. So I guess the only solution is tu use thread for the long running command. BUT, my long running command in already threaded so I don't really know how to proceed.

->在GUI中单击BUT1后,程序将冻结,直到功能完全完成.我想在背景中运行此功能 ,所以程序不会冻结.

--> As soon as I click on BUT1 in the GUI, the program freeze until the function is entirely done. I'd like to run this function in the backgroung, so the program will not freeze.

->我不是在寻找完整的解决方案,但是如果有人可以让我走上一个好的轨道,那就太好了!

--> I'm not looking for a complete solution but if someone can put me on a good track, it will be wonderful !

  • Main.py-> GUI
  • Module_1.py->我们通过单击按钮BUT1调用的函数

提前谢谢!

这是Main.py-> GUI

Here is Main.py --> the 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->包含大功能

And here is Module_1.py --> contain the big function

#!/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,我们运行带有参数BUT1的Module_1.py文件中包含的main("BUT1")函数,并启动-> run('Function1',SPIDER1(),'C:\ LOL \ Output1 '+ DATE +'.csv') 然后程序冻结,直到解析器完成工作.. ::

So by clicking on BUT1, we run the main("BUT1") function contained in the Module_1.py file with argument BUT1 that launch -> run('Function1',SPIDER1(),'C:\LOL\Output1'+DATE+'.csv') And then the program freeze until the parser has finished is work .. :)

推荐答案

问题很简单:BUT1在返回main的调用之前不会返回.只要main(因此,BUT1)没有返回,您的GUI就会被冻结.

The problem is simple: BUT1 won't return until the call to main returns. As long as main (and thus, BUT1) doesn't return, your GUI will be frozen.

为此,必须将main放在单独的线程中.如果main只是在等待其他线程而产生其他线程,那是不够的.

For this to work you must put main in a separate thread. It's not sufficient that main spawns other threads if all it's doing is waiting for those threads.

这篇关于python& Tkinter->关于调用冻结程序的长时间运行的函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆