sdaau
sdaau

Reputation: 38631

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

Consider this example:

#!/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_())

It generates this (Ubuntu 18.04):

pyqt5

I want to use mousewheel only on the left QScrollArea, for which I've made a separate class. However, its wheelEvent fires only when I'm outside the red box, not when I hover over it. How can I make ScrollAreaWheel.wheelEvent fire even when mouse is over the child label (the red box)?

Upvotes: 1

Views: 70

Answers (1)

eyllanesc
eyllanesc

Reputation: 244132

You are the QLabel placing on top of the QScrollArea instead of placing it inside, visually it is the same but at the level of events it is not.

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

Upvotes: 1

Related Questions