Qt listView添加控件、图片
首先,先上效果图:
点击listView中的按钮,分别有:clicked row index = 0 和 clicked row index = 1 的打印,也就是说可以判断item中哪个按钮被按下。
怎么做?
第一步
当然是先创建一个widget的project,再往ui文件中拖入一个listView,
点击栅格布局,如图:
第二步
自定义一个委托类,这个类主要用来在listView中绘制自己想要的元素,看了效果图就知道,listView中主要是有按钮和文字这两个元素,那么我们只需要每一个item中绘制一个文本和一个按钮即可,看代码:
.h
#ifndef LISTVIEWDELEGATE_H
#define LISTVIEWDELEGATE_H
#include <QStyledItemDelegate>
#include <QPainter>
typedef struct {
//文字
QString titleText;
//开关状态
QString state;
//按钮
QWidget *widget;
} itemProperty;
Q_DECLARE_METATYPE(itemProperty)
class listViewDelegate : public QStyledItemDelegate
{
public:
explicit listViewDelegate(QObject *parent = nullptr);
void paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index)
const override;
QSize sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index)
const override;
};
#endif // LISTVIEWDELEGATE_H
.cpp
#include "listviewdelegate.h"
//按钮的高、宽以及坐标点
#define WIDGET_LEFT_MARGIN 270
#define WIDGET_TOP_MARGIN 20
#define WIDGET_WIDTH 80
#define WIDGET_HEIGHT 50
//每个item的高度
#define LISTVIEW_ITEM_HEIGHT 100
//分割item的线的颜色
#define LINE_COLOR "#CECECE"
//文字的颜色
#define TEXT_COLOR "#130c0e"
//文字的大小
#define TEXT_SIZE 15
listViewDelegate::listViewDelegate(QObject *parent) :
QStyledItemDelegate(parent) {
}
void listViewDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index)
const {
if (index.isValid()) {
QVariant dataVar = index.data(Qt::UserRole + 1);
itemProperty itemData = dataVar.value<itemProperty>();
painter->save();
//每个item的区域
QRectF rect;
rect.setX(option.rect.x());
rect.setY(option.rect.y());
rect.setWidth(option.rect.width() - 1);
rect.setHeight(option.rect.height() - 1);
//text的区域
QRect textRect = QRect(
0 + 10, rect.top() + WIDGET_TOP_MARGIN, 100, WIDGET_HEIGHT);
painter->setPen(QPen(TEXT_COLOR));
painter->setFont(QFont("SourceHanSansCN-Normal", TEXT_SIZE));
painter->drawText(textRect, itemData.titleText);
//widget的区域
QRect widgetRect = QRect(
WIDGET_LEFT_MARGIN, rect.top() + WIDGET_TOP_MARGIN, WIDGET_WIDTH, WIDGET_HEIGHT);
if (itemData.widget) {
itemData.widget->setGeometry(widgetRect);
itemData.widget->show();
}
//设置线的颜色
painter->setPen(QPen(QColor(LINE_COLOR)));
//两点确定一条直线
//线的起点:x一定是0,并且每一条线的x是一样的,y是每个item的顶部坐标 + 1
//线的终点:y一定是和起点的y是一样的,那么只需要给出x的长度,线的长度就是每个item的宽度
painter->drawLine(QPointF(0, rect.bottom() - 1), QPointF(rect.width(), rect.bottom() - 1));
}
painter->restore();
}
QSize listViewDelegate::sizeHint(
const QStyleOptionViewItem &option,
const QModelIndex &index)
const {
Q_UNUSED(index)
return QSize(option.rect.width(), LISTVIEW_ITEM_HEIGHT);
}
第三步
委托类已经写好了,剩下的就是主UI的逻辑部分了。在主UI的头文件中包含一下自定义的委托类:
#include "listviewdelegate.h"
刚才在委托类中定义了一个结构体,这个结构体就包含了我们所需要的所有元素了,那么在头文件中也要定义一个:
//因为一个listView一般不会只有一个item,
//一个结构体只对应一个item,
//很多个item就是很多的结构体,
//所以弄成一个list
QList<itemProperty> listItems;
//记得包含头文件
QStandardItemModel *listModel;
listViewDelegate *listItemDelegate;
最后,在主UI 的.cpp中
#define STYLE_OFF_STR "QPushButton{border-image: url(:/myIcon/switch/off-.png)};"
#define STYLE_ON_STR "QPushButton{border-image: url(:/myIcon/switch/on-.png)};"
构造函数中加入:
listModel = NULL;
listItemDelegate = NULL;
listItems = {
{"按钮0", NULL},
{"按钮1", NULL},
};
listModel = new QStandardItemModel(this);
for(int listRow=0; listRow<listItems.count(); listRow++) {
QStandardItem *pItem = new QStandardItem;
//定义一个按钮(可以根据需求不同定义不同的控件)
QPushButton *widget = new QPushButton("");
//设置按钮的属性,在这里设置了按钮的id,
//可以在槽函数中根据这个按钮的id区分出具体是哪一个按钮按下
widget->setProperty("BtnID", QString("%1").arg(listRow));
//设置父级
widget->setParent(ui->listView);
listItems[listRow].widget = widget;
//设置风格
widget->setStyleSheet(STYLE_OFF_STR);
//下一次开关状态
listItems[listRow].state = "1";
//关联槽函数,可以几个按钮关联同一个槽函数,
//在槽函数中根据BtnID区分出具体是哪一个按钮按下,再执行相应的代码
connect(widget, SIGNAL(clicked()), this, SLOT(slotListviewBtnCheckin()));
pItem->setData(QVariant::fromValue(listItems.at(listRow)), Qt::UserRole + 1);
listModel->appendRow(pItem);
}
listItemDelegate = new listViewDelegate(this);
ui->listView->setItemDelegate(listItemDelegate);
ui->listView->setModel(listModel);
connect(ui->listView, SIGNAL(clicked(QModelIndex)),
this, SLOT(slotlistViewForCheckin(QModelIndex)));
//禁止编辑
ui->listView->setEditTriggers(QAbstractItemView::NoEditTriggers);
/***************************按钮关联的槽函数************************************/
void listViewWidget::slotListviewBtnCheckin()
{
QPushButton *btn = dynamic_cast<QPushButton*> (sender());
if(btn != Q_NULLPTR) {
//取出按钮的id属性
int index = btn->property("BtnID").toInt();
switch(index) {
//根据BtnID不同,执行相应的代码
case 0:
break;
case 1:
break;
default:
break;
}
//按钮图片更新
if(listItems[index].state.compare("0") == 0) {
listItems[index].widget->setStyleSheet(STYLE_OFF_STR);
listItems[index].state = "1";
} else {
listItems[index].widget->setStyleSheet(STYLE_ON_STR);
listItems[index].state = "0";
}
qDebug() << "clicked row index = " << index;
}
}
点击运行:
Nice,歪瑞故德