Search code examples
pythonqtqtreeviewpyside2qabstractitemmodel

align pixmap in column's center with QTreeView and QAbstractItemModel


How do I make a pixmap's alignment centered to its column in a QTreeView? I have 2 columns with icons that are aligned to left, but I want one of them centered, so this needs to work on a single column and not force the whole table to one alignment.

I'm using a QTreeView with QAbstractItemModel as its model. On one column I flagged it as QtCore.Qt.DecorationRole and return a pixmap in the model's data() method so that it displays images along that column.

All works well, except that the images all align left, and for the life of me I can't get them centered horizontally.

In the data() method, I tried returning QtCore.Qt.AlignCenter if the role was QtCore.Qt.TextAlignmentRole, but that seems to only effect text (duh!).

Is there another way to achieve this? I'm not interested in taking the route of delegates if possible.


Solution

  • A possible solution is to overwrite the delegate's initStyleOption() method:

    from PySide2 import QtCore, QtGui, QtWidgets
    
    
    class IconCenterDelegate(QtWidgets.QStyledItemDelegate):
        def initStyleOption(self, option, index):
            super(IconCenterDelegate, self).initStyleOption(option, index)
            option.decorationAlignment = (
                QtCore.Qt.AlignHCenter | QtCore.Qt.AlignCenter
            )
            option.decorationPosition = QtWidgets.QStyleOptionViewItem.Top
    
    
    if __name__ == "__main__":
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
        w = QtWidgets.QTreeView()
        model = QtGui.QStandardItemModel(w)
        w.setModel(model)
        delegate = IconCenterDelegate(w)
        w.setItemDelegateForColumn(1, delegate)
        icons = [
            "SP_TitleBarMinButton",
            "SP_TitleBarMenuButton",
            "SP_TitleBarMaxButton",
            "SP_TitleBarCloseButton",
            "SP_TitleBarNormalButton",
            "SP_TitleBarShadeButton",
            "SP_TitleBarUnshadeButton",
            "SP_TitleBarContextHelpButton",
            "SP_MessageBoxInformation",
            "SP_MessageBoxWarning",
            "SP_MessageBoxCritical",
            "SP_MessageBoxQuestion",
            "SP_DesktopIcon",
        ]
        parent = model.invisibleRootItem()
        for icon_name in icons:
            icon = QtWidgets.QApplication.style().standardIcon(
                getattr(QtWidgets.QStyle, icon_name)
            )
            its = []
            for _ in range(3):
                it = QtGui.QStandardItem()
                it.setIcon(icon)
                its.append(it)
            parent.appendRow(its)
        model.appendRow(it)
        w.resize(640, 480)
        w.expandAll()
        w.show()
        sys.exit(app.exec_())
    

    enter image description here


    If you want the icons of all the columns to be aligned centrally then you could overwrite the viewOptions() method of the view:

    class TreeView(QtWidgets.QTreeView):
        def viewOptions(self):
            option = super().viewOptions()
            option.decorationAlignment = (
                QtCore.Qt.AlignHCenter | QtCore.Qt.AlignCenter
            )
            option.decorationPosition = QtWidgets.QStyleOptionViewItem.Top
            return option