Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to workaround change in Qt 5 handling of QListView.mousePressEvent and QStyledItemDelegate.editorEvent?
Forum Update on Monday, May 27th 2025

How to workaround change in Qt 5 handling of QListView.mousePressEvent and QStyledItemDelegate.editorEvent?

Scheduled Pinned Locked Moved Solved General and Desktop
qlistviewqstyleditemdelepython3
4 Posts 2 Posters 1.5k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • D Offline
    D Offline
    DamonLynch
    wrote on 5 Mar 2020, 21:13 last edited by
    #1

    Between Qt 5.12.2 and 5.12.7 (I'm unsure precisely which release), Qt 5 behavior changed in the following scenario:

    • A class inheriting QListView is created and selection mode is set to QAbstractItemView.ExtendedSelection. Let's call this subclass ThumbnailView.
    • mousePressEvent is initiated after a left mouse button click
    • The ThumbnailView.mousePressEvent determines the left click was in a particular region of a QListView cell (e.g. over a QStyleOptionButton), and does not call the parent class mousePressEvent(event)

    In Qt 5.12.2, the delegate editorEvent is called regardless of whether the subclass called the parent class mousePressEvent. In Qt 5.12.7, mousePressEvent is called only if the the parent class mousePressEvent was called. It appears as if some versions of Qt are patched to mimic the behavior in Qt 5.12.7, e.g. in openSUSE Leap 15.1.

    Why this is important? When the user clicks a thumbnail checkbox the action of marking / unmarking is applied to all the selected thumbnails, not just the single checkbox in a single thumbnail:
    alt text
    With default Qt 5 behavior, marking the checkbox deselects all other listview items and selects only the listview item containing the checkbox, which is the behavior I want to override.
    My PyQt5 code to do this is (irrelevant class members removed):

    class ThumbnailView(QListView):
    
        def __init__(self, parent: QWidget) -> None:
            style = """QAbstractScrollArea { background-color: %s;}""" % ThumbnailBackgroundName
            super().__init__(parent)
            self.rapidApp = parent
            self.setViewMode(QListView.IconMode)
            self.setResizeMode(QListView.Adjust)
            self.setStyleSheet(style)
            self.setUniformItemSizes(True)
            self.setSpacing(8)
            self.setSelectionMode(QAbstractItemView.ExtendedSelection)
    
            self.selectionToRestore = self.selectedIndexesToRestore = None
    
            try:
                major, minor, patch = [int(v) for v in QT_VERSION_STR.split('.')]
            except ValueError:
                logging.error("Could not determine Qt version using %s", QT_VERSION_STR)
                self.editorEvent_always_triggered = False
            else:
                self.editorEvent_always_triggered = minor <= 12 and patch < 7
                if self.editorEvent_always_triggered:
                    logging.info('Disabling editorEvent workaround with Qt %s', QT_VERSION_STR)
                else:
                    logging.info('Applying editorEvent workaround')
    
        @pyqtSlot(QMouseEvent)
        def mousePressEvent(self, event: QMouseEvent) -> None:
            """
            Filter selection changes when click is on a thumbnail checkbox.
    
            When the user has selected multiple items (thumbnails), and
            then clicks one of the checkboxes, Qt's default behaviour is to
            treat that click as selecting the single item, because it doesn't
            know about our checkboxes. Therefore if the user is in fact
            clicking on a checkbox, we need to filter that event.
    
            On some versions of Qt 5 (to be determined), no matter what we do here,
            the delegate's editorEvent will still be triggered.
    
            :param event: the mouse click event
            """
    
            right_button_pressed = event.button() == Qt.RightButton
            if right_button_pressed:
                super().mousePressEvent(event)
    
            else:
                checkbox_clicked = False
                index = self.indexAt(event.pos())
                row = index.row()
                if row >= 0:
                    rect = self.visualRect(index)  # type: QRect
                    delegate = self.itemDelegate(index)  # type: ThumbnailDelegate
                    checkboxRect = delegate.getCheckBoxRect(rect)
                    checkbox_clicked = checkboxRect.contains(event.pos())
                    if checkbox_clicked:
                        status = index.data(Roles.download_status)  # type: DownloadStatus
                        checkbox_clicked = status not in Downloaded
    
                if not checkbox_clicked:
                    if self.rapidApp.prefs.auto_scroll and row >= 0:
                        self._scrollTemporalProximity(row=row)
                    super().mousePressEvent(event)
                elif not self.editorEvent_always_triggered:
                    if self.selectionModel().selection().contains(index):
                        if len(self.selectionModel().selectedIndexes()) > 1:
                            super().keyPressEvent(QKeyEvent(QEvent.KeyPress, Qt.Key_Space, Qt.NoModifier, ' '))
                    else:
                        super().mousePressEvent(event)
    

    The code is hopefully self-explanatory. The line containing delegate.getCheckBoxRect(rect) simply returns the QRect of the checkbox. The code from which it is taken is available here.

    My workaround with Qt >= 5.12.7 when multiple items are selected and the user clicks a checkbox in one of the selected items is to convert the button press into a spacebar press, which does not affect the selection. It works well enough — except for when older versions of Qt are patched by a Linux distro!

    What can I do differently to make this code more robust?

    1 Reply Last reply
    0
    • C Online
      C Online
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on 5 Mar 2020, 21:30 last edited by
      #2

      @DamonLynch said in How to workaround change in Qt 5 handling of QListView.mousePressEvent and QStyledItemDelegate.editorEvent?:

      What can I do differently to make this code more robust?

      Provide a proper simple testcase (in c++), create a bugreport and let us know :)

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      D 1 Reply Last reply 5 Mar 2020, 21:38
      0
      • C Christian Ehrlicher
        5 Mar 2020, 21:30

        @DamonLynch said in How to workaround change in Qt 5 handling of QListView.mousePressEvent and QStyledItemDelegate.editorEvent?:

        What can I do differently to make this code more robust?

        Provide a proper simple testcase (in c++), create a bugreport and let us know :)

        D Offline
        D Offline
        DamonLynch
        wrote on 5 Mar 2020, 21:38 last edited by
        #3

        @Christian-Ehrlicher said in How to workaround change in Qt 5 handling of QListView.mousePressEvent and QStyledItemDelegate.editorEvent?:

        @DamonLynch said in How to workaround change in Qt 5 handling of QListView.mousePressEvent and QStyledItemDelegate.editorEvent?:

        What can I do differently to make this code more robust?

        Provide a proper simple testcase (in c++), create a bugreport and let us know :)

        @Christian-Ehrlicher sorry, but that would be rather difficult for me. It has been more than 20 years since I last touched C++ code. If the bug report example code really has to be in C++, I would be extremely grateful if someone could produce a C++ testcase.

        1 Reply Last reply
        0
        • D Offline
          D Offline
          DamonLynch
          wrote on 9 Apr 2020, 01:11 last edited by
          #4

          In case anyone comes across this in a search, I was able to solve the problem by manipulating the selection in the class member function selectionChanged():

          https://bazaar.launchpad.net/~dlynch3/rapid/zeromq_pyqt/revision/1178#raphodo/thumbnaildisplay.py

          Perhaps that was always the best way to do it.

          1 Reply Last reply
          0

          • Login

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • Users
          • Groups
          • Search
          • Get Qt Extensions
          • Unsolved