Re: (pyqt)set different column font for qtableview
Maurizio Berti <[email protected]>
| Newsgroups | gmane.comp.python.pyqt-pykde |
|---|---|
| Message-ID | <CAPn+-XROzGZB0vVBbb1LYRqjW6fyTLRpLL2uFoiVkhdutukmFg@mail.gmail.com> |
Il giorno gio 25 apr 2019 alle ore 21:04 Maziar Parsijani < [email protected]> 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 _______________________________________________ PyQt mailing list [email protected] https://www.riverbankcomputing.com/mailman/listinfo/pyqt