Qt5 子类化 QStyledItemDelegate 格式
Posted
技术标签:
【中文标题】Qt5 子类化 QStyledItemDelegate 格式【英文标题】:Qt5 Subclassing QStyledItemDelegate Formatting 【发布时间】:2016-08-31 08:20:32 【问题描述】:我正在为 Qt5 中的 SQLite 数据库开发 GUI。我使用QSqlQueryModel
和QTableView
来存储和显示数据。
然后我创建了一个自定义委托,使用 switch 语句将某些列的数值替换为表格视图中的文字(例如 1 = "Hello", 2 = "World")。
委托按应有的方式显示数据并正常工作。但是,自定义委托绘制的列与QStyledItemDelegate
的默认绘制方法相比具有不同的格式。值在左上角而不是左中,更改后的列不再自动扩展列以显示完整值,并且列中的单元格在选择时不会变成蓝色或具有虚线轮廓。
我创建了这个示例程序:
#include <QApplication>
#include <QModelIndex>
#include <QPainter>
#include <QStandardItemModel>
#include <QStyledItemDelegate>
#include <QTableView>
class TestDelegate: public QStyledItemDelegate
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index)
const Q_DECL_OVERRIDE
if (index.column() == 0)
int value = index.model()->data(index, Qt::DisplayRole).toInt();
QString str;
switch (value)
case 1:
str = "Hello0000";
break;
case 2:
str = "World0000";
break;
if (option.state.testFlag (QStyle::State_Selected))
painter->fillRect(option.rect, option.palette.highlight());
qApp->style()->drawItemText(painter, option.rect, option.displayAlignment, option.palette, true, str, QPalette::HighlightedText);
else
painter->drawText(option.rect, option.displayAlignment, str);
else
return QStyledItemDelegate::paint(painter, option, index);
;
int main(int argc, char **argv)
QApplication app(argc, argv);
QStandardItemModel model(2, 2);
model.setHorizontalHeaderItem(0, new QStandardItem(QString("A")));
model.setHorizontalHeaderItem(1, new QStandardItem(QString("B")));
model.setData(model.index(0, 0, QModelIndex()), 1);
model.setData(model.index(1, 0, QModelIndex()), 2);
model.setItem(0, 1, new QStandardItem(QString("Hello")));
model.setItem(1, 1, new QStandardItem(QString("World0000")));
QTableView view;
view.setItemDelegate(new TestDelegate);
view.setModel(&model);
view.resizeColumnsToContents();
view.show();
app.exec();
这通过将options.displayAlignment
添加到painter->drawText()
来修复文本对齐;我还在if(option.state & QStyle::State_Selected)
语句中添加了附加代码,该语句根据其选择状态绘制单元格。因此,如果未选中,则文本为黑色,如果选中,则文本变为白色,背景变为蓝色。但是,我仍然无法让列扩展以适应单元格的内容,或者在单元格外部添加一条虚线,就像使用标准委托一样。
在使用我的自定义绘制方法时,有没有一种简单的方法可以保持表格视图的默认样式?
【问题讨论】:
你能提供你委托的代码吗? 里面的代码不多。它覆盖了委托的绘制方法,在方法主体内是: if (index.column() ==3) // switch 语句 //painter->drawText(option.rect, literalStr); else return QStyledItemDelegate: :paint(painter, option, index) 如果您只想用字符串值替换数字值以进行显示,您是否考虑过保留默认委托并插入代理模型?您可以继承QIdentityProxyModel
并覆盖其 data()
方法,这可能就是您所需要的。
我没有考虑代理,没有。我是 Qt5 的新手,看到星型委托示例与我想做的事情(更改模型数据在表格中的显示)有点相似,因此我将其用作起点。基本上,我的代表将int
s 更改为QString
s,就像上面一样,并使用QString.setNum(double, 'f', decimals)
设置双打的小数位数。从您的评论看来,代理模型可以做同样的事情,但要保持标准委托。它是否正确?如果是这样,您能否指出一个覆盖代理模型的 data()
方法的示例?
【参考方案1】:
委托是一种相当迂回且不必要的处理方式。我们已经有了一个可以完美绘制元素的视图,无需重做。我们只需要将修改后的数据传递给视图。因此,我们在源和视图之间插入了一个QIdentityProxyModel
视图模型。
// https://github.com/KubaO/***n/tree/master/questions/proxy-reformat-39244309
#include <QtWidgets>
class RewriteProxy : public QIdentityProxyModel
QMap<QVariant, QVariant> m_read, m_write;
int m_column;
public:
RewriteProxy(int column, QObject * parent = nullptr) :
QIdentityProxyModelparent, m_columncolumn
void addReadMapping(const QVariant & from, const QVariant & to)
m_read.insert(from, to);
m_write.insert(to, from);
QVariant data(const QModelIndex & index, int role) const override
auto val = QIdentityProxyModel::data(index, role);
if (index.column() != m_column) return val;
auto it = m_read.find(val);
return it != m_read.end() ? it.value() : val;
bool setData(const QModelIndex & index, const QVariant & value, int role) override
auto val = value;
if (index.column() == m_column)
auto it = m_write.find(value);
if (it != m_write.end()) val = it.value();
return QIdentityProxyModel::setData(index, val, role);
;
int main(int argc, char ** argv)
QApplication appargc, argv;
QStandardItemModel model2,2;
model.setData(model.index(0, 0), 1);
model.setData(model.index(1, 0), 2);
model.setData(model.index(0, 1), "Zaphod");
model.setData(model.index(1, 1), "Beeblebrox");
RewriteProxy proxy0;
proxy.setSourceModel(&model);
proxy.addReadMapping(1, "Hello");
proxy.addReadMapping(2, "World");
QTableView ui;
ui.setModel(&proxy);
ui.show();
return app.exec();
【讨论】:
解决方案不适用于 QSqlQueryModel。 “没有匹配函数调用'RewriteProxy::setSourceModel (QSqlQueryModel**)'”。 @Krippy_MD06 该解决方案绝对适用于任何型号。编译器会告诉你你做错了什么。您的模型不是一个值,而是一个指针,因此您不需要使用&
运算符获取它的地址。不要只是盲目地复制代码,试着去了解发生了什么,涉及的类型是什么,以及你的代码有什么不同。
我试过它返回“'key1
如果您要询问有关代码的问题,最好提供代码!代码按原样工作,无需更改。您可以从 github 下载该项目,在 Qt Creator 中打开它,然后运行它。如果你修改它并且它不再工作,你应该发布一个单独的问题。
我现在已经想出了如何实现它,尽管我废弃了它的 map 部分,而 data 方法完成了所有逻辑。谢谢。以上是关于Qt5 子类化 QStyledItemDelegate 格式的主要内容,如果未能解决你的问题,请参考以下文章