How to get focus item in QWebView / QWebPage?

I will need to react to focus changes in the QWebPage. I used the microFocusChanged () signal and it gives me almost the desired behavior, but anyway I don't know how to find out which item is selected. I want to do some action when any editable element on the page gains or loses focus.

Thank you in advance

+2


a source to share


2 answers


To handle any HTML event inside the page, you do the following:

  • Create a QObject with callback slots to receive events. It can be some kind of dedicated handler object, or an existing object like your QDialog / QMainWindow.
  • Register a QObject to access JavaScript with QWebFrame.addToJavaScriptWindowObject (name, object).
  • Write JavaScript to add HTML event handlers that call registered QObject callback slots.

JavaScript to add focus change handlers must traverse all text elements and add onfocus and onblur handlers. Better yet, add a separate documentElement handler and use event bubbles. Unfortunately the onblur ad onfocus doesn't bubble up. Fortunately, they have bubbled copies called DOMFocusIn and DOMFocusOut.



Here's a complete example of catching focus to / from events for page text elements. It declares two slots handleFocusIn

and handleFocusOut

in the main window, which is called from JavaScripts, and registers the main window as a global JavaScript variable named MainWindow

. JavaScript is then executed to bind the DOMFocusIn / DOMFocusOut events to these slots (indirectly, because we need to filter out non-text elements).

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

      

(I can rewrite in C ++ if you REALLY can't understand Python).

+7


a source


I had the same problem, but I didn't want to use Javascript as I wanted it to work even with javascript disabled in QWebSettings

. I can basically think of two approaches:



  • Listen for the signal microFocusChanged

    as suggested and then do something like:

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

    This of course has some overhead because it is microFocusChanged

    emitted multiple times, and in many cases not only when selecting an input field (like when selecting text).

    It would probably be wise to do it in as well loadFinished

    , because the element can be autofocusable.

    I haven't tested this yet, but intend to implement it soon.

  • If we only care about mouseclicks expanding mousePressEvent

    and doing hitTestContent

    there:

    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)
    
          

0


a source







All Articles