2

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.

Green Cell
  • 4,677
  • 2
  • 18
  • 49
  • @eyllanesc Hey is it ok if I keep the `qt` tag? It has tons of watchers and I don't mind if the solution is outside out python. – Green Cell Jun 04 '19 at 06:40
  • If you consider that my edition eliminated something important you can add it since you are the OP, each one has a different criterion. On the other hand I have marked a duplicate because the method used in QTableWidget is the same for the QTreeView since it is based on a method in the viewOptions method that belongs to the base class QAbstractItemView – eyllanesc Jun 04 '19 at 06:51
  • In the following link there is an example for PySide2 https://gist.github.com/eyllanesc/525a5f7dfd6fd51faa9fb2dd515d5bc5 – eyllanesc Jun 04 '19 at 06:56
  • That's ok, I didn't want to step on your toes and risk an edit war (some people on here easily take things the wrong way!) The duplicate question does fix the alignment, but for the WHOLE table as oppose to a column. For my case I can't use this solution as it's screwing up icons on other columns. – Green Cell Jun 04 '19 at 07:15
  • 1) I already have a lot of time here so I already know those wars for what it is for me: if the OP rejects my editing then I will follow my path, and if my editing was correct another user will have the opportunity to do the editing again. 2) What you point out is not very clear, perhaps placing an image of the error that brings the solution of the duplicate question that I have indicated may help, maybe what you indicated in your publication can be interpreted in different ways so maybe I mark it as duplicate that fits into one of the interpretations. – eyllanesc Jun 04 '19 at 07:20
  • No worries I get your reasoning. Well I have 2 columns that are using icons which are both default to align to left. I want the 2nd column to align center, and 1st to remain left. This solution forces both icons to center as it's an operation on the whole table. If that's still not clear I can post a screenshot. – Green Cell Jun 04 '19 at 07:25
  • Your comment is clear, I recommend placing in your publication that they only want to modify the alignment of the icon of a single column, in your question it is not clear that. – eyllanesc Jun 04 '19 at 07:28
  • Exactly, to only modify the alignment of one column. Sorry I can edit my question to include this. I just didn't think it was an issue as I posted! – Green Cell Jun 04 '19 at 07:29

1 Answers1

3

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
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Awesome! Just tested with `QAbstractItemModel` and it works! I had to include my `QTreeView` as a parent in the delegate's constructor otherwise it crashes, but it's probably because I'm not using `QStandardItemModel` and `QStandardItem` – Green Cell Jun 04 '19 at 08:03