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

先感谢您

有帮助吗?

解决方案

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

  1. 创建带有回调槽的 QObject 来接收事件。它可能是一些专用的处理程序对象或现有的对象,例如 QDialog/QMainWindow。
  2. 使用 QWebFrame.addToJavaScriptWindowObject(name, object) 注册用于 JavaScript 访问的 QObject。
  3. 编写 JavaScript 以添加 HTML 事件处理程序来调用已注册的 QObject 的回调槽。

添加焦点更改处理程序的 JavaScript 应遍历所有文本元素并添加 onfocus 和 onblur 处理程序。更好的方法是向 documentElement 添加单个处理程序并使用事件冒泡。不幸的是,onblur 广告 onfocus 不会冒泡。幸运的是,它们有一个名为 DOMFocusIn 和 DOMFocusOut 的冒泡对应项。

这是捕获页面文本元素的焦点输入/输出事件的完整示例。它声明了两个插槽 handleFocusInhandleFocusOut 在要从 JavaScript 调用的主窗口上,并将主窗口注册为名为的全局 JavaScript 变量 MainWindow. 。然后运行 ​​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++重写)。

其他提示

我遇到了同样的问题,但不想使用 Javascript ,因为我希望它即使在禁用 javascript 的情况下也能工作 QWebSettings. 。我基本上可以想到两种方法:

  • 聆听 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)
    
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top