2016-08-21 3 views
6

У меня есть образец PySide демо, который я создал, чтобы увидеть связь WebKit браузера с питоном ... У меня есть две кнопки в WebKitPySide Применение при выполнении асинхронной функции

  • кнопка 1 - при нажатии она спит в течение 10 секунд, а затем печатает сообщение

  • button2 - при нажатии на него печатается сообщение немедленно.

Когда я нажал на кнопку 1, все приложения замирает и ждет питона, чтобы закончить сон, это означает, что я не могу нажать на кнопку 2, чтобы сделать некоторые другие вещи. Как реализовать асинхронный метод между вызовами функций?

Мои питона коды ниже

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_() 

ВОПРОС

Как я могу нажать на button 1 в WebKit, и пусть питона сделать что-то в фоновом режиме, когда кнопка 1 нажата? (Так что button 2 функции не нужно ждать, пока кнопку 1 функцию, чтобы закончить)

Пожалуйста, используйте эту демку и улучшить его ... высоко ценится

ответ

2

Здесь есть несколько проблем. Во-первых, стоит отметить, почему приложение зависает, когда вы нажимаете кнопку button1: щелчок вызывает Qt для вызова обработчика события, reply, а Qt не может обрабатывать другое событие до тех пор, пока этот обработчик не вернется (по моему опыту, все системы окон работают путь). Поэтому, если вы помещаете какую-либо длительную процедуру внутри обработчика событий, ваше приложение замерзает до завершения процедуры. Каждый раз, когда обработчик событий занимает больше, чем примерно 0,05 секунды, пользователь замечает.

Как указывает titusjan в своем ответе, довольно легко получить Qt для выполнения функции через временной интервал. Но я думаю, что ваш вопрос заключается не в том, как справляться с простой временной задержкой, а в том, как справляться с длительным процессом. В моем примере кода я заменил вашу десяти вторую задержку на цикл, который насчитывает десять односекундных задержек, которые, я думаю, являются лучшей моделью того, чего вы пытаетесь достичь.

Решение состоит в том, чтобы выполнить длинный процесс в другом потоке. У вас есть два варианта: QThreads, которые являются частью среды Qt и потоки Python. Оба они работают, но я всегда использую потоки Python, где это возможно. Они лучше документированы и немного более легки. Возможность назначать потоки в качестве демонов иногда делает остановку приложений немного проще. Кроме того, проще преобразовать многопоточную программу в ту, которая использует многопроцессы. Я использовал поток Python в приведенном ниже примере кода.

Возникает проблема, как приложение знает, когда завершен вторичный поток? Для этого вы должны создать настраиваемый Qt-сигнал. Ваш вторичный поток выдает этот сигнал, когда он работает, и основное приложение соединяет слот, чтобы что-то делать, когда это происходит. Если вы собираетесь создать собственный Qt-сигнал, вы должны объявить его в подклассе QObject, как это было в примере.

Излишне говорить, что все стандартные проблемы многопоточности должны быть решены.

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

Я экспериментировал с QThreads после публикации моего вопроса, и это сработало. Я ждал, что кто-то опубликует такой ответ. Отличная работа! – repzero

+0

Немного о проблеме. Вы не передали параметры супер в классе LongPythonThread, который будет генерировать исключение .. но я добавил его в свой образец. Спасибо – repzero

+0

. Это разница между функцией super() в Py2 и Py3. Код, который я написал, работает с Python3, но ваша модификация позволяет ему работать с обоими. –

1

Используйте QTimer выполнить сигнал по истечению определенного периода времени , Например:

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_() 
Смежные вопросы