本小节属于《QTreeView使用代理实现表项编辑、定制显示控件》:系列教程之八的子章节。
由于本章节内容较多,放在一起可能大家看起来比较费劲,所以进行了拆分,大家可以从这里《QTreeView使用系列教程目录》找到其他的小节内容。
接下来开始讲解,QTreeView中嵌入QPushButton实现命令操作。
本小节比之前要稍微麻烦一些,之前我们都是嵌入的被动显示的控件,而QPushButton需要持久化存在。在显示的同时,还需要响应鼠标操作。但是跟双击启动一个Editor编辑数据不同,在同一时刻只会有一个Editor,QPushButton需要显示多个,持久化存在。
度娘到2个方案:
(1)重写paint()计算按钮位置,绘制按钮,然后重写editorEvent()处理鼠标消息,转化为按钮抬起信号。
参考《Qt 之模型/视图(自定义按钮)》
(2)使用网友造好的一个轮子,大概原理也是通过重写paint()来实现的,但是我们派生出来使用时,与继承QStyledItemDelegate区别不大。
参考《Model/View模块中Delegate的扩展:持久Delegate(一)》
这2个方案都能实现,具体怎么选择就看情况了。
下面以(2)方案为例进行说明:
PersistentStyledItemDelegate类为造好的轮子基类。我们派生出ButtonDelegate类。在createEditor()中,按照创建Editor并返回的思路,创建一个QWidget和QPushButton,然后把QPushButton布局在QWidget中,并返回QWidget,其间添加QPushButton信号通知出来,以便外部处理。
class ButtonDelegate : public PersistentStyledItemDelegate
{
Q_OBJECT
public:
ButtonDelegate(QObject *parent = nullptr)
: PersistentStyledItemDelegate(parent) { }
void setText(const QString &text) { _text = text; }
void setIcon(const QIcon &icon) { _icon = icon; }
signals:
void clicked(const QModelIndex& index);
public:
//因为按钮既不需要从model读取数据,也不需要写入,因此仅需要重写一个函数即可
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QPersistentModelIndex perIndex(index);
QWidget *widget = new QWidget(parent);
widget->setAutoFillBackground(true);
QHBoxLayout *layout = new QHBoxLayout();
layout->addStretch();
layout->setContentsMargins(2, 2, 2, 2);
QPushButton *btn = new QPushButton();
btn->setMinimumHeight(24);
btn->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
if (!_text.isEmpty()) btn->setText(_text);
if (!_icon.isNull()) btn->setIcon(_icon);
btn->setStyleSheet(BTN_QSS);
layout->addWidget(btn);
layout->addStretch();
widget->setLayout(layout);
QObject::connect(btn,&QPushButton::clicked,[=]{
QModelIndex tIndex = static_cast<QModelIndex>(perIndex);
//const成员里,不能修改对象,因此不能emit信号
auto temp = const_cast<ButtonDelegate *>(this);
emit temp->clicked(tIndex);
});
return widget;
}
private:
QString _text;
QIcon _icon;
const QString BTN_QSS = "QPushButton{"
"border-image: url(:/res/download_normal.png);"
"}"
"QPushButton::hover{"
"border-image: url(:/res/download_normal.png);"
"}"
"QPushButton::pressed{"
"border-image: url(:/res/download_press.png);"
"}";
};
给第7列指定委托,那么第7列使用QPushButton响应操作。
ButtonDelegate* button = new ButtonDelegate(ui->treeView);
connect(button, &ButtonDelegate::clicked, this, &MainWindow::onButtonClicked);
ui->treeView->setItemDelegateForColumn(7, button);
void MainWindow::onButtonClicked(const QModelIndex &index)
{
if(!index.isValid())
return;
QMessageBox::information(this, "提示", QString("点击(%1,%2)").arg(index.row()).arg(index.column()));
}
效果:
若对你有帮助,欢迎点赞、收藏、评论,你的支持就是我的最大动力!!!
同时,阿超为大家准备了丰富的学习资料,欢迎关注公众号“超哥学编程”,即可领取。
本文涉及工程代码,公众号回复:34EditorDelegate,即可下载。