2010-05-16 57 views
2

我需要能夠對QWebPage中的焦點變化做出反應。我用microFocusChanged()信號,它給了我幾乎所需的行爲,但無論如何,我不知道如何知道哪個元素被選中。我想在頁面上的任何可編輯元素獲取或失去焦點時執行一些操作。如何在QWebView/QWebPage中獲取焦點元素?

預先感謝您

回答

7

要你做下面的一個頁面內處理任何HTML事件:

  1. 有回調位建立的QObject接收的事件。它可能是一些專用的處理程序對象或像QDialog/QMainWindow這樣的現有對象。
  2. 使用QWebFrame.addToJavaScriptWindowObject(name,object)註冊表示用於JavaScript訪問的QObject。
  3. 編寫JavaScript以添加調用您註冊的QObject回調槽的HTML事件處理程序。

JavaScript添加焦點更改處理程序應該遍歷所有文本元素並添加onfocus和onblur處理程序。更好的做法是將單個處理程序添加到documentElement並使用事件冒泡。不幸的是,onblur廣告不會泡泡。幸運的是,它們有一個叫做DOMFocusIn和DOMFocusOut的冒泡對應物。

下面是一個完整的檢查頁面文本元素捕捉焦點輸入/輸出事件的示例。它在要從JavaScript調用的主窗口上聲明瞭兩個插槽handleFocusInhandleFocusOut,並將主窗口註冊爲名爲MainWindow的全局JavaScript變量。然後運行JavaScript以將DOMFocusIn/DOMFocusOut事件綁定到這些插槽(間接地,因爲我們需要過濾掉非文本元素)。

import sip 
sip.setapi("QString", 2) 
sip.setapi("QVariant", 2) 
from PyQt4 import QtCore, QtGui, QtWebKit 

class MyDialog(QtGui.QMainWindow): 

    def __init__(self): 
     super(MyDialog, self).__init__() 
     self.setWindowTitle("QWebView JavaScript Events") 

     web_view = QtWebKit.QWebView(self) 
     web_view.setHtml(""" 
      <html> 
       <body> 
        <input type="text" name="text1"/><br/> 
        <input type="text" name="text2"/><br/> 
        <input type="submit" value="OK"/> 
       </body> 
      </html>""") 
     self.setCentralWidget(web_view) 

     main_frame = web_view.page().mainFrame() 
     main_frame.addToJavaScriptWindowObject("MainWindow", self) 

     doc_element = main_frame.documentElement() 
     doc_element.evaluateJavaScript(""" 
      function isTextElement(el) { 
       return el.tagName == "INPUT" && el.type == "text"; 
      } 
      this.addEventListener("DOMFocusIn", function(e) { 
       if (isTextElement(e.target)) { 
        MainWindow.handleFocusIn(e.target.name); 
       } 
      }, false); 
      this.addEventListener("DOMFocusOut", function(e) { 
       if (isTextElement(e.target)) { 
        MainWindow.handleFocusOut(e.target.name); 
       } 
      }, false) 
     """) 

     self.resize(300, 150) 

    @QtCore.pyqtSlot(QtCore.QVariant) 
    def handleFocusIn(self, element_name): 
     QtGui.QMessageBox.information(
      self, "HTML Event", "Focus In: " + element_name) 

    @QtCore.pyqtSlot(QtCore.QVariant) 
    def handleFocusOut(self, element_name): 
     QtGui.QMessageBox.information(
      self, "HTML Event", "Focus Out: " + element_name) 


app = QtGui.QApplication([]) 
dialog = MyDialog() 
dialog.show() 
app.exec_() 

(如果你真的找不出Python,我可能會用C++重寫)。

+0

感謝名單了很多,我認爲應該是這樣的,但我確實沒有足夠的信息。thanx again – serge 2010-05-17 19:09:06

+0

'addToJavaScriptWindowObject'可能應該連接到'javaScriptWindowObjectCleared'信號,以便在加載新頁面後重新添加。另外,當JavaScript通過'QWebSettings'爲這個頁面禁用時,不幸的是這種方式無法工作,並且我發現沒有辦法禁止它僅用於來自web的javascript。此外,我認爲所添加的對象可以通過網站訪問,所以如果可以加載任何網站,暴露「MainWindow」可能是一個壞主意。 – 2014-04-24 06:34:47

0

我有同樣的問題,但不想使用JavaScript,因爲我希望它能夠在QWebSettings禁用JavaScript的情況下也能正常工作。我基本上能想到的兩種方法:

  • 聆聽microFocusChanged信號的建議,然後做這樣的事情:

    frame = page.currentFrame() 
    elem = frame.findFirstElement('input:not([type=hidden]):focus textarea:focus') 
    if not elem.isNull(): 
        logging.debug("Clicked editable element!") 
    

    這當然有一定的開銷,因爲microFocusChanged發出多次,並且在很多情況下,不僅僅是如果選擇了輸入字段(例如當選擇文本時)。

    loadFinished中這樣做可能也是有意義的,因爲元素可以自動聚焦。

    我還沒有測試過,但打算很快實施它。

  • 如果我們只關心鼠標點擊,延長mousePressEvent並做了hitTestContent有:

    def mousePressEvent(self, e): 
        pos = e.pos() 
        frame = self.page().frameAt(pos) 
        pos -= frame.geometry().topLeft() 
        hitresult = frame.hitTestContent(pos) 
        if hitresult.isContentEditable(): 
         logging.debug("Clicked editable element!") 
        return super().mousePressEvent(e)