Search code examples
pythonpyqtpyqt5qlistwidgetqlistwidgetitem

Pyqt - Lost selection highlighting on custom widget when adding to a QTreeViewItem in "IconMode"


I am trying to create a list of custom widgets where a user clicks them to open pictures/movies. I have everything working but I have lost the selection highlighting that usually comes with an item.

I know it's not there because I'm using a custom widget. How do I get selection highlight on the widget? I would like the item to show a transparent layer of blue.

Curious, when I change the view mode to ListMode you can see the blue selection. I have commented it out in the example code.

He is a striped back example, well as striped back as I can get it anyway. Switch the list views and select an item to see the different behaviour.

import sys
from datetime import datetime
from PyQt5 import QtWidgets
from PyQt5 import QtCore
from PyQt5 import QtGui


class EntryWidget(QtWidgets.QWidget):

    def __init__(self):
        super(EntryWidget, self).__init__()
        self.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))

        # controls
        self.thumbnail = QtWidgets.QLabel()
        self.version = QtWidgets.QLabel()
        self.date = QtWidgets.QLabel()
        self.name = QtWidgets.QLabel()
        self.name.setAlignment(QtCore.Qt.AlignCenter)
        self.author = QtWidgets.QLabel()
        self.author.setAlignment(QtCore.Qt.AlignRight)
        self.dummy = QtWidgets.QLabel(" ")

        # layout
        main_layout = QtWidgets.QVBoxLayout()

        main_layout.setContentsMargins(0, 0, 0, 0)
        main_layout.setSpacing(0)
        main_layout.addWidget(self.name)
        main_layout.addWidget(self.thumbnail)
        main_layout.addWidget(self.version)
        main_layout.addWidget(self.date)
        main_layout.addWidget(self.author)
        main_layout.addWidget(self.dummy)
        main_layout.addStretch()

        self.setLayout(main_layout)

    def set_size(self, w, h):
        self.thumbnail.setFixedSize(w, h)

    def set_version(self, name):
        self.version.setText(" Version:" + str(name))

    def set_date(self, name):
        date_string = " Date: {0}/{1}/{2}\n Time: {3}:{4}:{5}".format(
            str(name.day).zfill(2),
            str(name.month).zfill(2),
            name.year,
            name.hour,
            name.minute,
            name.second)
        self.date.setText(date_string)

    def set_name(self, name):
        self.name.setText(name)

    def set_author(self, name):
        self.author.setText(name + " ")

class QuickExample(QtWidgets.QDialog):
    def __init__(self, parent=None):
        super(QuickExample, self).__init__(parent)
        self.resize(500, 500)
        layout = QtWidgets.QVBoxLayout()

        media_list = QtWidgets.QListWidget(self)

        # switch the views and select an item
        media_list.setViewMode(QtWidgets.QListWidget.IconMode)
        # media_list.setViewMode(QtWidgets.QListWidget.ListMode)

        media_list.setResizeMode(QtWidgets.QListWidget.Adjust)
        media_list.setMovement(QtWidgets.QListWidget.Static)
        media_list.setSpacing(5)

        # dummy media, usually sourced from database
        media = [
            {"version": 1, "date": datetime.now(), "name": "Entry 01", "author": "Bob"},
            {"version": 2, "date": datetime.now(), "name": "Entry 02", "author": "John"}
        ]

        for i in media:
            # Create media Entry
            entry = EntryWidget()
            entry.set_version(i["version"])
            entry.set_date(i["date"])
            entry.set_size(128, 72)
            entry.set_name(i["name"])
            entry.set_author(i["author"])

            # Create QListWidgetItem
            media_item = QtWidgets.QListWidgetItem(media_list)

            # Set size hint
            media_item.setSizeHint(entry.sizeHint())

            # Add QListWidgetItem into QListWidget
            media_list.addItem(media_item)
            media_list.setItemWidget(media_item, entry)

        layout.addWidget(media_list)
        self.setLayout(layout)


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    example = QuickExample()
    example.show()
    sys.exit(app.exec_())

Solution

  • Well, I have found a hacky way of doing this which works fo me. I added some blank text to the QListWidgetItem and made the font really big. This brought back the highlighting for the item.

    media_item.setText("  ") # set the item with a  dummy string
    media_item.setFont(QFont('Verdana', 180)) # make the font big so it covers the whole widget
    

    After some research I found that using QListView and QItemDelegate is way to do this. I couldn't find a good example/tutorial using PyQt5 so I will just use this for now.

    Here is the code

    from PyQt5.QtCore    import *
    from PyQt5.QtGui     import *
    from PyQt5.QtWidgets import *
    
    from sys      import exit     as sysExit
    from datetime import datetime as dtDateTime
    
    class EntryWidget(QWidget):
        def __init__(self):
            QWidget.__init__(self)
    
            self.setCursor(QCursor(Qt.PointingHandCursor))
            self.setFocusPolicy(Qt.StrongFocus)  # Sets the Highlight when it has focus
    
          # Controls
            self.thumbnail = QLabel()
            self.version = QLabel()
            self.date = QLabel()
            self.name = QLabel()
            self.name.setAlignment(Qt.AlignCenter)
            self.author = QLabel()
            self.author.setAlignment(Qt.AlignRight)
            self.dummy = QLabel(" ")
    
          # Layout Container
            VBox = QVBoxLayout()
            VBox.setContentsMargins(0, 0, 0, 0)
            VBox.setSpacing(0)
            VBox.addWidget(self.name)
            VBox.addWidget(self.thumbnail)
            VBox.addWidget(self.version)
            VBox.addWidget(self.date)
            VBox.addWidget(self.author)
            VBox.addWidget(self.dummy)
            VBox.addStretch()
    
            self.setLayout(VBox)
    
        def set_size(self, w, h):
            self.thumbnail.setFixedSize(w, h)
    
        def set_version(self, name):
            self.version.setText(" Version:" + str(name))
    
        def set_date(self, name):
            date_string = " Date: {0}/{1}/{2}\n Time: {3}:{4}:{5}".format(
                str(name.day).zfill(2),
                str(name.month).zfill(2),
                name.year,
                name.hour,
                name.minute,
                name.second)
            self.date.setText(date_string)
    
        def set_name(self, name):
            self.name.setText(name)
    
        def set_author(self, name):
            self.author.setText(name + " ")
    
    class QuickExample(QDialog):
        def __init__(self):
            QDialog.__init__(self)
            self.resize(500, 500)
    
            media_list = QListWidget(self)
    
            # switch the views and select an item
            media_list.setViewMode(QListWidget.IconMode)
    
            media_list.setResizeMode(QListWidget.Adjust)
            media_list.setMovement(QListWidget.Static)
            media_list.setSpacing(5)
    
            # dummy media, usually sourced from database
            media = [
                {"version": 1, "date": dtDateTime.now(), "name": "Entry 01", "author": "Bob"},
                {"version": 2, "date": dtDateTime.now(), "name": "Entry 02", "author": "John"}
            ]
    
            for i in media:
                # Create media Entry
                entry = EntryWidget()
                entry.set_version(i["version"])
                entry.set_date(i["date"])
                entry.set_size(128, 72)
                entry.set_name(i["name"])
                entry.set_author(i["author"])
    
                # Create QListWidgetItem
                media_item = QListWidgetItem(media_list)
    
                ###########
                # the fix #
                ###########
    
                media_item.setText("  ") # set the item with a dummy string
                media_item.setFont(QFont('Verdana', 180)) # make the font big so it covers the whole widget
    
                # Set size hint
                media_item.setSizeHint(entry.sizeHint())
    
                # Add QListWidgetItem into QListWidget
                media_list.addItem(media_item)
                media_list.setItemWidget(media_item, entry)
    
            VBox = QVBoxLayout()
            VBox.addWidget(media_list)
    
            self.setLayout(VBox)
    
    
    if __name__ == "__main__":
        MainEventHandler = QApplication([])
        MainApplication = QuickExample()
        MainApplication.show()
        sysExit(MainEventHandler.exec_())