2012-06-02 6 views
5

जीयूआई प्रोग्रामिंग में नया है और मैं अपने पायथन पार्सर में से एक के लिए एक जीयूआई बनाने की कोशिश कर रहा हूं।पायथन और टिंकर -> प्रोग्राम को फ्रीज करने वाले लंबे समय तक चलने वाले फ़ंक्शन को कॉल करने के बारे में

मुझे पता है कि:

  • Tkinter एकल लड़ी है। इवेंट लूप के माध्यम से प्रत्येक यात्रा पर स्क्रीन अपडेट होते हैं। जब भी आपके पास लंबे समय तक चलने वाला कमांड होता है तो आप इवेंट लूप को पुनरावृत्ति को पूरा करने से रोक रहे हैं, इस प्रकार घटनाओं की प्रसंस्करण को रोकते हैं, इस प्रकार रेड्रो को रोकते हैं।

  • मेरा प्रोग्राम एक बड़ा फ़ंक्शन कॉल करता है जिसमें पूरी तरह से चलने में लगभग 5 मिनट लगते हैं। तो मुझे लगता है कि एकमात्र समाधान लंबे समय तक चलने वाले कमांड के लिए थू का उपयोग करता है। लेकिन, मेरे लंबे समय से चलने वाले कमांड को पहले ही थ्रेड किया गया है, इसलिए मुझे वास्तव में नहीं पता कि आगे कैसे बढ़ना है।

-> जैसे ही मैं जीयूआई में BUT1 पर क्लिक करेंगे, तो समारोह जब तक कार्यक्रम फ्रीज पूरी तरह से किया जाता है। मैं बैकगॉन्ग में यह फ़ंक्शन चलाने के लिए चाहता हूं, इसलिए प्रोग्राम स्थिर नहीं होगा।

-> मैं एक पूर्ण समाधान की तलाश नहीं कर रहा हूं लेकिन अगर कोई मुझे एक अच्छे ट्रैक पर रख सकता है, तो यह अद्भुत होगा!

  • Main.py -> जीयूआई
  • Module_1.py -> समारोह है कि हम बटन BUT1

अग्रिम धन्यवाद पर क्लिक करके कहते हैं! > जीयूआई

#!/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 है - -

यहाँ Main.py है> BUT1 पर क्लिक करके बड़ा समारोह शामिल

#!/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 फ़ाइल में निहित है जो लॉन्च -> रन ('फ़ंक्शन 1', SPIDER1(), 'C: \ LOL \ आउटपुट 1' + DATE + 'csv') और फिर जब तक पार्सर समाप्त नहीं हो जाता तब तक प्रोग्राम फ्रीज हो जाता है .. :)

उत्तर

3

समस्या सरल है: BUT1main रिटर्न के लिए कॉल तक लौटाई नहीं जाएगी। जब तक main (और इस प्रकार, BUT1) वापस नहीं आता है, तो आपका जीयूआई जमेगा।

इस काम के लिए आपको main को एक अलग थ्रेड में रखना होगा। यह पर्याप्त नहीं है कि main अन्य थ्रेड स्पॉन्स करता है यदि यह सब कुछ कर रहा है तो उन धागे की प्रतीक्षा कर रहा है।

+0

मैंने कोशिश की है लेकिन सफलता के बिना, मैं थ्रेडिंग चीजों में काफी नया हूं, अगर आपके पास सिर्फ एक संक्षिप्त उदाहरण है, तो यह बहुत उपयोगी होना चाहिए;) –

+0

कोई विचार? मैंने कोशिश की है लेकिन बिना किसी सफलता के ... मदद बहुत उपयोगी होगी;) –

2

यदि आप कभी-कभी BUT1 फ़ंक्शन से root.update() पर कॉल करते हैं, तो उसे जीयूआई को ठंड से रोकना चाहिए। आप एक निश्चित अंतराल के साथ एक अजगर धागे से भी ऐसा कर सकते हैं।

उदाहरण के लिए

, हर 0.1 सेकंड अद्यतन करने:

from threading import Thread 
from time import sleep 

self.updateGUIThread = Thread(target=self.updateGUI) 

def updateGUI(self): 
    while self.updateNeeded 
     root.update() 
     sleep(0.1) 

बड़ा समारोह पूरा करता है के बाद आप गलत पर self.updateNeeded सेट कर सकते हैं।

+0

बहुत रोचक! मैं bUT1 फ़ंक्शन से root.update() को कॉल करने का प्रयास कर रहा हूं और यह थ्रेड को बंद करने के लिए वापस आ गया है अगर यह काम करता है! बहुत बहुत धन्यवाद, यह बहुत ही आशाजनक लगता है! –

+1

@ नोकीमाशी: यह * बहुत * खतरनाक है। क्या आपने वास्तव में यह कोशिश की है? अगर यह काम करता है तो मैं आश्चर्यचकित हूं और अंततः किसी बिंदु पर डेडलॉक या दुर्घटना का कारण नहीं बनता। 'अपडेट'' को कॉल करना आम तौर पर एक बुरा अभ्यास है, और ऐसा लगता है कि किसी अन्य धागे से ऐसा करना खतरनाक लगता है। अनिवार्य रूप से आप एक दूसरा ईवेंट लूप बना रहे हैं जब आप 'अपडेट' कहते हैं, और यदि कोई ईवेंट उस दौरान होता है जो इस कोड को फिर से कॉल करने का कारण बनता है, तो आप वास्तविक समस्याओं में आ सकते हैं। –

+0

@ ब्रायन ओकले: मैंने इसे किसी भी समस्या के बिना इस्तेमाल किया है, क्या आप समझा सकते हैं कि किस तरह की 'वास्तविक समस्याएं' का मतलब है? खिड़की को उत्तरदायी नहीं होने से रोकने के लिए पर्याप्त नहीं होगा? इसके अलावा, क्या आपके पास कोई विकल्प है? – Junuxx

संबंधित मुद्दे