2016-08-21 1 views
6

ich eine Probe pyside Demo, die ich geschaffen, um die Webkit-Browser Kommunikation mit Python zu sehen ... Ich habe zwei Tasten in webkitpyside Anwendung mit asynchronen Funktionsausführung

  • Taste 1 - wenn sie angeklickt es schläft für 10 Sekunden und druckt dann eine Nachricht

  • button2 - wenn angeklickt wird, druckt es sofort eine Nachricht.

Wenn ich auf die Taste 1 geklickt haben, apps die ganze gefriert und wartet auf Python schlafen zu beenden, dies bedeutet, dass ich nicht auf die Schaltfläche klicken 2 kann einige andere Sachen zu tun. Wie kann ich eine asynchrone Methode zwischen Funktionsaufrufen implementieren?

Meine Python-Codes sind unter

import sys,json 
from time import sleep 
from PySide.QtCore import * 
from PySide.QtGui import * 
from PySide.QtWebKit import QWebView, QWebSettings 
from PySide.QtNetwork import QNetworkRequest 
from PySide.QtCore import QObject, Slot, Signal 

    html_str="""<!doctype> 
     <html> 

     <body>hello world 
     <button id="button" >button1</button> 
     <button id="button2" >button2</button> 
     </body> 
    </html> 
    <script type="text/javascript"> 
    document.getElementById("button").onclick=function(){ 
    object.reply(" hello "); 
    } 
    document.getElementById("button2").onclick=function(){ 
    object.reply2(" hello "); 
    } 
    function data_from_js(msg){ 
     var tag=document.createElement('div'); 
     tag.innerHTML="message from python"; 
     document.body.appendChild(tag); 
     alert(msg['name']); 
    } 
    </script> 
    <style> 
    body{ 
    border:solid black 1px; 
    } 
    </style> 
    </doctype>""" 
class Qbutton(QObject): 
    from time import sleep 
    def __init__(self): 
     super(Qbutton,self).__init__() 
    @Slot(str) 
    def reply(self,recd): 
     #r=QMessageBox.information(self,"Info",msg) 
     msgBox = QMessageBox() 
     sleep(10) 
     msgBox.setText("python just said"+recd) 
     msgBox.exec_() 
     return "I am recieving pythonic data" 
     #r=QMessageBox.question(self,title,recd,QMessageBox.Yes | QMessageBox.No) 
    @Slot(str) 
    def reply2(self,recd): 
     msgBox = QMessageBox() 
     msgBox.setText("python just said"+recd+ " another time") 
     msgBox.exec_() 
     return "I am recieving pythonic data"   
    @Slot(str) 
    def send_tojs(self): 
     pass 


class adstar_gui(QWidget): 
    def __init__(self):   
     super(adstar_gui,self).__init__() 
     self.setWindowTitle("Adstar Wordlist Generator") 
     self.setMaximumWidth(5000) 
     self.setMaximumHeight(5000) 
     self.setMinimumWidth(500) 
     self.setMinimumHeight(500) 
     self.show() 
     print "Sample window" 

    def closeEvent(self,event): 
     self.closeEvent() 
if __name__=="__main__": 
    Qapp=QApplication(sys.argv) 
    t=QWebView() 
    t.setHtml(html_str) 
    button=Qbutton() 
    t.page().mainFrame().addToJavaScriptWindowObject("object",button) 
    t.show() 
    #t.page().mainFrame().evaluateJavaScript("data_from_js(%s);" % (json.dumps({'name':"My name is Junior"}))) 
    QCoreApplication.processEvents() 
    #sys.exit(Qapp.exec_()) 
    Qapp.exec_() 

FRAGE

Wie kann ich auf button 1 in webkit klicken und lassen etwas im Hintergrund Python tun, wenn die Taste 1 gedrückt wird? (So ​​dass button 2 Funktion muss nicht für die Taste 1 Funktion warten, bis zum Ende)

Bitte diese Demo verwenden und verbessert es ... sehr geschätzt

Antwort

2

Es gibt ein paar Probleme hier. Zuerst sollten Sie darauf hinweisen, warum die App beim Klicken auf button1 einfriert: Der Klick bewirkt, dass Qt den Ereignishandler reply aufruft, und Qt kann erst dann ein anderes Ereignis verarbeiten, wenn dieser Handler zurückkehrt (meiner Erfahrung nach funktionieren alle Fenstersysteme) Weg). Wenn Sie also eine lange laufende Routine in einen Event-Handler einfügen, wird Ihre Anwendung eingefroren, bis die Routine beendet ist. Jedes Mal, wenn ein Event-Handler länger als etwa 0,05 Sekunden benötigt, wird der Benutzer bemerken.

Wie titusjan in seiner Antwort zeigt, ist es ziemlich einfach, Qt dazu zu bringen, nach einem Zeitintervall eine Funktion auszuführen. Aber ich denke, deine Frage ist nicht, wie man mit einer einfachen Zeitverzögerung umgehen soll, sondern wie man mit einem lang andauernden Prozess umgeht. In meinem Beispielcode habe ich Ihre Verzögerung von zehn Sekunden durch eine Schleife ersetzt, die zehn Verzögerungen von einer Sekunde umfasst, was meiner Meinung nach ein besseres Modell für das ist, was Sie erreichen möchten.

Die Lösung ist, den langen Prozess in einem anderen Thread zu tun. Sie haben zwei Optionen: QThreads, die Teil der Qt-Umgebung sind, und Python-Threads. Beide funktionieren, aber ich verwende immer Python-Threads, wo immer es möglich ist. Sie sind besser dokumentiert und ein bisschen leichter. Die Möglichkeit, Threads als Daemons zu bezeichnen, macht das Herunterfahren von Anwendungen manchmal etwas einfacher. Außerdem ist es einfacher, ein Multithread-Programm in ein Programm zu konvertieren, das Multiprozesse verwendet. Ich habe einen Python-Thread im folgenden Beispielcode verwendet.

Das Problem tritt dann auf, wie weiß die Anwendung, wenn der sekundäre Thread beendet ist? Zu diesem Zweck müssen Sie ein benutzerdefiniertes Qt-Signal erstellen. Dein sekundärer Thread gibt dieses Signal aus, wenn es fertig ist, und die Haupt-App verbindet einen Slot, um etwas zu tun, wenn das passiert. Wenn Sie ein benutzerdefiniertes Qt-Signal erstellen möchten, müssen Sie es wie in diesem Beispiel in einer Unterklasse von QObject deklarieren.

Unnötig zu sagen, dass alle Standard-Multithreading-Probleme behandelt werden müssen.

import sys 
import json 
import threading 
from time import sleep 
from PySide.QtCore import * 
from PySide.QtGui import * 
from PySide.QtWebKit import QWebView, QWebSettings 
from PySide.QtNetwork import QNetworkRequest 
from PySide.QtCore import QObject, Slot, Signal 

html_str="""<!doctype> 
     <html> 

     <body>hello world 
     <button id="button" >button1</button> 
     <button id="button2" >button2</button> 
     </body> 
    </html> 
    <script type="text/javascript"> 
    document.getElementById("button").onclick=function(){ 
    object.reply(" hello "); 
    } 
    document.getElementById("button2").onclick=function(){ 
    object.reply2(" hello "); 
    } 
    function data_from_js(msg){ 
     var tag=document.createElement('div'); 
     tag.innerHTML="message from python"; 
     document.body.appendChild(tag); 
     alert(msg['name']); 
    } 
    </script> 
    <style> 
    body{ 
    border:solid black 1px; 
    } 
    </style> 
    </doctype>""" 

class Qbutton(QObject): 
    def __init__(self): 
     super(Qbutton,self).__init__() 
     self.long_thread = LongPythonThread() 
     self.long_thread.thread_finished.connect(self.reply2_finished) 

    @Slot(str) 
    def reply(self,recd): 
     print("reply") 
     t = threading.Thread(target=self.long_thread.long_thread, args=(recd,)) 
     t.daemon = True 
     t.start() 

    @Slot(str) 
    def reply2(self,recd): 
     print("reply2") 
     msgBox = QMessageBox() 
     msgBox.setText("python just said"+recd) 
     msgBox.exec_() 
     return "I am receiving pythonic data" 

    @Slot(str) 
    def reply2_finished(self, recd): 
     print("reply2 finished") 
     msgBox = QMessageBox() 
     msgBox.setText("python just said"+recd+ " another time") 
     msgBox.exec_() 

    @Slot(str) 
    def send_tojs(self): 
     pass 

class LongPythonThread(QObject):  
    thread_finished = Signal(str) 

    def __init__(self): 
     super(LongPythonThread,self).__init__() 

    def long_thread(self, recd): 
     for n in range(10): 
      sleep(1.0) 
      print("Delayed for {:d}s".format(n+1)) 
     self.thread_finished.emit(recd) 

if __name__=="__main__": 
    Qapp=QApplication(sys.argv) 
    t=QWebView() 
    t.setHtml(html_str) 
    button=Qbutton() 
    t.page().mainFrame().addToJavaScriptWindowObject("object",button) 
    t.show() 
    #t.page().mainFrame().evaluateJavaScript("data_from_js(%s);" % (json.dumps({'name':"My name is Junior"}))) 
    QCoreApplication.processEvents() 
    #sys.exit(Qapp.exec_()) 
    Qapp.exec_() 
+0

Ich hatte mit QThreads experimentiert, nachdem ich meine Frage gepostet hatte und es funktionierte..Ich wartete darauf, dass jemand eine solche Antwort posten konnte..Exzellente Arbeit! – repzero

+0

Nur ein kleines Problem..Sie haben keine Parameter an super in der Klasse LongPythonThread übergeben, die eine Ausnahme auslösen..aber ich habe es in meinem Beispiel..thanks – repzero

+0

hinzugefügt Das ist ein Unterschied zwischen der super() -Funktion in Py2 und Py3. Der Code, den ich geschrieben habe, funktioniert mit Python3, aber Ihre Modifikation lässt es mit beiden funktionieren. –

1

Verwenden Sie ein QTimer ein Signal nach einer bestimmten Zeitperiode auszuführen . Gefällt mir:

import sys,json 
from PySide.QtCore import * 
from PySide.QtGui import * 
from PySide.QtWebKit import QWebView, QWebSettings 
from PySide.QtNetwork import QNetworkRequest 
from PySide.QtCore import QObject, Slot, Signal, QTimer 

html_str="""<!doctype> 
     <html> 

     <body>hello world 
     <button id="button" >button1</button> 
     <button id="button2" >button2</button> 
     </body> 
    </html> 
    <script type="text/javascript"> 
    document.getElementById("button").onclick=function(){ 
    object.replyAfter10Seconds(" hello "); 
    } 
    document.getElementById("button2").onclick=function(){ 
    object.reply2(" hello "); 
    } 
    function data_from_js(msg){ 
     var tag=document.createElement('div'); 
     tag.innerHTML="message from python"; 
     document.body.appendChild(tag); 
     alert(msg['name']); 
    } 
    </script> 
    <style> 
    body{ 
    border:solid black 1px; 
    } 
    </style> 
    </doctype>""" 


class Qbutton(QObject): 
    def __init__(self): 
     super(Qbutton,self).__init__() 
     self.timer = QTimer() 
     self.timer.setSingleShot(True) 
     self.timer.setInterval(10 * 1000) 
     self.timer.timeout.connect(self.reply) 
    @Slot(str) 
    def replyAfter10Seconds(self,recd): 
     self._replyText = recd 
     print "Started timer" 
     self.timer.start() 
    @Slot() 
    def reply(self): 
     #r=QMessageBox.information(self,"Info",msg) 
     msgBox = QMessageBox() 
     msgBox.setText("python just said"+self._replyText) 
     msgBox.exec_() 
     return "I am recieving pythonic data" 
     #r=QMessageBox.question(self,title,recd,QMessageBox.Yes | QMessageBox.No) 
    @Slot(str) 
    def reply2(self,recd): 
     msgBox = QMessageBox() 
     msgBox.setText("python just said"+recd+ " another time") 
     msgBox.exec_() 
     return "I am recieving pythonic data"   
    @Slot(str) 
    def send_tojs(self): 
     pass 


class adstar_gui(QWidget): 
    def __init__(self):   
     super(adstar_gui,self).__init__() 
     self.setWindowTitle("Adstar Wordlist Generator") 
     self.setMaximumWidth(5000) 
     self.setMaximumHeight(5000) 
     self.setMinimumWidth(500) 
     self.setMinimumHeight(500) 
     self.show() 
     print "Sample window" 

    def closeEvent(self,event): 
     self.closeEvent() 
if __name__=="__main__": 
    Qapp=QApplication(sys.argv) 
    t=QWebView() 
    t.setHtml(html_str) 
    button=Qbutton() 
    t.page().mainFrame().addToJavaScriptWindowObject("object",button) 
    t.show() 
    t.raise_() 
    #t.page().mainFrame().evaluateJavaScript("data_from_js(%s);" % (json.dumps({'name':"My name is Junior"}))) 
    QCoreApplication.processEvents() # does nothing as long as App.exec_() hasn't statred. 
    #sys.exit(Qapp.exec_()) 
    Qapp.exec_()