Как получить элемент фокуса в QWebView / QWebPage? - PullRequest
2 голосов
/ 16 мая 2010

Мне нужно иметь возможность реагировать на изменения фокуса в QWebPage. Я использовал сигнал microFocusChanged (), и он дает мне почти желательное поведение, но в любом случае я не знаю, как узнать, какой элемент выбран. Я хочу сделать некоторые действия, когда любой редактируемый элемент на странице получает или теряет фокус.

Заранее спасибо

Ответы [ 2 ]

7 голосов
/ 17 мая 2010

Для обработки любого события HTML на странице вы делаете следующее:

  1. Создание QObject со слотами обратного вызова для получения событий. Это может быть некоторый выделенный объект-обработчик или существующий объект, такой как ваш QDialog / QMainWindow.
  2. Зарегистрируйте указанный QObject для доступа к JavaScript с помощью QWebFrame.addToJavaScriptWindowObject (name, object).
  3. Напишите JavaScript для добавления обработчиков событий HTML, которые вызывают слоты обратного вызова вашего зарегистрированного QObject.

JavaScript для добавления обработчиков изменения фокуса должен пройти через все текстовые элементы и добавить обработчики onfocus и onblur. Еще лучше добавить отдельный обработчик к documentElement и использовать всплывающее окно событий. К сожалению, onblur ad onfocus не пузырьков. К счастью, у них есть пузырьковые аналоги DOMFocusIn и DOMFocusOut.

Вот полный пример перехвата фокусировки событий ввода / вывода для текстовых элементов страницы. Он объявляет два слота handleFocusIn и handleFocusOut в главном окне для вызова из JavaScripts и регистрирует главное окно как глобальную переменную 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_()

(я могу переписать в C ++, если вы ДЕЙСТВИТЕЛЬНО не можете понять Python).

0 голосов
/ 24 апреля 2014

У меня была та же проблема, но я не хотел использовать 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)
    
...