2012-09-06 58 views
1

我有一個PyQt4類,它顯示一個html表單並獲取輸入,這要歸功於前面的questions here(一個older one is here)。PyQt4:重新啓動主循環?

現在我想退出主循環,做一些其他的事情,稍後用不同的html表單重新啓動主循環。問題是,我的事件句柄在主循環的第二次執行中不起作用。我究竟做錯了什麼?

問題似乎是由於未提交表單而第二次調用app.exec_()時無法正常工作。

這裏是我的代碼運行,但不提交第二種形式:

import sys 
from urllib import unquote_plus 

from PyQt4 import QtCore, QtGui, QtWebKit 

class MyWebPage(QtWebKit.QWebPage): 
    formSubmitted = QtCore.pyqtSignal(QtCore.QUrl) 

    def acceptNavigationRequest(self, frame, req, nav_type): 
     if nav_type == QtWebKit.QWebPage.NavigationTypeFormSubmitted: 
      self.formSubmitted.emit(req.url()) 
     return super(MyWebPage, self).acceptNavigationRequest(frame, req, nav_type) 



class PsyTML(QtGui.QWidget): 
    def __init__(self): 
     super(PsyTML, self).__init__() 
     self.elements = {} 
     self.view = QtWebKit.QWebView(self) 
     layout = QtGui.QVBoxLayout(self) 
     layout.addWidget(self.view) 
     layout.setContentsMargins(0, 0, 0, 0) 
     self.view.setPage(MyWebPage()) 
     self.view.page().formSubmitted.connect(self.handleFormSubmitted) 

    def viewPsyTML(self, html): 
     self.view.setHtml(html) 
     self.show() 

    def handleFormSubmitted(self, url): 
     elements = self.elements 
     self.close() 
     for key, value in url.encodedQueryItems(): 
      key = unquote_plus(bytes(key)).decode('utf8') 
      value = unquote_plus(bytes(value)).decode('utf8') 
      elements[key] = value 
     # do stuff with elements... 
     for item in elements.iteritems(): 
      print '"%s" = "%s"' % item 
     QtGui.qApp.quit() 


# setup the html form 
html = """ 
<form action="" method="get"> 
Like it? 
<input type="radio" name="like" value="yes"/> Yes 
<input type="radio" name="like" value="no" /> No 
<br/><input type="text" name="text" value="" /> 
<input type="submit" name="submit" value="Send"/> 
</form> 
""" 

html2 = """ 
<form action="" method="get"> 
Choose wisely? 
<input type="radio" name="choose" value="A"/> Yes 
<input type="radio" name="choose" value="B" /> No 
<br/><input type="text" name="text" value="" /> 
<input type="submit" name="submit" value="Send"/> 
</form> 
""" 

def main(): 
    app = QtGui.QApplication(sys.argv) 
    intro = PsyTML() 
    intro.viewPsyTML(html) 
    # now, the html form is displayed nicely and the form elemtns returned 
    app.exec_() 
    # do something else here 

    # in the secomd run, the form is not submitted. 
    intro.viewPsyTML(html2) 
    app.exec_() 



if __name__ == "__main__": 
    main() 

我workinh與Python 2

回答

1

需要改變你的程序的現有結構。

首先,main函數應儘可能簡單。它應該只是創建一個應用程序對象和一個主窗口,然後運行事件循環。之後,每件事都應該圍繞着信號/事件和他們的處理程序。

目前,只有一箇中心事件:表單提交。發生異步,所以應用程序必須保存其當前狀態,然後等待被動完成每個表單,然後才能轉到下一個任務。

編輯

現在你的規範是清晰的,一個方式來實現你想要的是使用QDialog,它有自己的事件循環。

這是你的腳本的修訂版本,是希望能更接近你想要什麼:

import sys 
from urllib import unquote_plus 

from PyQt4 import QtCore, QtGui, QtWebKit 

class MyWebPage(QtWebKit.QWebPage): 
    formSubmitted = QtCore.pyqtSignal(object) 

    def acceptNavigationRequest(self, frame, req, nav_type): 
     if nav_type == QtWebKit.QWebPage.NavigationTypeFormSubmitted: 
      elements = {} 
      for key, value in req.url().encodedQueryItems(): 
       key = unquote_plus(bytes(key)).decode('utf8') 
       value = unquote_plus(bytes(value)).decode('utf8') 
       elements[key] = value 
      self.formSubmitted.emit(elements) 
     return super(MyWebPage, self).acceptNavigationRequest(frame, req, nav_type) 

class PsyTML(QtGui.QDialog): 
    def __init__(self): 
     super(PsyTML, self).__init__() 
     self.elements = {} 
     self.view = QtWebKit.QWebView(self) 
     layout = QtGui.QVBoxLayout(self) 
     layout.addWidget(self.view) 
     layout.setContentsMargins(0, 0, 0, 0) 
     self.view.setPage(MyWebPage()) 
     self.view.page().formSubmitted.connect(self.handleFormSubmitted) 

    def viewPsyTML(self, html): 
     self.view.setHtml(html) 
     self.exec_() 

    def handleFormSubmitted(self, elements): 
     self.elements = elements 
     self.accept() 

# setup the html form 
html = """ 
<form action="" method="get"> 
Like it? 
<input type="radio" name="like" value="yes"/> Yes 
<input type="radio" name="like" value="no" /> No 
<br/><input type="text" name="text" value="" /> 
<input type="submit" name="submit" value="Send"/> 
</form> 
""" 

html2 = """ 
<form action="" method="get"> 
Choose wisely? 
<input type="radio" name="choose" value="A"/> Yes 
<input type="radio" name="choose" value="B" /> No 
<br/><input type="text" name="text" value="" /> 
<input type="submit" name="submit" value="Send"/> 
</form> 
""" 

def main(): 
    app = QtGui.QApplication(sys.argv) 

    intro = PsyTML() 
    intro.viewPsyTML(html) 

    # do stuff with elements... 
    for item in intro.elements.iteritems(): 
     print '"%s" = "%s"' % item 

    intro = PsyTML() 
    intro.viewPsyTML(html2) 

if __name__ == "__main__": 
    main() 
+0

非常感謝您的回答(再次)。不幸的是,我真的**必須**退出主循環('app.exec _()')並返回到'main()',然後再次返回'app.exec _()'。你認爲這是不可能的嗎?或者我必須創建兩個應用程序(這似乎也很困難)?問題是,在我真正的任務中,PyQt4顯示只是一個程序部分,在整個更大的程序中的不同時間激發其他圖形窗口(例如'pyglet')。 – Henrik

+0

@Henrik你會更好地將整個程序製作成一個單獨的Qt應用程序,它可以在需要時擁有窗口,或者爲每個顯示的表單啓動並與單獨的可執行文件進行通信。 – ephemient

+0

@ephemient問題是,我打算提供的功能只是現有Python庫[PsychoPy](http://psychopy.org/)的插件。在編寫PsychoPy實驗的某個時候,可能需要使用上面的類來顯示一個html頁面。但主要部分是PsychoPy。因此,我絕對有必要逃避主循環。 – Henrik