Qt Table 小部件。如何同时设置垂直 header 和水平 header 的 meaning/title?
Qt Table widget. How to set the meaning/title for vertical header and horizontal header together?
我知道如何将文本标签设置到行或列中 headers。但我想做这样的事情:
http://i.stack.imgur.com/eMM6U.jpg
我找不到任何关于如何在红色圆圈内做这件事的信息。我开始相信这不能用 QTableWidget 来完成。
谢谢 ;)
我认为标准 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.
所以你需要忘记它并禁用它,你应该实现你自己的 headers(设置你的颜色,你的文本等等),但我当然会帮助 meaning/title。我通过下一个项目委托实现了这一点:
.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
但是所有这些方法在这里都不是很有用,你可以通过一些具体的操作自己实现它,我将向你展示主要方法 - 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);
}
}
这段代码展示了主要思想,它不是最终版本,但你应该自己完成所有这些具体的事情。当然这种做法不是很容易,你可以直接创建图片并设置为单元格,但这样的话图片的可伸缩性就不好了。如果用户调整一些 headers 的大小,我的代码可以正常工作。为了证明,请查看不同尺寸的屏幕截图。
如果文本元素如此处所示
就足够了,可以使用标准 header 和我在评论中发布的 link 中的解决方案来完成:
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://whosebug.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://whosebug.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
如果 painter.drawControl()
-method 被任何其他 painter.draw...()
-method 任意元素替换,包括。可以在 cornerButton 上绘制图形。
我知道如何将文本标签设置到行或列中 headers。但我想做这样的事情:
http://i.stack.imgur.com/eMM6U.jpg
我找不到任何关于如何在红色圆圈内做这件事的信息。我开始相信这不能用 QTableWidget 来完成。
谢谢 ;)
我认为标准 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.
所以你需要忘记它并禁用它,你应该实现你自己的 headers(设置你的颜色,你的文本等等),但我当然会帮助 meaning/title。我通过下一个项目委托实现了这一点:
.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
但是所有这些方法在这里都不是很有用,你可以通过一些具体的操作自己实现它,我将向你展示主要方法 - 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);
}
}
这段代码展示了主要思想,它不是最终版本,但你应该自己完成所有这些具体的事情。当然这种做法不是很容易,你可以直接创建图片并设置为单元格,但这样的话图片的可伸缩性就不好了。如果用户调整一些 headers 的大小,我的代码可以正常工作。为了证明,请查看不同尺寸的屏幕截图。
如果文本元素如此处所示
就足够了,可以使用标准 header 和我在评论中发布的 link 中的解决方案来完成:
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://whosebug.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://whosebug.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
如果 painter.drawControl()
-method 被任何其他 painter.draw...()
-method 任意元素替换,包括。可以在 cornerButton 上绘制图形。