[PyQt] (pyqt)set different column font for qtableview

Maziar Parsijani maziar.parsijani at gmail.com
Fri Apr 26 06:36:06 BST 2019


This is great, thank you so much!

On Fri, Apr 26, 2019 at 3:43 AM Maurizio Berti <maurizio.berti at gmail.com>
wrote:

> Il giorno gio 25 apr 2019 alle ore 21:04 Maziar Parsijani <
> maziar.parsijani at gmail.com> ha scritto:
>
>> Hi
>> I want to know if it is possible to change font for each column in
>> Qtableview and if it is possible even more different appearances in columns
>> like backgrounds and font colors.
>>
>
>
> There are different possible approaches, and the choice usually depends on
> how the table data is filled and if it's editable.
> The most common way is to set the QtCore.Qt.ItemDataRole for each field
> index, by providing the FontRole, ForegroundRole and BackgroundRole to the
> index.setData(value, role).
> If you're using a QStandardItemModel, the data is simple and you don't
> need interaction, just use setData method on each item.
>
> If you are using any model based on QAbstractItemModel you could subclass
> its data method like this:
>
> class SimpleModel(QtGui.QStandardItemModel):
>     backgrounds = QtGui.QColor(QtCore.Qt.lightGray),
> QtGui.QColor(QtCore.Qt.darkCyan), QtGui.QColor(QtCore.Qt.darkGray)
>     foregrounds = QtGui.QColor(QtCore.Qt.darkGreen),
> QtGui.QColor(QtCore.Qt.darkBlue), QtGui.QColor(QtCore.Qt.yellow)
>     fonts = QtGui.QFont('monospace'), QtGui.QFont(), QtGui.QFont('times')
>
>     def data(self, index, role=QtCore.Qt.DisplayRole):
>         if role == QtCore.Qt.BackgroundRole:
>             return self.backgrounds[index.column()]
>         elif role == QtCore.Qt.ForegroundRole:
>             return self.foregrounds[index.column()]
>         elif role == QtCore.Qt.FontRole:
>             return self.fonts[index.column()]
>         return QtGui.QStandardItemModel.data(self, index, role)
>
> Note that you could also set a QIdentityProxyModel with your original
> model (and use the proxy on the table instead) and then implement the
> data() method in the same way. Just use the code above with
> QIdentityProxyModel instead of QStandardItemModel, do a
> setSource(originalModel) and you're done; this is usually better and much
> more transparent.
>
> If you cannot have that kind of access, the alternative is to create your
> own item delegate subclass and implement the paint() method. Be aware that
> item painting is not an easy task, expecially if you want to mimic the
> default implementation.
>
> class SimpleDelegate(QtWidgets.QStyledItemDelegate):
>     backgrounds = QtGui.QColor(QtCore.Qt.lightGray),
> QtGui.QColor(QtCore.Qt.darkCyan), QtGui.QColor(QtCore.Qt.darkGray)
>     foregrounds = QtGui.QColor(QtCore.Qt.darkGreen),
> QtGui.QColor(QtCore.Qt.darkBlue), QtGui.QColor(QtCore.Qt.yellow)
>     fonts = QtGui.QFont('monospace'), QtGui.QFont(), QtGui.QFont('times')
>     fontData = zip(backgrounds, foregrounds, fonts)
>
>     def paint(self, qp, option, index):
>         #painting needs performance, let's get all data at once
>         background, foreground, font = self.fontData[index.column()]
>
>         # never reuse the given option argument, always create a new one
> based on it!
>         # reusing QStyleOptions might create issues and inconsistencies
> with item "siblings"
>         option = QtWidgets.QStyleOptionViewItem(option)
>         self.initStyleOption(option, index)
>
>         # reset the text so that QStyle won't paint it
>         option.text = ''
>         option.backgroundBrush = background
>
>         widget = option.widget
>         style = widget.style()
>
>         # we could use the drawPrimitive instead, but it won't paint the
> decoration (icon),
>         # if it exists; drawControl paints everything, that's why I
> cleared the text before,
>         # otherwise you'll see the text drawn twice
>         style.drawControl(QtWidgets.QStyle.CE_ItemViewItem, option, qp)
>         #style.drawPrimitive(QtWidgets.QStyle.PE_PanelItemViewItem,
> option, qp)
>
>         # get the rectangle available for item text and adjust it to
> standard margins;
>         # one pixel is added for consistency with the original Qt painting
> behavior
>         textRect = style.subElementRect(style.SE_ItemViewItemText, option,
> widget)
>         margin = style.pixelMetric(style.PM_FocusFrameHMargin, option,
> widget) + 1
>         textRect.adjust(margin, 0, -margin, 0)
>
>         # set the foreground color to the palette (not to the painter!)
>         option.palette.setColor(option.palette.Active,
> option.palette.Base, foreground)
>         # if you want to have differrent colors for disabled items, use
> again the setColor
>         # method with option.palette.Disabled
>         #option.palette.setColor(option.palette.Disabled,
> option.palette.Base, disabledColor)
>
>         qp.setFont(font)
>         style.drawItemText(qp, textRect,
> style.visualAlignment(option.direction, option.displayAlignment),
>             option.palette, option.state & style.State_Enabled,
>             option.fontMetrics.elidedText(index.data(),
> option.textElideMode, textRect.width()),
>             option.palette.Base)
>
>
> class MyTable(QtWidget.QTableView):
>     def __init__(self, *args, **kwargs):
>         QtWidgets.QTableView.__init__(self, *args, **kwargs)
>         self.setItemDelegate(SimpleDelegate())
>
>
> Unfortunately, this is not quite perfect: while it should be fine for most
> user cases, it doesn't take into account the word wrapping, meaning that
> the text will always be on one line, no matter how much the row height is
> big. To fix this, it would take about 60-70 more lines of code, which would
> be run at each paintEvent for each visible item. Not always a good idea,
> but if you think it's good enough, you can find how it's done from the
> calculateElidedText method called by viewItemDrawText in here:
> https://code.woboq.org/qt5/qtbase/src/widgets/styles/qcommonstyle.cpp.html
>
> Cheers,
> Maurizio
>
> --
> È difficile avere una convinzione precisa quando si parla delle ragioni
> del cuore. - "Sostiene Pereira", Antonio Tabucchi
> http://www.jidesk.net
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20190426/10a83c59/attachment-0001.html>


More information about the PyQt mailing list