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)。
<!-- 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)来美化界面元素:
/* 搜索按钮样式 */
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)组织,并添加了适当的间距。
<!-- 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)来美化界面元素:
/* 头像容器样式 */
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)
#ifndef QQITEM_H
#define QQITEM_H#include <QWidget>namespace Ui {
class QQItem;
}class QQItem : public QWidget
{Q_OBJECTpublic: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)
#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;
}
构造函数中的主要操作:
- 加载头像图片,并设置到icon标签
- 加载电话图标,并根据flag参数决定是否显示
- 设置成员名称到name标签
5.2 主窗口类 (Widget)
5.2.1 类定义 (widget.h)
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private:Ui::Widget *ui;
};
#endif // WIDGET_H
5.2.2 类实现 (widget.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;
}
主窗口构造函数中的主要操作:
- 创建4个自定义列表项(QQItem),设置不同的头像、电话图标显示状态和名称
- 创建4个列表项(QListWidgetItem)
- 将列表项添加到列表控件(QListWidget)
- 将自定义列表项设置为列表项的控件
5.3 主函数 (main.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)
<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 基本用法
// 创建列表项
QListWidgetItem *item = new QListWidgetItem;// 添加列表项到列表控件
listWidget->addItem(item);// 设置列表项的文本
item->setText("列表项文本");// 设置列表项的图标
item->setIcon(QIcon("图标路径"));// 设置列表项的工具提示
item->setToolTip("工具提示文本");// 设置列表项的数据
item->setData(Qt::UserRole, QVariant("自定义数据"));
7.2 自定义列表项
// 创建自定义控件
MyCustomWidget *widget = new MyCustomWidget;// 创建列表项
QListWidgetItem *item = new QListWidgetItem;// 添加列表项到列表控件
listWidget->addItem(item);// 设置列表项的大小
item->setSizeHint(widget->sizeHint());// 将自定义控件设置为列表项的控件
listWidget->setItemWidget(item, widget);
7.3 样式设置
/* 列表控件样式 */
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 信号与槽
// 连接列表项点击信号
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. 实现自定义列表项的步骤
-
创建自定义控件类
- 继承QWidget或其他适合的控件类
- 设计控件的界面(使用Qt Designer或代码)
- 实现必要的功能和交互
-
在主窗口中使用自定义列表项
- 创建QListWidgetItem对象
- 创建自定义控件对象
- 将列表项添加到QListWidget
- 使用setItemWidget将自定义控件设置为列表项的控件
-
设置样式和交互
- 使用Qt样式表(QSS)美化界面
- 实现必要的信号与槽连接
- 处理用户交互事件
10. 扩展功能示例
10.1 添加搜索功能
// 连接搜索输入框的文本变化信号
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 添加右键菜单
// 重写上下文菜单事件
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 拖放排序
// 在构造函数中启用拖放
ui->listWidget->setDragEnabled(true);
ui->listWidget->setDragDropMode(QAbstractItemView::InternalMove);
ui->listWidget->setDefaultDropAction(Qt::MoveAction);