如何在QWebView / QWebPage中获得焦点元素?

时间:2010-05-16 13:52:15

标签: qt qwebview qwebpage

我需要能够对QWebPage中的焦点更改做出反应。我使用了microFocusChanged()信号,它给了我几乎所需的行为,但无论如何我不知道如何知道选择了哪个元素。我希望在页面上的任何可编辑元素获得或失去焦点时执行某些操作。

提前谢谢

2 个答案:

答案 0 :(得分:7)

要处理页面中的任何HTML事件,请执行以下操作:

  1. 使用回调槽创建QObject以接收事件。它可能是一些专用的处理程序对象或现有的对象,如QDialog / QMainWindow。
  2. 使用QWebFrame.addToJavaScriptWindowObject(name,object)注册表示QObject for JavaScript访问。
  3. 编写JavaScript以添加调用已注册QObject的回调插槽的HTML事件处理程序。
  4. 添加焦点更改处理程序的JavaScript应该遍历所有文本元素并添加onfocus和onblur处理程序。更好的是将单个处理程序添加到documentElement并使用事件冒泡。不幸的是,onblur广告onfocus不会冒泡。幸运的是,他们有一个名为DOMFocusIn和DOMFocusOut的冒泡对手。

    这是一个完整的检查页面文本元素的焦点进/出事件。它声明主窗口上的两个槽handleFocusInhandleFocusOut将从JavaScripts中调用,并将主窗口注册为名为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 ++重写。)

答案 1 :(得分: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)