- Qt6 安装教程
#include "widget.h"
#include
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
#ifndef WIDGET_H
#define WIDGET_H
#include
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget {
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
void open1(); // 基础版本
void open2(); // 记住上次打开的路径,并指定默认的路径为 文档/图片
void open3(); // 图片自适应显示
private slots:
void on_btnOpen_clicked();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include
#include // 用于读取和写入应用程序的设置和配置信息
#include
#include
#include // 智能指针
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
ui->setupUi(this);
ui->label_image->clear();
}
Widget::~Widget() {
delete ui;
}
void Widget::open1() {
// QFileDialog::getOpenFileName() 用于显示一个打开文件对话框,并返回用户选择的文件路径
// 参数:指向当前窗口的指针 this,打开的窗口标题,默认打开路径,文件类型过滤器
QString filename = QFileDialog::getOpenFileName(this, "请选择图片", "D:/", "图片(*.png *jpg);");
if(filename.isEmpty()) {
return;
}
ui->lineEdit_path->setText(filename); // 显示图片路径
ui->label_image->setPixmap((QPixmap(filename))); // 显示图片
}
// 记住上次打开的路径,并指定默认的路径为 文档/图片
void Widget::open2() {
// qApp->applicationDirPath() 用于获取当前应用程序所在的目录路径
// "/config/Setting.ini" 是一个固定的字符串表示配置文件的路径
QString config_path = qApp->applicationDirPath() + "/config/Setting.ini";
qDebug() << config_path;
// 使用智能指针创建了一个 QSettings 对象,并使用指定的配置文件路径和格式进行初始化
// QSettings::IniFormat 是一个枚举值,用于指定配置文件的格式,此处采用的是 ini 格式的配置文件
// 通过 pIniSet 指针调用 value() 函数来获取指定键的值,并将其转换为 QString 类型
std::unique_ptr<QSettings> pIniSet(new QSettings(config_path, QSettings::IniFormat));
QString lastPath = pIniSet->value("/LastPath/path").toString();
// 设置默认读取路径为 windows 下 图片 目录
if(lastPath.isEmpty()) {
lastPath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
}
QString filename = QFileDialog::getOpenFileName(this, "请选择图片", lastPath, "图片(*.png *jpg);");
if(filename.isEmpty()) {
return;
}
ui->lineEdit_path->setText(filename);
ui->label_image->setPixmap((QPixmap(filename)));
// 找到给定文件名(filename)中最后一个斜杠"/"的位置
int end = filename.lastIndexOf("/");
// 提取文件名中最后一个斜杠"/"之前的部分,即路径部分
QString _path = filename.left(end);
// 将键 "/LastPath/path" 的值设置为 _path
pIniSet->setValue("/LastPath/path", _path);
qDebug() << _path;
}
// 图片自适应显示
void Widget::open3() {
QString config_path = qApp->applicationDirPath() + "/config/Setting.ini";
qDebug() << config_path;
std::unique_ptr<QSettings> pIniSet(new QSettings(config_path, QSettings::IniFormat));
QString lastPath = pIniSet->value("/LastPath/path").toString();
if(lastPath.isEmpty()) {
lastPath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
}
QString filename = QFileDialog::getOpenFileName(this, "请选择图片", lastPath, "图片(*.png *jpg);");
if(filename.isEmpty()) {
return;
}
ui->lineEdit_path->setText(filename);
// 图片自适应显示
std::unique_ptr<QPixmap> pix(new QPixmap(filename)); // 通过给定的文件名(filename)加载图像数据
// 将加载的图像按照 ui->label_image 控件的大小进行缩放
// Qt::KeepAspectRatio:保持图像的纵横比例不变
pix->scaled(ui->label_image->size(), Qt::KeepAspectRatio);
ui->label_image->setScaledContents(true); // 当图像大于控件大小时,将自动缩放以适应控件的大小
ui->label_image->setPixmap(*pix); // 设置 ui->label_image 控件的图像为加载并缩放后的图像
int end = filename.lastIndexOf("/");
QString _path = filename.left(end);
pIniSet->setValue("/LastPath/path", _path);
qDebug() << _path;
}
void Widget::on_btnOpen_clicked() {
//open1();
//open2();
open3();
}
[捕获列表](形参列表) mutable 异常列表->返回类型 {
函数体
}
#include
using namespace std;
int main() {
// 1、值捕获
int value = 100;
auto f = [value](int a, int b)->int {
//value++; // 不能在 lambda 表达式中修改捕获变量的值
return a + b + value;
};
cout << f(1, 2) << endl;
// 2、引用捕获
auto f2 = [&value](int a, int b)->int {
value++;
return a + b;
};
cout << f2(1, 3) << endl;
cout << "value = " << value << endl;
// 3、隐式捕获
// = 值捕获
// & 引用捕获
int age = 123;
auto f3 = [&](int a, int b)->int {
value++;
age++;
return a + b;
};
return 0;
}
Qt 4 写法
connect(ui->btnOpen, SIGNAL(clicked), this, SLOT(open()));
Qt 5 写法
connect(ui.btnOpen, QPushButton::clicked, this, &Widget::open);
lambda 函数表达式写法
connect(ui.btnOpen, &QPushButton::clicked, [=](){
// 具体代码实现
});
直接法
void on_控件名_信号名();
如何自定义信号
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget {
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_btnOpen_clicked();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include
namespace Ui { class Dialog; }
class Dialog : public QDialog {
Q_OBJECT
public:
explicit Dialog(QWidget *parent = nullptr);
~Dialog();
private slots:
void on_btnAdd_clicked();
signals:
void sig_addOne(int value);
private:
Ui::Dialog *ui;
};
#endif // DIALOG_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include "dialog.h" // 跨 UI 头文件
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
ui->setupUi(this);
}
Widget::~Widget() {
delete ui;
}
void Widget::on_btnOpen_clicked() {
Dialog dlg;
// 使用 lambda 函数编写槽函数
connect(&dlg, &Dialog::sig_addOne, [=](int value) {
ui->lineEdit->setText(QString::number(value));
});
dlg.exec(); // 需放在 connect 后,因为此行为事件循环会阻塞 UI
}
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog) {
ui->setupUi(this);
}
Dialog::~Dialog() {
delete ui;
}
void Dialog::on_btnAdd_clicked() {
static int value = 100;
emit sig_addOne(value++); // 实现跨 UI 自加操作
}
Qt 的子线程无法直接修改 ui,需要发送信号到 ui 线程进行修改
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include
#include "childthread.h"
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget {
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_btnUpdate_clicked();
void showInfo(Score s);
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
ui->setupUi(this);
qDebug() << "ui thread id = " << QThread::currentThreadId();
}
Widget::~Widget() {
delete ui;
}
void Widget::on_btnUpdate_clicked() {
ChildThread *ch = new ChildThread();
// 以下实现还是在子线程中(不在 ui 线程中),无法直接修改 ui
// connect(ch, &ChildThread::sig_SendToUI, [=](Score s) {
// string info = s.name + "id = " + to_string(s.id) + " age = " + to_string(s.age);
// ui->lineEdit->setText(QString::fromStdString(info));
// // 用于验证 slot 与 ui 下是否同属一个线程(id)
// // 结果表明此处的 slot 与子线程的 run() 同属一个线程(id)
// qDebug() << "slot thread id = " << QThread::currentThreadId();
// });
// 以下实现在 ui 线程 (主线程) 中,可以直接修改 ui
connect(ch, &ChildThread::sig_SendToUI, this, &Widget::showInfo);
ch->start();
}
void Widget::showInfo(Score s) {
qDebug() << "ui thread id2 = " << QThread::currentThreadId();
string info = s.name + "id = " + to_string(s.id) + " age = " + to_string(s.age);
ui->lineEdit->setText(QString::fromStdString(info));
}
childthread.h
#ifndef CHILDTHREAD_H
#define CHILDTHREAD_H
#include
#include
using namespace std;
struct Score {
string name;
int id;
int age;
};
class ChildThread : public QThread {
Q_OBJECT
public:
ChildThread();
protected:
void run() override;
signals:
void sig_SendToUI(Score score);
};
#endif // CHILDTHREAD_H
childthread.cpp
#include "childthread.h"
#include
ChildThread::ChildThread() {
// 非基础类型参数需要注册
qRegisterMetaType<Score>("Score");
qRegisterMetaType<string>("string");
}
void ChildThread::run() {
qDebug() << "run thread id = " << QThread::currentThreadId();
Score s;
s.name = "jack";
s.id = 1001;
s.age = 26;
emit sig_SendToUI(s); // 发送信号
}
例如 QComboBox 的信号
Q_SIGNALS:
void currentIndexChanged(int index);
void currentIndexChanged(const QString &);
解决方案
// 错误写法
connect(ui->comboBox, &QComboBox::currentIndexChanged, this, &Widget::onIndex);
// 解决方案一
connect(ui->comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onIndex(int)));
// 解决方案二
connect(ui->comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Widget::onIndex);
template <typename Func1, typename Func2>
static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender,
Func1 signal,
const typename QtPrivate::FunctionPointer<Func2>::Object *receiver,
Func2 slot,
Qt::ConnectionType type = Qt::AutoConnection)
enum ConnectionType {
AutoConnection,
DirectConnection,
QueuedConnection,
BlockingQueuedConnection,
UniqueConnection = 0x80,
SingleShotConnection = 0x100,
};
AutoConnection
DirectConnection
QueuedConnection
BlockingQueuedConnection
UniqueConnection
可以这么理解,moc 把 Qt 中一些不是 C++ 的关键字做了解析,让 C++ 编译器认识,例如:slots, signals,emit 等,moc 会把这些重新编译解析
C++ 派生类
Qt 半内存管理机制
粘贴别人的代码时,首先在记事本里复制一遍,再粘贴到 QtCreator
使用 u8
不使用 QtCreator开发,直接使用 vs2019
其他设置