Reputation: 53
I know how to set text labels into row or column headers. But I want to do something like this:
https://i.sstatic.net/eMM6U.jpg
I don't find any info on how to do the thing inside the red circumference. I'm starting to believe this can't be done with QTableWidget.
Thanks ;)
Upvotes: 5
Views: 2407
Reputation: 4286
if text elements as shown here
are sufficient, it can be done with standard header and the solution from the link i posted in my comment:
from PyQt5 import QtCore, QtWidgets
class MyTableWidget(QtWidgets.QTableWidget):
def __init__(self, parent = None):
QtWidgets.QTableWidget.__init__(self, parent)
self.setRowCount(4)
self.setColumnCount(5)
self.items = []
self.items.append(['white ppt','no reaction', 'no reaction', 'no reaction', 'no reaction'])
self.items.append(['no reaction','white ppt', 'dissolves', 'dissolves', 'no reaction'])
self.items.append(['no reaction','pale yellow\nprecipitate', 'dissolves\npartly', 'dissolves', 'no reaction'])
self.items.append(['no reaction','yellow ppt', 'does not\ndissolve', 'does not\ndissolve', 'turns\nblue'])
self.horizontalHeader().setFixedHeight(90)
self.verticalHeader().setFixedWidth(120)
self.hh = ['Ca(NO\u2083)\u2082', 'AgNO\u2083','AgNO\u2083\n+\nNH\u2083','AgNO\u2083\n+\nNa\u2083S\u2082O\u2083','Starch\n+\nNaOCl']
self.vh = ['NaF', 'NaCl', 'NaBr or KBR', 'NaJ']
self.addItems()
self.addHeaderItems()
# text in cornerButton
btnTxt = '{: >15}\n{: >19}\n{:<}\n{:<}'.format('reagent', '\u21D2','halide', 'ion \u21D3')
# add cornerbutton from http://stackoverflow.com/questions/22635867/is-it-possible-to-set-the-text-of-the-qtableview-corner-button
btn = self.findChild(QtWidgets.QAbstractButton)
btn.setText(btnTxt)
btn.installEventFilter(self)
opt = QtWidgets.QStyleOptionHeader()
opt.text = btn.text()
# end cornerbutton
def addItems(self):
for r in range(0,len(self.items)):
for c in range(0,len(self.items[r])):
item = QtWidgets.QTableWidgetItem()
item.setText(self.items[r][c])
self.setItem(r,c,item)
def addHeaderItems(self):
for i in range(0,len(self.hh)):
item = QtWidgets.QTableWidgetItem()
item.setText(self.hh[i])
self.setHorizontalHeaderItem(i,item)
self.setColumnWidth(i,150)
for i in range(0,len(self.vh)):
item = QtWidgets.QTableWidgetItem()
item.setText(self.vh[i])
self.setVerticalHeaderItem(i,item)
self.setRowHeight(i,60)
# eventfilter from http://stackoverflow.com/questions/22635867/is-it-possible-to-set-the-text-of-the-qtableview-corner-button
def eventFilter(self, obj, event):
if event.type() != QtCore.QEvent.Paint or not isinstance(
obj, QtWidgets.QAbstractButton):
return False
# Paint by hand (borrowed from QTableCornerButton)
opt = QtWidgets.QStyleOptionHeader()
opt.initFrom(obj)
styleState = QtWidgets.QStyle.State_None
if obj.isEnabled():
styleState |= QtWidgets.QStyle.State_Enabled
if obj.isActiveWindow():
styleState |= QtWidgets.QStyle.State_Active
if obj.isDown():
styleState |= QtWidgets.QStyle.State_Sunken
opt.state = styleState
opt.rect = obj.rect()
# This line is the only difference to QTableCornerButton
opt.text = obj.text()
opt.position = QtWidgets.QStyleOptionHeader.OnlyOneSection
painter = QtWidgets.QStylePainter(obj)
painter.drawControl(QtWidgets.QStyle.CE_Header, opt)
return True
if painter.drawControl()
-method is replaced by any other painter.draw...()
-method arbitrary elements incl. graphics can be drawn on cornerButton.
Upvotes: 1
Reputation: 18504
I think that it is impossible with standard headers (QHeaderView) because of:
Note: Each header renders the data for each section itself, and does not rely on a delegate. As a result, calling a header's setItemDelegate() function will have no effect.
So you need forgot about it and disable it, you should implement your own headers(set your color, your text and so on), but I of course will help with meaning/title. I achieved this with next item delegate:
.h:
#ifndef ITEMDELEGATEPAINT_H
#define ITEMDELEGATEPAINT_H
#include <QStyledItemDelegate>
class ItemDelegatePaint : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit ItemDelegatePaint(QObject *parent = 0);
ItemDelegatePaint(const QString &txt, QObject *parent = 0);
protected:
void paint( QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index ) const;
QSize sizeHint( const QStyleOptionViewItem &option,
const QModelIndex &index ) const;
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
void setEditorData(QWidget * editor, const QModelIndex & index) const;
void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const;
void updateEditorGeometry(QWidget * editor, const QStyleOptionViewItem & option, const QModelIndex & index) const;
signals:
public slots:
};
#endif // ITEMDELEGATEPAINT_H
But all these method is not very useful here, you can implement it yourself with some specific actions, I will show you main method - paint()
void ItemDelegatePaint::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if(index.row() == 0 && index.column() == 0)
{
QRect source1 = QRect(option.rect.topLeft(),option.rect.size()/2);
QRect source2 = QRect(option.rect.topLeft(),option.rect.size()/2);
painter->drawLine(option.rect.topLeft(),option.rect.bottomRight());
source1.moveTopLeft(source1.topLeft() += QPoint(source1.size().width(),0));
painter->drawText(source1,"agent reagent");
source2.moveBottomLeft(source2.bottomLeft() += QPoint(0,source2.size().height()));
painter->drawText(source2,"hallide ion");
}
else
{
QStyledItemDelegate::paint(painter,option,index);
}
}
This code shows main idea and it is not final version, but you should do all these specific things by yourself. Of course this approach is not very easy, you can just create picture and set it to cell, but in this case picture will not be good scalable. My code works normal if user will resize some headers. To prove, see screenshots with different sizes.
Upvotes: 2