Qt listView添加控件、图片

本文介绍了如何在Qt中使用QListView结合自定义委托(QStyledItemDelegate)来实现列表项中包含按钮和文本的效果。通过创建一个委托类并重写paint和sizeHint方法,绘制出带有文本和按钮的列表项。同时,通过槽函数处理按钮点击事件,实现了按钮状态的切换。最终展示了一个功能完整的QtListView控件实例。
摘要由CSDN通过智能技术生成

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,歪瑞故德

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

__不高兴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值