## 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_())
KEY PRESSED
is logged into the console. KEY PRESSED
is logged into the console. I want all of the cases to log KEY PRESSED
once into the console.
I tried adding an eventFilter
to the MainWindow
but it gives the same outout.
I also tried the solution from this answer by forwarding the key events to MainWindow
but then it logs KEY PRESSED
twice for Case 2.
I am not able to differentiate between the events that was propagated to MainWindow
(Case 2) and those that weren't (Case 3) so that I could've implemented something to ignore the excess function call.
The problem is that Qt must pass the events to the internal Chrome browser, which complicates the normal process of event-propagation. The simplest solution I could find is to install an event-filter on the internal web-view delegate, whilst also ignoring any events that come from the delegate in the main key-press handler:
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)
What I did was forward the key events from the browser
to the MainWindow
using the ForwardKeyEvent
class from this post . I ignored any QKeyEvent
sent by the browser
and accepted the ones that were sent artificially. This was more convenient for me since all the logging was done by one function, which is the function I needed to be called when there was a 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)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.