Qt自定义列表项与QListWidget学习

Qt自定义列表项与QListWidget学习

1. 项目概述

本项目实现了一个模拟QQ群成员列表的界面,主要展示了如何使用Qt中的QListWidget控件结合自定义控件来创建复杂的列表项。项目的主要特点包括:

  • 使用QListWidget作为列表容器
  • 创建自定义的QQItem控件作为列表项
  • 使用Qt样式表(QSS)美化界面
  • 使用Qt资源系统管理图片资源

2. 项目结构

复制代码
42/
├── 42.pro           # 项目文件
├── main.cpp         # 主函数入口
├── widget.h         # 主窗口头文件
├── widget.cpp       # 主窗口实现
├── widget.ui        # 主窗口界面设计
├── qqitem.h         # 自定义列表项头文件
├── qqitem.cpp       # 自定义列表项实现
├── qqitem.ui        # 自定义列表项界面设计
├── res.qrc          # 资源文件
└── icons/           # 图标资源目录
    ├── icon0.jpg    # 头像图片
    ├── icon1.jpg    # 头像图片
    ├── icon2.jpg    # 头像图片
    ├── icon3.jpg    # 头像图片
    ├── phone.png    # 电话图标
    └── search.png   # 搜索图标

3. 主窗口设计

3.1 界面设计 (widget.ui)

主窗口界面使用Qt Designer设计,主要包含以下元素:

  • 一个标题标签,显示群成员数量信息
  • 一个搜索框,包含搜索图标按钮和文本输入框
  • 一个QListWidget控件,用于显示群成员列表

界面使用垂直布局(QVBoxLayout)组织这些元素,搜索框内部使用水平布局(QHBoxLayout)。

xml 复制代码
<!-- widget.ui 主要结构 -->
<layout class="QVBoxLayout" name="verticalLayout">
  <item>
    <widget class="QLabel" name="label">
      <!-- 标题标签属性设置 -->
    </widget>
  </item>
  <item>
    <layout class="QHBoxLayout" name="horizontalLayout">
      <item>
        <widget class="QPushButton" name="pushButton">
          <!-- 搜索按钮属性设置 -->
        </widget>
      </item>
      <item>
        <widget class="QLineEdit" name="lineEdit">
          <!-- 搜索输入框属性设置 -->
        </widget>
      </item>
    </layout>
  </item>
  <item>
    <widget class="QListWidget" name="listWidget">
      <!-- 列表控件属性设置 -->
    </widget>
  </item>
</layout>

3.2 样式设置

主窗口中使用了Qt样式表(QSS)来美化界面元素:

css 复制代码
/* 搜索按钮样式 */
QPushButton { border-image: url(:/icons/search.png) }

/* 搜索输入框样式 */
QLineEdit { background: transparent; border: none }

/* 列表项样式 */
QListWidget::item { height: 65px }
QListWidget::item:selected { background-color: rgb(200, 200, 200) }
QListWidget::item:hover { background-color: rgb(220, 220, 220) }

这些样式设置了:

  • 搜索按钮使用图片作为背景
  • 搜索输入框透明无边框
  • 列表项高度固定为65px
  • 列表项选中和悬停时的背景颜色

4. 自定义列表项设计

4.1 界面设计 (qqitem.ui)

自定义列表项使用Qt Designer设计,包含以下元素:

  • 一个头像图片标签(QLabel)
  • 一个电话图标标签(QLabel),可选显示
  • 一个名称标签(QLabel)

这些元素使用水平布局(QHBoxLayout)组织,并添加了适当的间距。

xml 复制代码
<!-- qqitem.ui 主要结构 -->
<layout class="QHBoxLayout" name="horizontalLayout">
  <item>
    <spacer name="horizontalSpacer">
      <!-- 左侧间距 -->
    </spacer>
  </item>
  <item>
    <widget class="QWidget" name="widget" native="true">
      <!-- 头像容器 -->
      <widget class="QLabel" name="icon">
        <!-- 头像标签属性设置 -->
      </widget>
      <widget class="QLabel" name="phone">
        <!-- 电话图标标签属性设置 -->
      </widget>
    </widget>
  </item>
  <item>
    <widget class="QLabel" name="name">
      <!-- 名称标签属性设置 -->
    </widget>
  </item>
  <item>
    <spacer name="horizontalSpacer_2">
      <!-- 右侧间距 -->
    </spacer>
  </item>
</layout>

4.2 样式设置

自定义列表项中也使用了Qt样式表(QSS)来美化界面元素:

css 复制代码
/* 头像容器样式 */
QWidget { background: transparent; border-radius: 10px }

/* 头像标签样式 */
QLabel { background-color: darkgray; border-radius: 10px }

/* 名称标签样式 */
QLabel { color: darkgray; font-size: 20px }

这些样式设置了:

  • 头像容器透明背景,圆角边框
  • 头像标签深灰色背景,圆角边框
  • 名称标签深灰色文字,20px字体大小

5. 代码实现

5.1 自定义列表项类 (QQItem)

5.1.1 类定义 (qqitem.h)
cpp 复制代码
#ifndef QQITEM_H
#define QQITEM_H

#include <QWidget>

namespace Ui {
class QQItem;
}

class QQItem : public QWidget
{
    Q_OBJECT

public:
    explicit QQItem(QString icon, bool flag, QString name, QWidget *parent = nullptr);
    ~QQItem();

private:
    Ui::QQItem *ui;
};

#endif // QQITEM_H

自定义列表项类继承自QWidget,构造函数接受三个参数:

  • icon:头像图片路径
  • flag:是否显示电话图标
  • name:成员名称
5.1.2 类实现 (qqitem.cpp)
cpp 复制代码
#include "qqitem.h"
#include "ui_qqitem.h"

QQItem::QQItem(QString icon, bool flag, QString name, QWidget *parent) :
    QWidget(parent),
    ui(new Ui::QQItem)
{
    ui->setupUi(this);
    QImage image(icon);
    ui->icon->setPixmap(QPixmap::fromImage(image.scaled(ui->icon->width(), ui->icon->height())));

    QImage image2(":/icons/phone.png");
    ui->phone->setPixmap(QPixmap::fromImage(image2.scaled(ui->phone->width(), ui->phone->height())));
    ui->phone->setVisible(flag);

    ui->name->setText(name);
}

QQItem::~QQItem()
{
    delete ui;
}

构造函数中的主要操作:

  1. 加载头像图片,并设置到icon标签
  2. 加载电话图标,并根据flag参数决定是否显示
  3. 设置成员名称到name标签

5.2 主窗口类 (Widget)

5.2.1 类定义 (widget.h)
cpp 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H
5.2.2 类实现 (widget.cpp)
cpp 复制代码
#include "widget.h"
#include "ui_widget.h"
#include "qqitem.h"

#include <QListWidgetItem>

class QQItem;

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setLayout(ui->verticalLayout);
    QQItem *qqItem = new QQItem(":/icons/icon1.jpg", true, "风子兰特");
    QQItem *qqItem1 = new QQItem(":/icons/icon0.jpg", false, "LIYOU");
    QQItem *qqItem2 = new QQItem(":/icons/icon2.jpg", false, "简单一点");
    QQItem *qqItem3 = new QQItem(":/icons/icon3.jpg", true, "Nov");

    QListWidgetItem *item0 = new QListWidgetItem;
    QListWidgetItem *item1 = new QListWidgetItem;
    QListWidgetItem *item2 = new QListWidgetItem;
    QListWidgetItem *item3 = new QListWidgetItem;

    ui->listWidget->addItem(item0);
    ui->listWidget->addItem(item1);
    ui->listWidget->addItem(item2);
    ui->listWidget->addItem(item3);

    ui->listWidget->setItemWidget(item0, qqItem);
    ui->listWidget->setItemWidget(item1, qqItem1);
    ui->listWidget->setItemWidget(item2, qqItem2);
    ui->listWidget->setItemWidget(item3, qqItem3);
}

Widget::~Widget()
{
    delete ui;
}

主窗口构造函数中的主要操作:

  1. 创建4个自定义列表项(QQItem),设置不同的头像、电话图标显示状态和名称
  2. 创建4个列表项(QListWidgetItem)
  3. 将列表项添加到列表控件(QListWidget)
  4. 将自定义列表项设置为列表项的控件

5.3 主函数 (main.cpp)

cpp 复制代码
#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

主函数创建并显示主窗口,然后进入应用程序事件循环。

6. 资源管理

6.1 资源文件 (res.qrc)

xml 复制代码
<RCC>
    <qresource prefix="/">
        <file>icons/icon0.jpg</file>
        <file>icons/icon1.jpg</file>
        <file>icons/icon2.jpg</file>
        <file>icons/icon3.jpg</file>
        <file>icons/phone.png</file>
        <file>icons/search.png</file>
    </qresource>
</RCC>

资源文件定义了项目中使用的图片资源,包括头像图片和图标。这些资源可以通过:/icons/xxx的路径在代码中访问。

7. QListWidget使用技巧

7.1 基本用法

cpp 复制代码
// 创建列表项
QListWidgetItem *item = new QListWidgetItem;

// 添加列表项到列表控件
listWidget->addItem(item);

// 设置列表项的文本
item->setText("列表项文本");

// 设置列表项的图标
item->setIcon(QIcon("图标路径"));

// 设置列表项的工具提示
item->setToolTip("工具提示文本");

// 设置列表项的数据
item->setData(Qt::UserRole, QVariant("自定义数据"));

7.2 自定义列表项

cpp 复制代码
// 创建自定义控件
MyCustomWidget *widget = new MyCustomWidget;

// 创建列表项
QListWidgetItem *item = new QListWidgetItem;

// 添加列表项到列表控件
listWidget->addItem(item);

// 设置列表项的大小
item->setSizeHint(widget->sizeHint());

// 将自定义控件设置为列表项的控件
listWidget->setItemWidget(item, widget);

7.3 样式设置

css 复制代码
/* 列表控件样式 */
QListWidget {
    background-color: white;
    border: 1px solid gray;
    outline: none; /* 去除焦点边框 */
}

/* 列表项样式 */
QListWidget::item {
    height: 50px; /* 固定高度 */
    padding: 5px; /* 内边距 */
    border-bottom: 1px solid lightgray; /* 底部边框 */
}

/* 选中列表项样式 */
QListWidget::item:selected {
    background-color: #e0e0e0; /* 选中背景色 */
    color: black; /* 选中文字颜色 */
}

/* 悬停列表项样式 */
QListWidget::item:hover {
    background-color: #f0f0f0; /* 悬停背景色 */
}

7.4 信号与槽

cpp 复制代码
// 连接列表项点击信号
connect(listWidget, &QListWidget::itemClicked, this, &MyClass::onItemClicked);

// 连接列表项双击信号
connect(listWidget, &QListWidget::itemDoubleClicked, this, &MyClass::onItemDoubleClicked);

// 连接当前项改变信号
connect(listWidget, &QListWidget::currentItemChanged, this, &MyClass::onCurrentItemChanged);

// 槽函数实现
void MyClass::onItemClicked(QListWidgetItem *item)
{
    // 处理列表项点击事件
    int row = listWidget->row(item); // 获取行号
    QString text = item->text(); // 获取文本
    QVariant data = item->data(Qt::UserRole); // 获取自定义数据
}

8. 实现自定义列表项的步骤

  1. 创建自定义控件类

    • 继承QWidget或其他适合的控件类
    • 设计控件的界面(使用Qt Designer或代码)
    • 实现必要的功能和交互
  2. 在主窗口中使用自定义列表项

    • 创建QListWidgetItem对象
    • 创建自定义控件对象
    • 将列表项添加到QListWidget
    • 使用setItemWidget将自定义控件设置为列表项的控件
  3. 设置样式和交互

    • 使用Qt样式表(QSS)美化界面
    • 实现必要的信号与槽连接
    • 处理用户交互事件

10. 扩展功能示例

10.1 添加搜索功能

cpp 复制代码
// 连接搜索输入框的文本变化信号
connect(ui->lineEdit, &QLineEdit::textChanged, this, &Widget::onSearchTextChanged);

// 搜索功能实现
void Widget::onSearchTextChanged(const QString &text)
{
    // 遍历所有列表项
    for (int i = 0; i < ui->listWidget->count(); ++i)
    {
        QListWidgetItem *item = ui->listWidget->item(i);
        QWidget *widget = ui->listWidget->itemWidget(item);
        QQItem *qqItem = qobject_cast<QQItem*>(widget);
        
        // 获取名称标签的文本(假设有getName方法)
        QString name = qqItem->getName();
        
        // 根据搜索文本显示或隐藏列表项
        if (text.isEmpty() || name.contains(text, Qt::CaseInsensitive))
        {
            item->setHidden(false);
        }
        else
        {
            item->setHidden(true);
        }
    }
}

10.2 添加右键菜单

cpp 复制代码
// 重写上下文菜单事件
void Widget::contextMenuEvent(QContextMenuEvent *event)
{
    QListWidgetItem *item = ui->listWidget->itemAt(ui->listWidget->mapFromGlobal(event->globalPos()));
    if (item)
    {
        QMenu menu(this);
        QAction *viewAction = menu.addAction("查看资料");
        QAction *chatAction = menu.addAction("发送消息");
        QAction *deleteAction = menu.addAction("删除好友");
        
        QAction *selectedAction = menu.exec(event->globalPos());
        if (selectedAction == viewAction)
        {
            // 查看资料
        }
        else if (selectedAction == chatAction)
        {
            // 发送消息
        }
        else if (selectedAction == deleteAction)
        {
            // 删除好友
            ui->listWidget->takeItem(ui->listWidget->row(item));
            delete item;
        }
    }
}

10.3 拖放排序

cpp 复制代码
// 在构造函数中启用拖放
ui->listWidget->setDragEnabled(true);
ui->listWidget->setDragDropMode(QAbstractItemView::InternalMove);
ui->listWidget->setDefaultDropAction(Qt::MoveAction);
相关推荐
歪歪1004 小时前
Qt Creator 打包应用程序时经常会遇到各种问题
开发语言·c++·qt·架构·编辑器
Yvonne爱编码4 小时前
零基础学习数据采集与监视控制系统SCADA
学习·信息可视化·信息与通信·数据可视化
PEI044 小时前
MVCC(多版本并发控制)
java·开发语言·数据库
熊猫钓鱼>_>4 小时前
2025反爬虫之战札记:从robots.txt到多层防御的攻防进化史
开发语言·c++·爬虫
肥肠可耐的西西公主4 小时前
后端(JDBC)学习笔记(CLASS 1):基础篇(一)
笔记·学习
牛十二5 小时前
mac-intel操作系统go-stock项目(股票分析工具)安装与配置指南
开发语言·前端·javascript
励志不掉头发的内向程序员5 小时前
从零开始的python学习——文件
开发语言·python·学习
恒森宇电子有限公司5 小时前
IP5326_BZ 支持C同口输入输出的移动电源芯片 2.4A的充放电电流 支持4LED指示灯
c语言·开发语言·单片机
曼巴UE55 小时前
UE5.3 C++ 接口初步使用
开发语言·jvm·c++