QT框架笔记 VS上使用QT 环境搭建
C++实践之Qt学习(扩展):Visual Studio中Qt开发环境的搭建_visual studio 与 qt-CSDN博客
配置下32,64位的生成配置
【QT】visual studio QT 32位和64位生成配置_qt生成32位程序-CSDN博客
显示中文,防止乱码:
1 #pragma execution_character_set("utf-8" )
Qt 在跨平台开发中广泛支持 UTF-8 , 它告诉编译器将源代码中的字符串文字编码为 UTF-8,而不是默认的系统编码(例如GBK)。
关于父类的说明
QMainWindow
可以包含菜单栏、工具栏、状态栏、标题栏等,是最常见的窗口形式,可以作为桌面应用的主窗口
QWidget
是所有用户界面对象的基类,其他的窗口和控件都是直接或间接地集成自QWidget,一般创建桌面应用程序时需要创建一个窗口,此时选择QMainWindow或者QDialog即可,QMainWindow是主窗口,QDialog表示对话框。而如果不确定是否作为一个顶级窗口或者嵌入到其他窗口中,可以使用QWidget,同时它也是实现自定义部件的基类。
QDialog
表示对话框,主要用来进行短期交互,可以设置成模态的。一般没有菜单栏、工具栏、状态栏等。
QT信号与槽机制 简单介绍 在 Qt 框架中,信号和槽 (Signal and Slot)是一种用于对象之间通信的机制,尤其适用于事件驱动的 GUI 应用程序。信号和槽是 Qt 中的一种扩展机制,专门为简化和增强组件间的交互设计的。
信号 :类似于一种“广播”机制,表明发生了某些事件。信号本身不包含处理逻辑,只是单纯的事件通知。
槽 :槽函数用于接收信号,槽函数会定义如何处理事件。槽函数可以是任何可调用的成员函数。
类似于之前学过的MFC框架中的消息映射
QT中信号和槽的特点 (为什么信号和槽不写成统一的普通函数)
1. 松耦合(Loose Coupling)
信号和槽的机制通过解耦事件的发送者(信号)和接收者(槽)之间的关系,提供了松耦合的编程方式。松耦合是指发送信号的对象并不需要知道任何关于接收信号的对象(即槽)的细节,反之亦然。
传统的函数调用 :通常在 C++ 中,一个对象直接调用另一个对象的函数,这需要对象彼此了解,并且依赖于函数的实现。如果你想更改接收者对象或者函数的实现,必须更改调用者代码。这种方式很紧耦合,修改和维护变得困难。
信号与槽 :使用信号和槽机制时,发送信号的对象根本不需要知道谁在接收信号,它只是通过 emit
关键字发出信号。接收信号的槽函数可以在其他任何地方实现并连接到信号。这使得对象间的关系非常灵活,减少了代码之间的依赖。
2. 事件驱动机制
Qt 是一个事件驱动框架,这意味着程序的行为是由事件触发的,而不是由方法调用的。信号和槽机制就是实现事件驱动模型的核心之一。
传统的调用 :在传统 C++ 中,你通常会通过直接调用函数来触发某些行为,这种行为是同步的,即调用者必须等待返回。
信号和槽 :信号和槽机制允许事件的异步处理。例如,某个对象可以发出信号(事件),而不关心谁处理它,接收者(槽)可以在合适的时机处理这个信号,而不必与发送者直接交互。Qt 框架也支持这种信号异步传递的机制,可以在后台线程中处理信号,从而避免 UI 阻塞。
3. 自动连接机制
Qt 的信号和槽机制具有自动连接功能。通常,Qt 会根据信号和槽的名称、参数匹配情况,自动连接信号与槽。你无需手动管理函数指针或事件传递。
传统的函数指针或回调 :你需要显式地将回调函数与事件绑定。例如,在某些情况下,你可能需要手动管理一个函数指针或回调对象。这种方式不如信号和槽机制直观和灵活。
信号与槽的自动连接 :通过 QObject::connect
函数,信号和槽可以自动绑定。如果信号发射时参数类型与槽匹配,Qt 会自动调用相应的槽函数。你只需要专注于信号的触发和槽的实现,不必担心对象间如何互相调用。
4. 多个槽的连接(多重响应)
使用信号和槽机制,一个信号可以连接到多个槽函数,这意味着一个事件可以触发多个不同的行为。这种特性使得信号和槽非常适合多任务或并发编程。
传统的函数调用 :你只能调用一个函数。
信号与槽 :一个信号可以连接到多个槽,这使得你可以根据不同的需求实现不同的行为。例如,多个组件都可以监听同一个信号,而各自作出不同的反应。
5. 线程安全
Qt 的信号和槽机制本身设计时考虑了多线程环境,在多线程的情况下,信号和槽之间的调用是线程安全的。Qt 内部自动处理了信号和槽的线程间通信。
传统的线程通信 :在传统的 C++ 中,你需要使用显式的线程同步机制(如互斥锁、条件变量等)来保证线程安全。
信号与槽的线程安全 :Qt 会自动处理跨线程的信号和槽连接,例如在不同线程之间传递信号时,它会将信号的执行放到目标线程的事件队列中,这样即使在多线程环境下,信号与槽的通信也能保持安全。
6. 灵活性
信号和槽提供了非常灵活的方式来处理事件。你可以通过编程动态地添加和移除槽,甚至可以在运行时动态连接信号和槽。这种灵活性非常适用于复杂的 GUI 应用程序或需要高度自定义行为的程序。
传统的函数调用 :通常是固定的,函数调用的绑定在编译时就已经确定了,缺乏动态调整的能力。
信号和槽 :通过 QObject::connect
和 QObject::disconnect
,你可以在运行时灵活地连接和断开信号与槽的关系,极大地增加了代码的灵活性和扩展性。
参数类型、参数数量和顺序都一致 那么信号和槽就会匹配。
QObject::connect() 在 Qt 中,信号和槽是通过 QObject::connect()
函数连接的:
1 2 3 4 5 6 7 QObject::connect ( const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction slot, Qt::ConnectionType type = Qt::AutoConnection );
sender
(发送者对象指针)
const QObject *sender
:表示信号的发送者对象,即哪个对象发出信号。
一般是类的对象指针,如 &myButton
或 this
。
signal
(信号函数指针)
PointerToMemberFunction signal
:这是指向信号函数的成员函数指针,指定要发出的信号。
格式是 &ClassName::signalName
,需要明确指出信号所在类的作用域。
示例 :&QPushButton::clicked
表示 QPushButton
类中的 clicked()
信号。
receiver
(接收者对象指针)
const QObject *receiver
:表示信号的接收者对象,即哪个对象接收信号并执行相应槽函数。
一般是类的对象指针,比如 &obj
或 this
。
slot
(槽函数指针)
PointerToMemberFunction slot
:这是指向槽函数的成员函数指针,表示当信号触发时要调用的槽函数。
格式是 &ClassName::slotName
,也需要明确槽所在类的作用域。
示例 :&MyClass::onButtonClicked
表示 MyClass
类中的 onButtonClicked()
槽函数。
**type
**(连接类型,可选参数)
函数返回值
返回一个 QMetaObject::Connection
类型的值,用于断开连接。如果连接成功,返回一个有效的连接对象;如果连接失败(例如信号与槽的参数不匹配),则返回一个无效的连接。
代码示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 #pragma once #pragma execution_character_set("utf-8" ) #include <QtWidgets/QMainWindow> #include "ui_Calculate_Volume.h" #include <QMainWindow> #include <QLabel> #include <QPushButton> #include <QLineEdit> #include <QVBoxLayout> #include <QHBoxLayout> #include <QString> #include <cmath> #include <windows.h> #include <QMessageBox> #define M_PI 3.1415926535 class Calculate_Volume : public QMainWindow{ Q_OBJECT public : Calculate_Volume (QWidget *parent = nullptr ); ~Calculate_Volume (); private : Ui::Calculate_VolumeClass ui; QLabel* label; QLineEdit* radiusInput; QLineEdit* volumeOutput; QPushButton* calculateButton; public slots: void onButtonClicked () { bool ok; double radius = radiusInput->text ().toDouble (&ok); if (!ok || radius <= 0 ) { QMessageBox::warning (this , "输入错误" , "请输入一个有效的正数作为半径!" ); return ; } double volume = (4.0 / 3.0 ) * M_PI * std::pow (radius, 3 ); volumeOutput->setText (QString::number (volume)); } };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 #include "Calculate_Volume.h" #include <QVBoxLayout> #include <QDebug> Calculate_Volume::Calculate_Volume (QWidget* parent) : QMainWindow (parent), label (new QLabel ("请输入球的半径:" , this )), radiusInput (new QLineEdit (this )), volumeOutput (new QLineEdit (this )), calculateButton (new QPushButton ("计算体积" , this )) { ui.setupUi (this ); volumeOutput->setReadOnly (true ); QVBoxLayout* mainLayout = new QVBoxLayout; QHBoxLayout* firstRowLayout = new QHBoxLayout; QHBoxLayout* secondRowLayout = new QHBoxLayout; firstRowLayout->addWidget (label); firstRowLayout->addWidget (radiusInput); secondRowLayout->addWidget (volumeOutput); secondRowLayout->addWidget (calculateButton); mainLayout->addLayout (firstRowLayout); mainLayout->addLayout (secondRowLayout); QWidget* centralWidget = new QWidget (this ); centralWidget->setLayout (mainLayout); setCentralWidget (centralWidget); connect (calculateButton, &QPushButton::clicked, this , &Calculate_Volume::onButtonClicked); } Calculate_Volume::~Calculate_Volume () {} #include "Calculate_Volume.h" #include <QtWidgets/QApplication> int main (int argc, char *argv[]) { QApplication a (argc, argv) ; Calculate_Volume w; w.show (); return a.exec (); }
效果展示:
一些Qt的方法类 QString类: QString
是 Qt 中用于处理字符串的类,提供了丰富的字符串操作功能。以下是 QString
中一些常用的方法:
基础操作
QString::isEmpty()
检查字符串是否为空,返回 true
表示为空。
QString::isNull()
检查字符串是否为 null
,与 isEmpty()
不同的是,null
的字符串没有分配任何内存,而空字符串分配了内存但没有内容。
QString::length()
或 QString::size()
返回字符串的长度(字符个数)。
QString::clear()
清空字符串内容。
字符串拼接
QString::append(const QString &str)
在字符串末尾追加另一个字符串。
operator+
使用 +
操作符拼接两个字符串。例如:str1 + str2
。
查找与替换
QString::contains(const QString &str)
检查字符串是否包含指定子串,返回布尔值。
QString::indexOf(const QString &str)
返回子串首次出现的位置,如果未找到返回 -1
。
QString::lastIndexOf(const QString &str)
返回子串最后一次出现的位置。
QString::replace(const QString &before, const QString &after)
将指定子串替换为另一个字符串。
大小写转换
QString::toLower()
将字符串转换为小写。
QString::toUpper()
将字符串转换为大写。
子串与截取
QString::left(int n)
返回字符串左边的 n
个字符。
QString::right(int n)
返回字符串右边的 n
个字符。
QString::mid(int position, int n = -1)
从指定位置开始,提取 n
个字符的子串,若 n
为 -1
则提取到字符串末尾。
格式化输出
转换与编码
QString::toStdString()
将 QString
转换为标准 C++ 字符串 std::string
。
QString::toUtf8()
将 QString
转换为 QByteArray
,编码为 UTF-8。
QString::fromUtf8(const char \*str)
将 UTF-8 编码的 char
数组转换为 QString
。
QString::fromStdString(const std::string &str)
将标准 C++ 字符串转换为 QString
。
去空格
QString::trimmed()
去除字符串两端的空格字符。
QString::simplified()
去除字符串开头和结尾的空格,并将连续空格缩减为单个空格。
分割与连接
QString::split(const QString &sep)
按照指定分隔符将字符串分割成一个字符串列表,返回 QStringList
。
QStringList::join(const QString &sep)
将 QStringList
中的元素用指定字符串 sep
拼接成一个 QString
。
1 2 3 4 5 6 QString str = " Hello World! " ; qDebug () << str.trimmed (); qDebug () << str.toLower (); qDebug () << str.mid (2 , 5 ); qDebug () << str.contains ("World" ); qDebug () << str.replace ("World" , "Qt" );
总之,要用查AI就行,没必要细究
QMap,QHash,QVector类 QMap
和 QHash
是 Qt 中的键值对容器类,类似于标准库中的 std::map
和 std::unordered_map
,它们用于存储键值对并支持快速查找。
QMap
定义 :QMap
是一个基于二叉树实现的键值对容器,键值对按键自动排序。
特点 :查找、插入、删除操作的时间复杂度为 O(logn)
适用场景 :适合需要按顺序遍历键值对,或对键进行排序的场景。
常用方法
**insert(key, value)
**:插入键值对。
**value(key)
**:通过键查找值。
**contains(key)
**:检查键是否存在。
**remove(key)
**:移除指定键的键值对。
keys()
和 **values()
**:分别获取所有键和所有值的列表
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <QMap> #include <QDebug> void exampleQMap () { QMap<QString, int > map; map.insert ("Alice" , 25 ); map.insert ("Charlie" , 28 ); map.insert ("Bob" , 30 ); qDebug () << "Keys in sorted order:" ; for (auto it = map.begin (); it != map.end (); ++it) { qDebug () << it.key () << ":" << it.value (); } if (map.contains ("Alice" )) { qDebug () << "Alice's age:" << map.value ("Alice" ); } }
在 QMap
中,键 会自动按字典序(或称为”字母顺序”)排序,这种排序是基于键的自然顺序实现的。也就是说,当插入键值对时,QMap
会自动将键按顺序排列,而不考虑插入顺序。
QHash
定义 :QHash
是一个基于哈希表实现的键值对容器,键值对的顺序不固定。
特点 :查找、插入、删除的平均时间复杂度为 O(1)O(1)O(1),速度通常快于 QMap
。
适用场景 :适合需要快速查找、插入和删除键值对,但不需要顺序或排序的场景。
常用方法
**insert(key, value)
**:插入键值对。
**value(key)
**:通过键查找值。
**contains(key)
**:检查键是否存在。
**remove(key)
**:移除指定键的键值对。
keys()
和 **values()
**:分别获取所有键和所有值的列表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <QHash> #include <QDebug> void exampleQHash () { QHash<QString, int > hash; hash.insert ("Alice" , 25 ); hash.insert ("Charlie" , 28 ); hash.insert ("Bob" , 30 ); qDebug () << "Keys in arbitrary order:" ; for (auto it = hash.begin (); it != hash.end (); ++it) { qDebug () << it.key () << ":" << it.value (); } if (hash.contains ("Bob" )) { qDebug () << "Bob's age:" << hash.value ("Bob" ); } }
此时就是没有顺序了
QMap vs QHash
顺序 :QMap
自动排序键,QHash
没有顺序。
性能 :QMap
的查找速度较 QHash
慢,但在需要排序时是理想选择。QHash
在查找、插入和删除方面更快。
选择建议
QMap :需要排序或按顺序遍历键值对时。
QHash :仅需快速查找时,且不关心键的顺序时。
QVector
QVector
(Qt库的Vector
类) 和C++标准库里面的Vector
类很相近
常用的方法有
1. append
和 prepend
append
用于在向量末尾追加元素。
prepend
用于在向量头部添加元素。
2. at
和 operator[]
at
用于访问指定索引的元素,带边界检查。
operator[]
直接访问元素,不检查越界。
3. size
和 isEmpty
size
返回元素数量。
isEmpty
判断是否为空。
4. insert
和 remove
insert
在指定位置插入元素。
remove
删除指定位置的元素。
5. contains
和 indexOf
contains
判断是否包含某个值。
indexOf
查找元素的索引,未找到返回-1。
6. fill
和 resize
fill
用指定值填充整个向量。
resize
调整向量大小,可能会丢失或补充数据。
7. toList
和 fromList
toList
转换为 QList
。
fromList
将 QList
转换为 QVector
。
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <QVector> #include <QDebug> int main () { QVector<int > vec; vec.append (10 ); vec.append (20 ); vec.prepend (5 ); qDebug () << "First element:" << vec.at (0 ); qDebug () << "Second element:" << vec[1 ]; qDebug () << "Vector size:" << vec.size (); if (vec.contains (20 )) { qDebug () << "Contains 20 at index:" << vec.indexOf (20 ); } vec.insert (1 , 15 ); vec.remove (2 ); vec.resize (5 ); QList<int > list = vec.toList (); for (int i : vec) { qDebug () << i; } return 0 ; }
QList和QLinkedList类 在 Qt 中,QList
和 QLinkedList
是两种常用的容器类,分别适用于不同的使用场景。它们都是存储一组元素的线性容器,但在内存布局和性能上有所区别。
QList
QList
存储结构体时,会选择存储指向结构体的指针,以减少内存开销,尤其是在隐式共享(copy-on-write)机制下,不同的 QList
可以共享结构体数据。然而,在 插入 和 删除 操作时,它的效率相对较低
常用方法
append(const T &value)
: 在列表末尾添加元素。
prepend(const T &value)
: 在列表开头添加元素。
insert(int index, const T &value)
: 在指定索引位置插入元素。
removeAt(int index)
: 删除指定索引的元素。
at(int index)
: 获取指定索引处的元素(只读)。
contains(const T &value)
: 检查列表中是否包含某个元素。
size()
: 返回列表中的元素数量。
isEmpty()
: 检查列表是否为空。
clear()
: 清空列表中的所有元素。
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <QList> #include <QDebug> int main () { QList<int > list; list.append (10 ); list.append (20 ); list.prepend (5 ); qDebug () << "List elements:" ; for (int i = 0 ; i < list.size (); ++i) { qDebug () << list.at (i); } if (list.contains (10 )) { qDebug () << "List contains 10." ; } list.removeAt (1 ); qDebug () << "After removing element at index 1:" ; for (int val : list) { qDebug () << val; } return 0 ; }
QLinkedList
QLinkedList
是基于链表实现的容器类,适合需要频繁在列表头部或中间插入或删除元素的场景。由于链表不支持随机访问,因此获取指定位置的元素会比较慢。
常用方法
append(const T &value)
: 在链表末尾添加元素。
prepend(const T &value)
: 在链表开头添加元素。
insert(iterator pos, const T &value)
: 在指定位置的迭代器处插入元素。
removeFirst()
: 删除第一个元素。
removeLast()
: 删除最后一个元素。
size()
: 返回链表中的元素数量。
isEmpty()
: 检查链表是否为空。
clear()
: 清空链表中的所有元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <QLinkedList> #include <QDebug> int main () { QLinkedList<int > linkedList; linkedList.append (10 ); linkedList.append (20 ); linkedList.prepend (5 ); qDebug () << "LinkedList elements:" ; for (int val : linkedList) { qDebug () << val; } linkedList.removeFirst (); qDebug () << "After removing the first element:" ; for (int val : linkedList) { qDebug () << val; } return 0 ; }
使用场景总结
QList :适用于需要频繁访问元素的场景,且数据的增删操作主要集中在末尾。
QLinkedList :适用于需要频繁在头部或中间插入或删除元素的场景。
QMap :适合需要按顺序存储键值对,或在键的基础上进行排序的场景。
QHash :适合不关心元素顺序且需要快速查找的场景。
如果你存储的是结构体对象,并且这些结构体通常很大,那么 QList
存储结构体时的内存占用相对 QVector
更小 ,毕竟QList存的是指针
QVariant类 QVariant
是 Qt 中一个非常重要的类,它是一个通用容器 ,能够存储多种类型的数据。QVariant
可以用来在不同类型之间进行转换,尤其在 Qt 中的数据模型和视图类(如 QTableView
, QListView
)中非常常见。它提供了一种标准化的方式来存储不同类型的数据,同时也支持类型安全的类型转换。
在 Qt 中,QVariant
常用于存储如字符串、数字、日期、时间等多种不同类型的数据,并且支持这些数据类型之间的互相转换。
方法介绍:
1. 构造函数
QVariant()
:创建一个空的 QVariant
。
QVariant(int)
、QVariant(double)
等:直接用基本数据类型来构造 QVariant
。
1 2 3 4 QVariant intVariant (42 ) ; QVariant doubleVariant (3.14 ) ; QVariant stringVariant ("Hello" ) ; QVariant emptyVariant;
2. isValid()
判断 QVariant
是否包含有效数据。
1 2 3 4 5 QVariant v; qDebug () << v.isValid (); v = 100 ; qDebug () << v.isValid ();
3. isNull()
检查 QVariant
是否为空(空指针或未初始化的值)。
1 2 3 4 5 QVariant nullVariant; qDebug () << nullVariant.isNull (); QVariant intVariant (10 ) ;qDebug () << intVariant.isNull ();
4. clear()
清除 QVariant
的值,使其变成空。
1 2 3 4 QVariant v (123 ) ;qDebug () << v; v.clear (); qDebug () << v.isNull ();
5. typeName()
返回 QVariant
中存储数据的类型名称。
1 2 3 4 5 cpp复制代码QVariant intVariant (42 ) ; qDebug () << intVariant.typeName (); QVariant stringVariant ("Hello" ) ;qDebug () << stringVariant.typeName ();
6. canConvert()
检查 QVariant
是否可以转换为指定类型。
1 2 3 QVariant v (42 ) ;qDebug () << v.canConvert <QString>(); qDebug () << v.canConvert <QDate>();
7. convert()
将 QVariant
转换为指定类型,如果转换成功则返回 true
。
1 2 3 QVariant v (42 ) ;v.convert (QVariant::String); qDebug () << v;
8. toInt()、toDouble()、toString() 等
将 QVariant
转换为不同的数据类型。常用的转换方法包括 toInt()
、toDouble()
、toString()
、toBool()
等。
1 2 3 4 5 6 7 8 9 QVariant v ("123" ) ;int intValue = v.toInt (); double doubleValue = v.toDouble (); QString stringValue = v.toString (); qDebug () << intValue; qDebug () << doubleValue; qDebug () << stringValue;
9. setValue()
使用模板方法存储任意类型的数据。
1 2 3 QVariant v; v.setValue <QString>("Hello" ); qDebug () << v.toString ();
10. value()
从 QVariant
中提取特定类型的数据。这个方法使用模板类型 T
来指定需要提取的类型。
1 2 3 QVariant v = QVariant::fromValue (3.14 ); double d = v.value <double >(); qDebug () << d;
11. fromValue()
静态模板方法,用于将任意类型的数据转换为 QVariant
。
1 2 QVariant variant = QVariant::fromValue <QString>("Hello World" ); qDebug () << variant.toString ();
12. type()
返回 QVariant::Type
类型的枚举值,表示当前存储的数据类型。
1 2 3 4 QVariant v (100 ) ;if (v.type () == QVariant::Int) { qDebug () << "It's an int" ; }
13. isDetached()
判断 QVariant
是否已从其共享数据中分离(浅拷贝时用于检测)。
1 2 3 4 5 6 QVariant v (42 ) ;QVariant vCopy = v; qDebug () << v.isDetached (); v = 100 ; qDebug () << v.isDetached ();
14. swap()
交换两个 QVariant
的值。
1 2 3 4 5 6 QVariant v1 (42 ) ;QVariant v2 ("Hello" ) ;v1.swap (v2); qDebug () << v1.toString (); qDebug () << v2.toInt ();
使用代码例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 #include <QtCore/QCoreApplication> #include <QVariant> #include <QDebug> #include <QMap> struct Student { int iNo; QString strName; int score; }; Q_DECLARE_METATYPE (Student);int main (int argc, char *argv[]) { QCoreApplication a (argc, argv) ; QVariant qv1 (298 ) ; qDebug () << "qv1" << qv1.toInt () << endl; QVariant qv2 ("this is string" ) ; qDebug () << "qv2" << qv2.toString () << endl; QMap<QString, QVariant> qmap; qmap["int" ] = 2000 ; qmap["double" ] = 2000.0 ; qmap["string" ] = "20000" ; qDebug () << qmap["int" ] << qmap["int" ].toInt (); qDebug () << qmap["double" ] << qmap["double" ].toInt (); qDebug () << qmap["string" ] << qmap["string" ].toString (); qDebug () << endl; QStringList qsl; qsl << "A" << "B" << "C" << "D" << "E" << "F" << "G" ; QVariant qvsl (qsl) ; if (qvsl.type () == QVariant::StringList) { QStringList qlist = qvsl.toStringList (); for (int i = 0 ; i < qlist.size (); i++) { qDebug () << qlist.at (i); } } qDebug () << endl; Student stu; stu.iNo = 202201 ; stu.score = 715 ; stu.strName = "sunny" ; QVariant Qvstu = QVariant::fromValue (stu); if (Qvstu.canConvert <Student>()) { Student temp_stu = Qvstu.value <Student>(); Student qtemp = qvariant_cast <Student>(Qvstu); qDebug () << temp_stu.iNo << temp_stu.score << temp_stu.strName; qDebug () << qtemp.iNo << qtemp.score << qtemp.strName; } system ("pause" ); return a.exec (); }
运行结果:
QT开发常见控件 Layouts&Spacers 手动操作 首先我们创建一个Qt Widgets Application
(qt窗体程序)
进来之后,解决方案资源管理器有一个ui文件
双击这个.ui文件,即可进入Qt的设计板块
其中,这里有Layouts(布局)和Spacers(间隔)
Vertical Layout 垂直布局
Horizontal Layout 横向(水平)布局
Grid Layout 网格(栅格)布局
Form Layout 表单布局
Horizontal Spacer 水平弹簧
Vertical Spacer 垂直弹簧
菜单栏有布局的快捷键:
例如下图显示的垂直布局
先选中这三个控件,然后点击一下垂直布局
就会自动帮我们布局
包含对象都垂直排列开
Horizontal Layout 横向(水平)布局
包含的对象都横向排列开
将控件放置到网格中布局,它本身会从父窗口或父布局中占据尽可能多的界面空间,然后把自己的空间划分为行和列,再把每个控件塞到设置好的一个或多个单元格中。通常情况下 QGridLayout不需要自己添加空白条 QSpacerltem,因为其他功能控件把各自的单元格占据之后,剩下没控件占据的单元格自然就是空的,空的格子默认里面什么都没有,也没有空白条。
专门用于管理输入控件和与之相关的标签等表单布局,QFormLavout固定为两列布局,并针对表单做了建模,配套了一堆方便使用的函数。网格布局器的基本单元是单元格,而表单布局器的基本单元是行。表单布局器是高度建模并封装的,它没有 addWidget0和 addLavout0)之类的函数,它只有addRow()函数。表单布局器中一行的空间可以由多个控件占据,也可以由一个控件占据。
弹簧:
Horizontal Spacer 水平弹簧
Vertical Spacer 垂直弹簧
用于在布局中创建灵活的空白空间。弹簧的主要作用是控制控件之间的间距,提供空间的拉伸或压缩效果,以实现布局中的自适应。
在Qt中,给控件设置布局和给顶层窗口设置布局是两个不同层次的事情,目的是为了实现自适应布局效果和确保整个界面按期望排布。
顶层窗口(如QMainWindow
或QWidget
)需要有一个布局来管理其内部的控件或子布局。如果不为顶层窗口设置布局,虽然可以在其中手动放置控件,但它们不会自动调整位置和大小,不具备自适应能力。
为顶层窗口设置布局后,Qt会自动管理窗口内部的空间分配,确保在窗口大小变化时,布局中的控件能够合理调整,达到更好的用户体验。
就像这样,这样是没有设置顶层布局,即使运行起来了,弹簧也不会起作用
所以我们要在空白处右键,点击布局,选择一个布局,例如这里选择了栅格布局,ctrl+s保存之后,运行,这时候弹簧就可以进行伸缩了
代码实现: 栅格布局:
我们先实现往栅格布局上面放一个按钮,注释都标注好了
1 2 3 4 5 6 7 8 9 10 11 12 13 Grid_Layout::Grid_Layout (QWidget *parent) : QWidget (parent) { ui.setupUi (this ); button1 = new QPushButton (this ); button1->setText ("第一区:顶不菜单栏选项" ); button1->setFixedHeight (40 ); button1->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding); pGrid_layouts = new QGridLayout (); pGrid_layouts->setContentsMargins (0 , 0 , 0 , 0 ); pGrid_layouts->addWidget (button1, 0 , 0 ); setLayout (pGrid_layouts); }
以上代码有一些疑问:
1.固定高度和 Expanding
尺寸策略的
固定高度优先于 Expanding
,导致按钮高度固定,只有水平方向会尝试扩展。所以这两者并不冲突,固定高度在垂直方向优先,Expanding
只在水平方向有效。
2. 网格布局的行列数
QGridLayout
的行列数是动态的,由添加的控件位置决定。
行列数是根据 addWidget
方法中给出的行和列参数动态生成的。没有预先设置网格大小,布局会根据所添加的控件自动计算需要的行和列数。
例如
1 2 3 pGrid_layouts->addWidget (button1, 0 , 1 ); pGrid_layouts->addWidget (button2, 1 , 0 ); pGrid_layouts->addWidget (button3, 1 , 1 );
pGrid_layouts
会自动创建一个 2 行 × 2 列的网格布局。
再介绍下addWidget
指定控件的对齐方式和弹性策略:
1 2 3 4 5 6 7 addWidget ( QWidget *widget, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment, QSizePolicy::Policy horizontalPolicy, QSizePolicy::Policy verticalPolicy )
参数 :
widget
:要添加的控件。
row
:控件所在的起始行。
column
:控件所在的起始列。
rowSpan
:控件跨越的行数。
columnSpan
:控件跨越的列数。
alignment
:控件的对齐方式(如 Qt::AlignCenter
、Qt::AlignLeft
)。
horizontalPolicy
:控件在水平方向上的尺寸策略(如 QSizePolicy::Expanding
,表示水平方向上可以扩展)。
verticalPolicy
:控件在垂直方向上的尺寸策略(如 QSizePolicy::Fixed
,表示垂直方向上的尺寸固定)。
作用 :允许更精确地控制控件的对齐方式和尺寸策略。尺寸策略用于指定控件如何在布局中调整自己的大小。
表单布局
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 Form_Layout::Form_Layout (QWidget *parent) : QWidget (parent) { ui.setupUi (this ); QFormLayout* qLayout = new QFormLayout (this ); le1 = new QLineEdit (); le2 = new QLineEdit (); le3 = new QLineEdit (); qLayout->addRow ("学号" , le1); qLayout->addRow ("姓名" , le2); qLayout->addRow ("学校" , le3); qLayout->setSpacing (8 ); qLayout->setRowWrapPolicy (QFormLayout::WrapAllRows); qLayout->setLabelAlignment (Qt::AlignLeft); setWindowTitle ("表单布局测试案例" ); setLayout (qLayout); }
其中
QFormLayout::setRowWrapPolicy
方法用于设置行的换行策略,即当空间不足以显示一行时,控件在布局中的排列方式。
1 void QFormLayout::setRowWrapPolicy (QFormLayout::RowWrapPolicy policy) ;
参数:RowWrapPolicy
RowWrapPolicy
是一个枚举类型,提供了三种策略:
**QFormLayout::DontWrapRows
**:不换行。当空间不足时,控件会被截断,但不会自动换行。
**QFormLayout::WrapLongRows
**:仅在行的内容过长时换行。此策略在行内容(标签和控件)超过窗口宽度时,才会将控件换到下一行。
**QFormLayout::WrapAllRows
**:总是换行。标签在一行,控件自动放置在下一行,形成两行布局(标签一行,控件一行)。
setLabelAlignment
用于设置标签的对齐方式,即标签在控件旁边的布局位置(如左对齐或右对齐)。
方法定义
1 void QFormLayout::setLabelAlignment (Qt::Alignment alignment) ;
参数 :
alignment
使用 Qt::Alignment
枚举类进行设置。常用的值包括:
**Qt::AlignLeft
**:左对齐标签。
**Qt::AlignRight
**:右对齐标签,常用于在窗口宽度较大时使标签在布局中右对齐。
**Qt::AlignHCenter
**:水平居中对齐标签。
**Qt::AlignJustify
**:标签的对齐方式为两端对齐。
控件介绍 Push Button (QPushButton)
这是最常见的按钮,用于触发简单的命令或操作,比如“确定”或“取消”。
Tool Button (QToolButton)
通常用于工具栏或小型控件,可以显示一个图标(或者文本)并触发特定的操作。
Radio Button (QRadioButton)
用于创建一组互斥的选项(只能选择一个)。
Check Box (QCheckBox)
允许用户选择多个选项或一个布尔值。
Command Link Button (QCommandLinkButton)
这是一个扩展了 QPushButton
的按钮,通常用于对话框中提供详细的操作说明。
Dialog Button Box (QDialogButtonBox)
功能 : 用于对话框中管理多个标准按钮(如“确定”、“取消”等)。特点 :
提供了标准按钮(如 QDialogButtonBox::Ok
)。
布局自动调整,不需要手动管理按钮的位置。
方便处理对话框的信号和槽。
代码示例 做一个按钮的集合,并结合上一期学到的布局
头文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #pragma once #include <QMainWindow> #include <QPushButton> #include <QToolButton> #include <QRadioButton> #include <QCheckBox> #include <QCommandLinkButton> #include <QDialogButtonBox> #include <QVBoxLayout> #include <QHBoxLayout> #include <QtWidgets/QMainWindow> #include "ui_Button.h" class Button : public QMainWindow{ Q_OBJECT public : Button (QWidget *parent = nullptr ); ~Button (); private : Ui::ButtonClass ui; private : QPushButton* pb1; QToolButton* tb1; QRadioButton* rb1; QRadioButton* rb2; QCheckBox* cb1; QCheckBox* cb2; QCommandLinkButton* clb1; QDialogButtonBox* dbb1; private slots: void pushbutton_clicked () ; void toolbutton_clicked () ; void radiobutton1_clicked () ; void radiobutton2_clicked () ; void checkbox1_clicked () ; void checkbox2_clicked () ; void commandlinkbutton_clicked () ; void dialogbuttonbox_clicked (QAbstractButton* button) ; };
cpp文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 #include "Button.h" #include <QDebug> Button::Button (QWidget *parent) : QMainWindow (parent) { ui.setupUi (this ); QWidget* centralWidget = new QWidget (this ); setCentralWidget (centralWidget); QVBoxLayout* mainLayout = new QVBoxLayout (); pb1 = new QPushButton ("Push Button" , this ); mainLayout->addWidget (pb1); tb1 = new QToolButton (this ); tb1->setText ("Tool Button" ); tb1->setIcon (QIcon (":/icons/tool.png" )); tb1->setToolButtonStyle (Qt::ToolButtonTextUnderIcon); mainLayout->addWidget (tb1); rb1 = new QRadioButton ("Radio Button 1" , this ); rb2 = new QRadioButton ("Radio Button 2" , this ); QHBoxLayout* radioLayout = new QHBoxLayout (); radioLayout->addWidget (rb1); radioLayout->addWidget (rb2); mainLayout->addLayout (radioLayout); cb1 = new QCheckBox ("Check Box 1" , this ); cb2 = new QCheckBox ("Check Box 2" , this ); QHBoxLayout* checkBoxLayout = new QHBoxLayout (); checkBoxLayout->addWidget (cb1); checkBoxLayout->addWidget (cb2); mainLayout->addLayout (checkBoxLayout); clb1 = new QCommandLinkButton ("Command Link Button" , "Description goes here" , this ); clb1->setIcon (QIcon (":/icons/info.png" )); mainLayout->addWidget (clb1); dbb1 = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this ); mainLayout->addWidget (dbb1); centralWidget->setLayout (mainLayout); setWindowTitle ("Qt Button Controls Example" ); resize (400 , 300 ); connect (pb1, &QPushButton::clicked, this , &Button::pushbutton_clicked); connect (tb1, &QToolButton::clicked, this , &Button::toolbutton_clicked); connect (rb1, &QRadioButton::clicked, this , &Button::radiobutton1_clicked); connect (rb2, &QRadioButton::clicked, this , &Button::radiobutton2_clicked); connect (cb1, &QCheckBox::clicked, this , &Button::checkbox1_clicked); connect (cb2, &QCheckBox::clicked, this , &Button::checkbox2_clicked); connect (clb1, &QCommandLinkButton::clicked, this , &Button::commandlinkbutton_clicked); connect (dbb1, &QDialogButtonBox::clicked, this , &Button::dialogbuttonbox_clicked); } Button::~Button () {} void Button::pushbutton_clicked () { qDebug () << "QPushButton" ; } void Button::toolbutton_clicked () { qDebug () << "QToolButton" ; } void Button::radiobutton1_clicked () { qDebug () << "QRadioButton 1" ; } void Button::radiobutton2_clicked () { qDebug () << "QRadioButton 2" ; } void Button::checkbox1_clicked () { qDebug () << "QCheckBox 1" ; } void Button::checkbox2_clicked () { qDebug () << "QCheckBox 2" ; } void Button::commandlinkbutton_clicked () { qDebug () << "QCommandLinkButton" ; } void Button::dialogbuttonbox_clicked (QAbstractButton* button) { qDebug () << "QDialogButtonBox" ; }
效果图:
Item Views
是基于 Model/View 架构的视图组件,提供了一种高效且灵活的方式来显示和编辑数据。常用的包括:
QListView :显示垂直列表。
QTableView :显示表格。
QTreeView :显示树状结构。
Model/View 架构 :
Model (数据模型):负责管理数据的存储和组织,例如 QStandardItemModel
或自定义的模型。
View (视图):负责渲染数据,例如 QTableView
。
Delegate (委托):负责数据的显示和编辑,例如 QStyledItemDelegate
。
头文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #pragma once #include <QtWidgets/QMainWindow> #include "ui_ItemViews.h" #include <QTableView> #include <QStandardItemModel> #include <QHeaderView> #include <QListView> #include <QStringListModel> #include <QTreeView> #include <QStandardItemModel> class ItemViews : public QMainWindow{ Q_OBJECT public : ItemViews (QWidget *parent = nullptr ); ~ItemViews (); private : Ui::ItemViewsClass* ui; private : QListView* listView; QStringListModel* listModel; QTableView* tableView; QStandardItemModel* tablemodel; QTreeView* treeView; QStandardItemModel* treeModel; void setuptableViewModel () ; void setuplistViewModel () ; void setupTreeViewModel () ; };
QListView :显示垂直列表。
cpp文件为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include "ItemViews.h" ItemViews::ItemViews (QWidget* parent) : QMainWindow (parent), listView (new QListView (this )), listModel (new QStringListModel (this )) { setWindowTitle ("Item Views Example" ); setuplistViewModel (); listView->setModel (listModel); setCentralWidget (listView); } ItemViews::~ItemViews () { } void ItemViews::setuplistViewModel () { QStringList data; data << "Alice" << "Bob" << "Charlie" << "David" << "Eve" ; listModel->setStringList (data); }
效果图:
QTableView:
cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 #include "ItemViews.h" ItemViews::ItemViews (QWidget* parent) : QMainWindow (parent), tableView (new QTableView (this )), model (new QStandardItemModel (this )) { setWindowTitle ("Item Views Example" ); setupModel (); tableView->setModel (model); tableView->horizontalHeader ()->setSectionResizeMode (QHeaderView::Stretch); tableView->setSelectionBehavior (QAbstractItemView::SelectRows); tableView->setEditTriggers (QAbstractItemView::DoubleClicked); setCentralWidget (tableView); } ItemViews::~ItemViews () { } void ItemViews::setupModel () { model->setRowCount (3 ); model->setColumnCount (3 ); model->setHeaderData (0 , Qt::Horizontal, "Name" ); model->setHeaderData (1 , Qt::Horizontal, "Age" ); model->setHeaderData (2 , Qt::Horizontal, "Country" ); model->setItem (0 , 0 , new QStandardItem ("Alice" )); model->setItem (0 , 1 , new QStandardItem ("25" )); model->setItem (0 , 2 , new QStandardItem ("USA" )); model->setItem (1 , 0 , new QStandardItem ("Bob" )); model->setItem (1 , 1 , new QStandardItem ("30" )); model->setItem (1 , 2 , new QStandardItem ("UK" )); model->setItem (2 , 0 , new QStandardItem ("Charlie" )); model->setItem (2 , 1 , new QStandardItem ("28" )); model->setItem (2 , 2 , new QStandardItem ("Canada" )); }
效果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 #include "ItemViews.h" ItemViews::ItemViews (QWidget* parent) : QMainWindow (parent), tableView (new QTableView (this )), listView (new QListView (this )), tablemodel (new QStandardItemModel (this )), listModel (new QStringListModel (this )), treeView (new QTreeView (this )), treeModel (new QStandardItemModel (this )) { setWindowTitle ("Item Views Example" ); setupTreeViewModel (); treeView->setModel (treeModel); treeView->setHeaderHidden (false ); treeView->setSelectionBehavior (QAbstractItemView::SelectRows); treeView->expandAll (); setCentralWidget (treeView); } ItemViews::~ItemViews () { } void ItemViews::setupTreeViewModel () { treeModel->setHorizontalHeaderLabels (QStringList () << "Category" << "Details" ); QStandardItem* rootNode = treeModel->invisibleRootItem (); QStandardItem* category1 = new QStandardItem ("Fruits" ); QStandardItem* detail1 = new QStandardItem ("Delicious and healthy" ); category1->appendRow (QList <QStandardItem*>() << new QStandardItem ("Apple" ) << new QStandardItem ("Red or green" )); category1->appendRow (QList <QStandardItem*>() << new QStandardItem ("Banana" ) << new QStandardItem ("Yellow" )); rootNode->appendRow (QList <QStandardItem*>() << category1 << detail1); QStandardItem* category2 = new QStandardItem ("Animals" ); QStandardItem* detail2 = new QStandardItem ("Different types" ); category2->appendRow (QList <QStandardItem*>() << new QStandardItem ("Cat" ) << new QStandardItem ("Cute pet" )); category2->appendRow (QList <QStandardItem*>() << new QStandardItem ("Dog" ) << new QStandardItem ("Loyal friend" )); rootNode->appendRow (QList <QStandardItem*>() << category2 << detail2); QStandardItem* category3 = new QStandardItem ("Vehicles" ); QStandardItem* detail3 = new QStandardItem ("Used for transport" ); category3->appendRow (QList <QStandardItem*>() << new QStandardItem ("Car" ) << new QStandardItem ("Fast and private" )); category3->appendRow (QList <QStandardItem*>() << new QStandardItem ("Bus" ) << new QStandardItem ("Public transport" )); rootNode->appendRow (QList <QStandardItem*>() << category3 << detail3); }
效果图:
Item Widgets
是基于 QWidget 的组件,用于在表格或列表中插入小部件,例如按钮、复选框等。它们通常用于需要显示复杂内容的场景。常见类包括:
QTableWidget :用于表格。
QTreeWidget :用于树状结构。
QListWidget :用于列表。
工作机制
基于 QWidget 的传统方式,直接在单元格中添加小部件(如按钮或复选框)。
典型用法是通过 QTableWidget::setCellWidget()
或 QTreeWidget::setItemWidget()
方法为某个单元格插入一个小部件。
TreeWidgetItem
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 ItemWidgets::ItemWidgets (QWidget *parent) : QMainWindow (parent), tableWidget (new QTableWidget (this )), treeWidget (new QTreeWidget (this )) { ui.setupUi (this ); setWindowTitle ("QTableWidget Example" ); setupTree (); setCentralWidget (treeWidget); } ItemWidgets::~ItemWidgets () {} void ItemWidgets::setupTree () { QTreeWidgetItem* root = new QTreeWidgetItem (treeWidget); root->setText (0 , "Root" ); root->setText (1 , "Root Node" ); QTreeWidgetItem* child1 = new QTreeWidgetItem (root); child1->setText (0 , "Child 1" ); child1->setText (1 , "This is child 1" ); QTreeWidgetItem* child2 = new QTreeWidgetItem (root); child2->setText (0 , "Child 2" ); child2->setText (1 , "This is child 2" ); QTreeWidgetItem* grandchild1 = new QTreeWidgetItem (child1); grandchild1->setText (0 , "Grandchild 1" ); grandchild1->setText (1 , "This is grandchild 1" ); QTreeWidgetItem* grandchild2 = new QTreeWidgetItem (child2); grandchild2->setText (0 , "Grandchild 2" ); grandchild2->setText (1 , "This is grandchild 2" ); treeWidget->expandAll (); }
tableWidget
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #include "ItemWidgets.h" ItemWidgets::ItemWidgets (QWidget *parent) : QMainWindow (parent), tableWidget (new QTableWidget (this )) { ui.setupUi (this ); setWindowTitle ("QTableWidget Example" ); setupTable (); setCentralWidget (tableWidget); } ItemWidgets::~ItemWidgets () {} void ItemWidgets::setupTable () { tableWidget->setRowCount (3 ); tableWidget->setColumnCount (2 ); tableWidget->setHorizontalHeaderLabels (QStringList () << "Name" << "Age" ); tableWidget->setItem (0 , 0 , new QTableWidgetItem ("Alice" )); tableWidget->setItem (0 , 1 , new QTableWidgetItem ("25" )); tableWidget->setItem (1 , 0 , new QTableWidgetItem ("Bob" )); tableWidget->setItem (1 , 1 , new QTableWidgetItem ("30" )); tableWidget->setItem (2 , 0 , new QTableWidgetItem ("Charlie" )); tableWidget->setItem (2 , 1 , new QTableWidgetItem ("35" )); tableWidget->resizeColumnsToContents (); tableWidget->setEditTriggers (QAbstractItemView::DoubleClicked); }
listWidget
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 #include "ItemWidgets.h" #include <QDebug> ItemWidgets::ItemWidgets (QWidget *parent) : QMainWindow (parent), tableWidget (new QTableWidget (this )), treeWidget (new QTreeWidget (this )), listWidget (new QListWidget (this )), addButton (new QPushButton ("Add Item" , this )), removeButton (new QPushButton ("Remove Item" , this )) { ui.setupUi (this ); setWindowTitle ("QTableWidget Example" ); QVBoxLayout* layout = new QVBoxLayout; layout->addWidget (listWidget); layout->addWidget (addButton); layout->addWidget (removeButton); QWidget* container = new QWidget (); container->setLayout (layout); setCentralWidget (container); setupList (); connect (addButton, &QPushButton::clicked, [this ]() { listWidget->addItem ("New Item" ); }); connect (removeButton, &QPushButton::clicked, [this ]() { delete listWidget->currentItem (); }); connect (listWidget, &QListWidget::itemClicked, [this ](QListWidgetItem* item) { qDebug () << "Item clicked: " << item->text (); }); } ItemWidgets::~ItemWidgets () {} void ItemWidgets::setupList () { listWidget->addItem ("Item 1" ); listWidget->addItem ("Item 2" ); listWidget->addItem ("Item 3" ); listWidget->addItem ("Item 4" ); }
区别:
特点
Item Views
Item Widgets
架构
基于 Model/View 架构
基于 QWidget 的传统方式
性能
更高效,适合处理大量数据
数据量大时性能差
灵活性
借助委托实现自定义渲染和编辑
可直接插入复杂小部件,灵活但不高效
开发复杂性
需要实现数据模型,稍复杂
使用传统方法开发,简单直观
适用场景
数据量大,需求偏重于数据展示
小数据量,需求偏重于复杂交互