QScrollArea 是否对 wheelEvent 做出反应,也在 space 中被儿童占用?

Have QScrollArea react on wheelEvent, also in space taken up by children?

考虑这个例子:

#!/usr/bin/env python

import sys,os
from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtCore import Qt

class MainWindow(QtWidgets.QMainWindow):

    class ScrollAreaWheel(QtWidgets.QScrollArea): # SO:9475772
        def __init__(self, parent=None):
            super(MainWindow.ScrollAreaWheel, self).__init__(parent)
            self.parent = parent
        def wheelEvent(self, event):
            print("wheelEvent", event.angleDelta().y())

    def __init__(self):
        #~ self.do_init = QtCore.QEvent.registerEventType()
        QtWidgets.QMainWindow.__init__(self)
        self.setMinimumWidth(1000)
        self.setMinimumHeight(400)
        self.frame1 = QtWidgets.QFrame(self)
        self.frame1.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame1layout = QtWidgets.QGridLayout(self.frame1)
        self.frame1layout.setSpacing(0);
        self.frame1layout.setContentsMargins(0,0,0,0);

        self.frame1widget = QtWidgets.QWidget()
        self.frame1widget.setLayout(QtWidgets.QGridLayout())
        self.frame1layout.addWidget(self.frame1widget)

        self.frame1scroll = MainWindow.ScrollAreaWheel(self) #QtWidgets.QScrollArea()
        self.frame1scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.frame1scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.frame1widget.layout().addWidget(self.frame1scroll, 0, 0) #, Qt.AlignCenter)

        #self.frame1scrolllayout = QtWidgets.QHBoxLayout(self.frame1scroll)
        self.frame1scrolllayout = QtWidgets.QGridLayout(self.frame1scroll)
        self.frame1scroll.setWidget(self.frame1scrolllayout.widget())
        self.frame1scroll.setWidgetResizable(True)
        self.frame1scroll.setAlignment(Qt.AlignCenter)

        self.frame1label = QtWidgets.QLabel()
        self.frame1scrolllayout.addWidget(self.frame1label, 0, 0, Qt.AlignCenter) ##

        pixmap = QtGui.QPixmap(200, 100)
        pixmap.fill(Qt.red)
        self.frame1label.setPixmap(pixmap)

        self.frame2 = QtWidgets.QFrame(self)
        self.frame2.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame2layout = QtWidgets.QHBoxLayout(self.frame2)
        self.frame2layout.setSpacing(0);
        self.frame2layout.setContentsMargins(0,0,0,0);
        self.frame2scroll = QtWidgets.QScrollArea(self)
        self.frame2scroll.setWidgetResizable(True)
        self.frame2widget = QtWidgets.QWidget()
        self.frame2widget.setLayout(QtWidgets.QGridLayout())
        self.frame2scroll.setWidget(self.frame2widget)
        self.frame2layout.addWidget(self.frame2scroll)

        self.mainwid = QtWidgets.QWidget()
        self.mainwid.setLayout(QtWidgets.QGridLayout())
        self.setCentralWidget(self.mainwid)

        self.splitter1 = QtWidgets.QSplitter(Qt.Horizontal)
        self.splitter1.addWidget(self.frame1)
        self.splitter1.addWidget(self.frame2)
        self.splitter1.setSizes([600, 600]); # equal splitter at start
        self.mainwid.layout().addWidget(self.splitter1)
        self.mainwid.layout().update()


if __name__ == "__main__":
    app = QtWidgets.QApplication([])
    main = MainWindow()
    main.show()
    sys.exit(app.exec_())

它生成这个 (Ubuntu 18.04):

我只想在左侧 QScrollArea 上使用鼠标滚轮,为此我单独制作了一个 class。然而,它的 wheelEvent 仅在我在红色框外时触发,而不是当我将鼠标悬停在它上面时。即使鼠标位于子标签(红色框)上,我怎样才能让 ScrollAreaWheel.wheelEvent 触发?

你是 QLabel 放在 QScrollArea 上面,而不是放在里面,视觉上是一样的,但在事件级别上却不是。

from PyQt5 import QtCore, QtGui, QtWidgets

class ScrollAreaWheel(QtWidgets.QScrollArea):
    def wheelEvent(self, event):
        print("wheelEvent", event.angleDelta().y())

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setMinimumSize(1000, 400)

        frame1 = QtWidgets.QFrame(frameShape=QtWidgets.QFrame.StyledPanel)
        scrollarea1 = ScrollAreaWheel(widgetResizable=True)
        scrollarea1.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        scrollarea1.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        widget1 = QtWidgets.QWidget()
        scrollarea1.setWidget(widget1)
        label_lay = QtWidgets.QGridLayout(widget1)
        lay1 = QtWidgets.QVBoxLayout(frame1)
        lay1.addWidget(scrollarea1)

        pixmap = QtGui.QPixmap(200, 100)
        pixmap.fill(QtCore.Qt.red)
        label = QtWidgets.QLabel(pixmap=pixmap)
        label_lay.addWidget(label, 0, 0, QtCore.Qt.AlignCenter)

        #==============================

        frame2 = QtWidgets.QFrame(frameShape=QtWidgets.QFrame.StyledPanel)
        scrollarea2 = QtWidgets.QScrollArea(widgetResizable=True)
        scrollarea2.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        scrollarea2.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        widget2 = QtWidgets.QWidget()
        scrollarea2.setWidget(widget2)

        splitter = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
        splitter.addWidget(frame1)
        splitter.addWidget(frame2)
        splitter.setSizes([600, 600])
        self.setCentralWidget(splitter)

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.resize(640, 480)
    w.show()
    sys.exit(app.exec_())