[prev in list] [next in list] [prev in thread] [next in thread]
List: pykde
Subject: Re: [PyQt] (pyqt)set different column font for qtableview
From: Maziar Parsijani <maziar.parsijani () gmail ! com>
Date: 2019-04-26 5:48:06
Message-ID: CAPD04aOTaKVrCJ_xno5bn61SKA+uFwoxi3oBrUX_SkLjaX2uOg () mail ! gmail ! com
[Download RAW message or body]
[Attachment #2 (multipart/alternative)]
This is great, thank you so much!
On Fri, Apr 26, 2019 at 3:43 AM Maurizio Berti <maurizio.berti@gmail.com>
wrote:
> Il giorno gio 25 apr 2019 alle ore 21:04 Maziar Parsijani <
> maziar.parsijani@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
>
[Attachment #5 (text/html)]
<div dir="ltr">This is great, thank you so much! <br></div><br><div \
class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Apr 26, 2019 at 3:43 AM \
Maurizio Berti <<a \
href="mailto:maurizio.berti@gmail.com">maurizio.berti@gmail.com</a>> \
wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px \
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div \
dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div \
dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div \
dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div \
dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr" \
class="gmail_attr">Il giorno gio 25 apr 2019 alle ore 21:04 Maziar Parsijani <<a \
href="mailto:maziar.parsijani@gmail.com" \
target="_blank">maziar.parsijani@gmail.com</a>> ha scritto:<br></div><blockquote \
class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid \
rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div>Hi</div><div>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.</div></div></blockquote><div><br></div><div><br></div></div><div \
dir="ltr">There are different possible approaches, and the choice usually depends on \
how the table data is filled and if it's editable.<div>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).<br>If you're \
using a QStandardItemModel, the data is simple and you don't need interaction, \
just use setData method on each item.</div><div><br></div><div>If you are using any \
model based on QAbstractItemModel you could subclass its data method like \
this:</div><div><br></div><div><div><font face="monospace, monospace">class \
SimpleModel(QtGui.QStandardItemModel):</font></div><div><span \
style="font-family:monospace,monospace"> backgrounds = \
QtGui.QColor(QtCore.Qt.lightGray), QtGui.QColor(QtCore.Qt.darkCyan), \
QtGui.QColor(QtCore.Qt.darkGray)</span><br></div><div><font face="monospace, \
monospace"> foregrounds = QtGui.QColor(QtCore.Qt.darkGreen), \
QtGui.QColor(QtCore.Qt.darkBlue), \
QtGui.QColor(QtCore.Qt.yellow)</font></div><div><div><font face="monospace, \
monospace"> fonts = QtGui.QFont('monospace'), QtGui.QFont(), \
QtGui.QFont('times')</font></div></div><div><font face="monospace, \
monospace"><br></font></div><div><font face="monospace, monospace"> def \
data(self, index, role=QtCore.Qt.DisplayRole):</font></div><div><font \
face="monospace, monospace"> if role == \
QtCore.Qt.BackgroundRole:</font></div><div><font face="monospace, monospace"> \
return self.backgrounds[index.column()]</font></div><div><span \
style="font-family:monospace,monospace"> elif role == \
QtCore.Qt.ForegroundRole:</span><br></div><div><font face="monospace, monospace"> \
return self.foregrounds[index.column()]</font></div><div><font face="monospace, \
monospace"> elif role == QtCore.Qt.FontRole:</font></div><div><font \
face="monospace, monospace"> return \
self.fonts[index.column()]</font></div><div><span \
style="font-family:monospace,monospace"> return \
QtGui.QStandardItemModel.data(self, index, \
role)</span><br></div></div><div><br></div><div>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.</div><div><br></div><div>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.</div><div><br></div><div><div><font \
face="monospace, monospace">class \
SimpleDelegate(QtWidgets.QStyledItemDelegate):</font></div><div><font \
face="monospace, monospace"> backgrounds = QtGui.QColor(QtCore.Qt.lightGray), \
QtGui.QColor(QtCore.Qt.darkCyan), \
QtGui.QColor(QtCore.Qt.darkGray)</font></div><div><font face="monospace, monospace"> \
foregrounds = QtGui.QColor(QtCore.Qt.darkGreen), QtGui.QColor(QtCore.Qt.darkBlue), \
QtGui.QColor(QtCore.Qt.yellow)</font></div><div><font face="monospace, monospace"> \
fonts = QtGui.QFont('monospace'), QtGui.QFont(), \
QtGui.QFont('times')</font></div><div><font face="monospace, monospace"> \
fontData = zip(backgrounds, foregrounds, fonts)</font></div><div><font \
face="monospace, monospace"><br></font></div><div><font face="monospace, monospace"> \
def paint(self, qp, option, index):</font></div><div><font face="monospace, \
monospace"> #painting needs performance, let's get all data at \
once</font></div><div><font face="monospace, monospace"> background, \
foreground, font = self.fontData[index.column()]</font></div><div><font \
face="monospace, monospace"><br></font></div><div><font face="monospace, monospace"> \
# never reuse the given option argument, always create a new one based on \
it!</font></div><div><font face="monospace, monospace"> # reusing \
QStyleOptions might create issues and inconsistencies with item \
"siblings"</font></div><div><font face="monospace, monospace"> \
option = QtWidgets.QStyleOptionViewItem(option)</font></div><div><font \
face="monospace, monospace"> self.initStyleOption(option, \
index)</font></div><div><font face="monospace, monospace"><br></font></div><div><font \
face="monospace, monospace"> # reset the text so that QStyle won't \
paint it</font></div><div><font face="monospace, monospace"> option.text = \
''</font></div><div><font face="monospace, monospace"> \
option.backgroundBrush = background</font></div><div><font face="monospace, \
monospace"><br></font></div><div><font face="monospace, monospace"> widget \
= option.widget</font></div><div><span style="font-family:monospace,monospace"> \
style = widget.style()</span><br></div><div><font face="monospace, \
monospace"><br></font></div><div><font face="monospace, monospace"> # we \
could use the drawPrimitive instead, but it won't paint the decoration (icon), \
</font></div><div><font face="monospace, monospace"> # if it exists; \
drawControl paints everything, that's why I cleared the text \
before,</font></div><div><font face="monospace, monospace"> # otherwise \
you'll see the text drawn twice</font></div><div><font face="monospace, \
monospace"> style.drawControl(QtWidgets.QStyle.CE_ItemViewItem, option, \
qp)</font></div><div><font face="monospace, monospace"> \
#style.drawPrimitive(QtWidgets.QStyle.PE_PanelItemViewItem, option, \
qp)</font></div><div><br></div><div><span style="font-family:monospace,monospace"> \
# get the rectangle available for item text and adjust it to standard \
margins;</span></div><div><span style="font-family:monospace,monospace"> # \
one pixel is added for consistency with the original Qt painting \
behavior</span></div><div><span style="font-family:monospace,monospace"> \
textRect = style.subElementRect(style.SE_ItemViewItemText, option, \
widget)</span><br></div><div><font face="monospace, monospace"> margin = \
style.pixelMetric(style.PM_FocusFrameHMargin, option, widget) + \
1</font></div><div><font face="monospace, monospace"> \
textRect.adjust(margin, 0, -margin, 0)</font></div><div><font face="monospace, \
monospace"><br></font></div><div><div><font face="monospace, monospace"> # \
set the foreground color to the palette (not to the painter!)</font></div><div><span \
style="font-family:monospace,monospace"> \
option.palette.setColor(option.palette.Active, option.palette.Base, \
foreground)</span><br></div><div><span style="font-family:monospace,monospace"> \
# if you want to have differrent colors for disabled items, use again the \
setColor</span><br></div><div><font face="monospace, monospace"> \
#</font><span style="font-family:monospace,monospace"> </span><span \
style="font-family:monospace,monospace">method</span><span \
style="font-family:monospace,monospace"> with \
option.palette.Disabled</span></div><div><span \
style="font-family:monospace,monospace"> \
#option.palette.setColor(option.palette.Disabled, option.palette.Base, \
disabledColor)</span><br></div><div><font face="monospace, \
monospace"><br></font></div><div><font face="monospace, monospace"> \
qp.setFont(font)</font></div><div><font face="monospace, monospace"> \
style.drawItemText(qp, textRect, style.visualAlignment(option.direction, \
option.displayAlignment), </font></div><div><font face="monospace, monospace"> \
option.palette, option.state & style.State_Enabled, </font></div><div><span \
style="font-family:monospace,monospace"> \
option.fontMetrics.elidedText(index.data(), option.textElideMode, textRect.width()), \
</span><br></div><div><font face="monospace, monospace"> \
option.palette.Base)</font></div></div></div><div><font face="monospace, \
monospace"><br></font></div><div><font face="monospace, \
monospace"><br></font></div><div><font face="monospace, monospace">class \
MyTable(QtWidget.QTableView):</font></div><div><font face="monospace, monospace"> \
def __init__(self, *args, **kwargs):</font></div><div><font face="monospace, \
monospace"> QtWidgets.QTableView.</font><span \
style="font-family:monospace,monospace">__init__(self, *args, \
**kwargs)</span></div><div><span style="font-family:monospace,monospace"> \
self.setItemDelegate(SimpleDelegate())</span></div><div><font face="monospace, \
monospace"><br></font></div><div><br></div><div>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: <a \
href="https://code.woboq.org/qt5/qtbase/src/widgets/styles/qcommonstyle.cpp.html" \
target="_blank">https://code.woboq.org/qt5/qtbase/src/widgets/styles/qcommonstyle.cpp. \
html</a></div><div><br></div><div>Cheers,</div><div>Maurizio</div><div><br></div></div></div></div></div></div></div>-- \
<br><div dir="ltr" class="gmail-m_6407532008947120603gmail_signature">È difficile \
avere una convinzione precisa quando si parla delle ragioni del cuore. - \
"Sostiene Pereira", Antonio Tabucchi<br><a href="http://www.jidesk.net" \
target="_blank">http://www.jidesk.net</a></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div>
</blockquote></div>
[Attachment #6 (text/plain)]
_______________________________________________
PyQt mailing list PyQt@riverbankcomputing.com
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic