簡體   English   中英

使用 QWebEngineView 時如何捕獲按鍵事件?

[英]How to capture key-press events when using QWebEngineView?

## minimal code
import sys
from PyQt5 import QtWidgets
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtCore import Qt

class Browser(QWebEngineView):
    def __init__(self, parent=None):
        super(Browser, self).__init__(parent)
        self.setHtml(r"""
        <div><textarea></textarea></div>
        <style>
        *{margin:0;}
        div {
            height: 100%;
            position: relative;
            background:grey;
        }
        textarea {
            background:red;
            height: 50%;
            width: 50%;
            resize: none;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
        }
        </style>
        """)

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        central=QtWidgets.QWidget(self)
        self.setCentralWidget(central)
        layout = QtWidgets.QGridLayout(central)
        self.browser = Browser(central)
        layout.addWidget(self.browser)
        another=QtWidgets.QWidget(central)
        layout.addWidget(another)
        another.setFocusPolicy(Qt.StrongFocus)

    def keyPressEvent(self, e):
        print("KEY PRESSED")
        return super().keyPressEvent(e)

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.setGeometry(300, 50, 800, 600)
    window.show()

    sys.exit(app.exec_())

當前行為:

情況1:

  1. 單擊白色區域(小部件)。
  2. 按一個鍵。
  3. KEY PRESSED登錄到控制台。

案例二:

  1. 單擊灰色區域(網絡視圖)。
  2. 按一個鍵。
  3. KEY PRESSED登錄到控制台。

案例3:

  1. 單擊紅色區域(webview 內的文本區域)。
  2. 按一個鍵。
  3. 沒有任何內容登錄到控制台。

必需的行為

我希望所有案例都將KEY PRESSED一次記錄到控制台中。

我嘗試過的事情

我嘗試向MainWindow添加一個eventFilter ,但它給出了相同的輸出。

我還通過將關鍵事件轉發到MainWindow嘗試了此答案的解決方案,但隨后它為案例 2 記錄了兩次KEY PRESSED

我無法區分傳播到MainWindow的事件(案例 2)和未傳播的事件(案例 3),因此我可以實施一些措施來忽略多余的 function 調用。

問題是 Qt 必須將事件傳遞給內部 Chrome 瀏覽器,這使事件傳播的正常過程變得復雜。 我能找到的最簡單的解決方案是在內部 web-view 委托上安裝一個事件過濾器,同時忽略來自主按鍵處理程序中委托的任何事件:

from PyQt5.QtCore import QEvent

class Browser(QWebEngineView):
    ...    
    def eventFilter(self, source, event):
        if event.type() == QEvent.KeyPress and source.parent() is self:
            print("KEY PRESSED:", source)
        return super().eventFilter(source, event)

    def childEvent(self, event):
        if event.added() and event.child().isWidgetType():
            event.child().installEventFilter(self)
        super().childEvent(event)

class MainWindow(QtWidgets.QMainWindow):
    ...    
    def keyPressEvent(self, e):
        target = QtWidgets.QApplication.focusWidget()
        if target.parentWidget() is not self.browser:
            print("KEY PRESSED:", target)
        return super().keyPressEvent(e)

我所做的是使用這篇文章中的ForwardKeyEvent class 將關鍵事件從browser轉發到MainWindow 我忽略了browser發送的任何QKeyEvent並接受了人為發送的 QKeyEvent。 這對我來說更方便,因為所有日志記錄都是由一個 function 完成的,這是在有 QKeyEvent 時需要調用的QKeyEvent

class ForwardKeyEvent(QObject):
    ## https://stackoverflow.com/a/57012924/14908508
    def __init__(self, sender, receiver, parent=None):
        super(ForwardKeyEvent, self).__init__(parent)
        self.m_sender = sender
        self.m_receiver = receiver
        self.m_sender.installEventFilter(self)

    def eventFilter(self, obj, event):
        if self.m_sender is obj and event.type() == QEvent.KeyPress:
            new_event = QKeyEvent(
                QEvent.KeyPress,
                event.key(),
                event.modifiers(),
                event.text(),
            )
            new_event.artificial = True
            QCoreApplication.postEvent(self.m_receiver, new_event)
        return super().eventFilter(obj, event)

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        ...
        
        self.FKE = ForwardKeyEvent(self.browser.focusProxy(), self)
    
    def keyPressEvent(self, e):
        target = QtWidgets.QApplication.focusWidget()
        if target.parentWidget() is not self.browser or hasattr(e,"artificial"):
            print("KEY PRESSED:", target)
        return super().keyPressEvent(e)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM