【QT】学习笔记1
QT概述
Qt是一个1991年由QtCompany开发的跨平台C++图形用户界面应用程序开发框架。它既可以开发GUI程序,也可用于开发非GUI程序,比如控制台工具和服务器。Qt是面向对象的框架,使用特殊的代码生成扩展(称为元对象编译器(MetaObjectCompiler,moc))以及一些宏,Qt很容易扩展,并且允许真正地组件编程。
QT特征
- 面向对象:Qt具有模块化设计的特点,其控件或元素具备可重用性。一个控件无需了解其具体内容和用途,通过信号(signal)和槽(slot)机制与外界进行通信和交互。并且,所有Qt的控件都支持通过继承的方式进行拓展。
- 控件间的相互通信:Qt提供了信号(signal)和槽(slot)的概念,这是一种安全可靠的通信方法,它允许回调操作,并且支持对象之间在彼此不了解对方详细信息的情况下进行协同合作。这种特性使得Qt非常适合用于真正意义上的控件编程。
- 友好的联机帮助:Qt包含大量的联机参考文档,有超文本HTML格式、UNIX帮助页、man手册以及补充的指南。对于初学者而言,这些指南能够逐步解释Qt编程的相关内容。
- 用户自定义:其他的工具包在应用时普遍存在一个问题,即常常没有完全符合需求的控件,并且生成的自定义控件对于用户来说,就像是一个不透明的黑匣子,难以深入了解和修改。例如,在Motif手册中就讨论过用户自定义控件的相关问题。而在Qt中,用户能够更灵活地进行自定义操作。
- 跨平台优势:由于Qt是一种跨平台的图形用户界面(GUI)工具包,所以它对编程者隐藏了在处理不同窗口系统时可能遇到的潜在问题。为了让基于Qt的程序开发更加便捷,Qt包含了一系列类,这些类能够使程序员避免在文件处理、时间处理等方面受到操作系统细节的限制。
QT Creator
OtCreator是一个用于Ot开发的轻量级跨平台集成开发环境。QtCreator可带来两大关键益处:提供首个专为支持跨平台开发而设计的集成开发环境(IDE),并确保首次接触Qt框架的开发人员能迅速上手和操作。即使不开发Qt应用程序,OtCreator也是一个简单易用且功能强大的IDE。
QT6如何安装?
- 在线安装包下载地址:
- 官网:https://download.qt.io/official_releases/online_installers/
- 中国科学技术大学:https://mirrors.ustc.edu.cn/qtproject/official_releases/online_installers/
- 清华大学:https://mirrors.tuna.tsinghua.edu.cn/qt/official_releases/online_installers/
- 北京理工大学:https://mirror.bit.edu.cn/qtproject/official_releases/online_installers/
- 如果后续需要对组间进行添加、修改或删除可以在安装目录中运行
MaintenanceTool.exe
进行操作。
🔴如果需要下载旧版本的QT可以在 “类别” 栏勾选Archive
,然后点击筛选。
在安装过程中如果遇到下面问题:
下载“https://mirrors. aliyun.com/qtproject/online/qtsdkrepository/windows_x86/android/qt6_624_x86/2022-03-14-1156_meta.7z”时出现网络错误:Error transferringhttps://mirrors.aliyun.com/qtproject/online/qtsdkrepository/windows_x86/android/qt6_624_x86/2022-03-14-1156_meta.7z -server replied:Not Found。
解决办法:用cmd在安装文件下运行下面指令:
可执行文件名.exe --mirror https://mirrors.aliyun.com/qt
可执行文件名.exe -mirror https://mirrors.tuna.tsinghua.edu.cn/qt/
创建QT项目
点击“文件”->“New Project”后会弹出新建项目对话框,选择“Qt Widgets Application”:
其中“Qt Quick Application”是使用QML
语言进行编写的应用程序。
之后在“Details“栏需要注意Base class
的选择:
在使用中会发现代码的检测比较严格,经常出现报错警告,我们可以在“帮助”->“About Plugin”中取消勾选下面选项即可:
GUI 程序设计基础
- QMainWindow:适用于需要完整主窗口架构(如菜单栏、工具栏、状态栏等)的应用。
- QDialog:适用于临时弹出的窗口(如设置窗口、文件选择窗口等)。
- QWidget:适用于没有复杂窗口结构的控件,可以作为顶级窗口或嵌入其他控件中。
- QFrame、QStackedWidget 等其他派生类:根据具体需求来选择,
QFrame
可以提供可定制的边框效果,QStackedWidget
可以管理多个页面。
QDialog 类控件的创建示例
下面我们以 logindialog
类为例,展示如何创建一个继承自 QDialog
的对话框控件。
目录结构
在创建 Qt 项目时,通常会自动生成一套标准的文件结构:
└─ExamSystem├─ExamSystem.pro # 项目的工程文件├─头文件│ └─logindialog.h # 对话框的头文件,用到了.ui文件├─源文件│ ├─logindialog.cpp # 对话框的实现文件│ └─main.cpp # 程序入口└─界面文件└─logindialog.ui # Qt Designer 生成的界面文件,使用XML格式描述元件及布局的界面文件
.pro文件
*.pro
文件就是项目工程文件,它是qmake
自动生成的用于生产makefile的配置文件(cmake
生成的是.txt
文件)。之后想要打开已有的项目就可以在打开文件或项目中选择该文件即可。(QT6依然支持qmake
但更推荐使用cmake
)
- qmake是构建项目的软件,它根据.pro文件生成 Makefile 文件,然后C++编译器可以根据 Makefile 文件进行编译和链接.
- qmake还会自动生成MOC(meta-object compiler)和UIC(user interface compiler)生成构建规则.
- **$$**为替换函数的前缀
以下是 qmake 文件中的一些常用变量及其含义(更多参见 qmake Manual):
变量名 | 含义 |
---|---|
TARGET | 指定项目的目标输出文件名,通常是可执行文件或库文件的名称 |
TEMPLATE | 指定项目的类型,如app 表示应用程序,lib 表示库,subdirs 表示包含子项目的工程等 |
SOURCES | 列出项目中的源文件,包括 C++ 源文件(.cpp )和其他支持的文件类型 |
HEADERS | 指定项目中的头文件 |
LIBS | 指定项目中需要链接的库文件,可使用 Unix 样式的表示法来指定库和路径,如LIBS += -L/usr/local/lib -lmath |
INCLUDEPATH | 指定头文件搜索路径 |
CONFIG | 指定编译选项,如debug 表示调试模式,release 表示发布模式,还可以有shared (生成共享对象)、static (生成静态对象)等选项 |
DEFINES | 指定宏定义,用于在代码中进行条件编译等操作 |
DESTDIR | 指定编译输出目录,即编译完成后的可执行文件或库文件等的输出路径 |
FORMS | 要由用户界面编译器(uic)处理的 UI 文件列表 |
RESOURCES | 要包含在最终项目中的资源(.qrc )文件列表 |
QT | 指定项目中使用的 Qt 模块列表,如QT += widgets 表示使用 Qt 的widgets 模块 |
PWD | 当前项目文件(.pro 或.pri )所在的路径 |
PRO_FILE | 项目文件(.pro )的完整路径 |
PRO_FILE_PWD | 项目文件(.pro )所在的路径 |
QMAKE_HOST.arch | 计算机架构 |
QMAKE_HOST.os | 计算机系统 |
QMAKE_HOST.cpu_count | 计算机 CPU 核心数 |
QMAKE_HOST.name | 计算机名 |
QMAKE_HOST.version | 系统版本(数字形式) |
QMAKE_HOST.version_string | 系统版本(字符串形式) |
QMAKE_PRE_LINK | 编译链接前自动执行的命令 |
QMAKE_POST_LINK | 编译链接后自动执行的命令 |
MOC_DIR | moc 文件路径 |
OBJECTS_DIR | 中间产品目录 |
RCC_DIR | qrc 文件的编译输出路径 |
SUBDIRS | 包含子项目时,当前项目引用的子项目列表 |
UI_DIR | ui 文件路径 |
案例分析:
# 引入 Qt 的核心模块和 GUI 模块
QT += core gui
# 如果 Qt 版本大于 4,那么引入 widgets 模块
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
# 设置生成的可执行文件名为 01_logindialog
TARGET = 01_logindialog
# 设置项目类型为应用程序 (app)
TEMPLATE = app
# 要编译的源文件列表
SOURCES += \main.cpp \logindialog.cpp# 要编译的头文件列表
HEADERS += \logindialog.h
main.cpp(程序入口)
#include "logindialog.h"
#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv); // 初始化 QApplication 对象,Qt 应用程序的必备类logindialog w; // 创建一个 logindialog 对象w.show(); // 显示对话框return a.exec(); // 进入事件循环,等待用户交互
}
解释:
Qt一个类对应一个头文件,类名和头文件名一致。
QApplication
应用程序类:
QApplication
是 Qt 中管理应用程序的核心类,负责处理应用的生命周期,包括初始化、事件循环以及退出时的清理工作。一个 Qt 图形界面应用程序必须至少有一个QApplication
对象,它将负责:
- 事件循环:Qt 提供的主消息循环(
a.exec()
)负责接收和调度所有事件消息。这是所有 Qt GUI 程序的关键机制,在事件循环中,Qt 会接收并处理来自系统和用户的事件(如鼠标点击、键盘输入等)。- 应用程序初始化与退出:
QApplication
在程序启动时进行初始化,并在程序退出时执行必要的清理。- 对话框和窗口管理:
QApplication
还负责窗口和对话框的管理,确保它们能够正确显示并与用户进行交互。
a.exec()
:调用exec()
启动 Qt 的事件循环。在这之后,程序会处于“等待状态”,等待用户输入或其他事件的发生。通过exec()
,Qt 会不断地接收并处理事件,直到调用QApplication::quit()
或者应用程序退出为止。
- 事件处理:Qt 在事件循环中会持续地监控用户与界面的交互(如点击按钮、输入文本等),并将这些事件传递给相应的控件。
- 退出机制:当事件循环结束时,
a.exec()
会返回,并且程序会继续执行并退出。通常,退出事件循环是通过用户关闭窗口或调用QApplication::quit()
来触发的。
logindialog.h(头文件)
#ifndef LOGINDIALOG_H
#define LOGINDIALOG_H#include <QDialog>QT_BEGIN_NAMESPACE
namespace Ui {
class logindialog;
}
QT_END_NAMESPACEclass logindialog : public QDialog
{Q_OBJECTpublic:explicit logindialog(QWidget *parent = nullptr);~logindialog();private:Ui::logindialog *ui;
};#endif // LOGINDIALOG_H
namespace Ui
:其中定义的class logindialog
并不是下面用户手写的类,而是在 编译时 由 Qt 的uic
工具自动生成的类。它负责管理和初始化由Qt Designer
创建的界面元素(如按钮、文本框等)。Q_OBJECT
宏:这是 Qt 中元对象系统的核心,它启用信号与槽机制,用于对象间的通信。Ui::logindialog *ui
:指向可视化的界面
logindialog.cpp(实现文件)
#include "logindialog.h"
#include "ui_logindialog.h" // 引入自动生成的 UI 头文件logindialog::logindialog(QWidget *parent): QDialog(parent),ui(new Ui::logindialog)
{ui->setupUi(this); // 设置界面
}logindialog::~logindialog()
{delete ui; // 释放资源
}
ui->setupUi(this)
:通过setupUi
方法,logindialog
类的 UI 由 Qt 自动生成的代码进行初始化,确保界面组件正确加载。实现了组件的各种设置、信号与槽的关联。
QT元对象系统 (Meta-Object-System)
一、元对象系统
元对象系统是一个基于标准C++扩展,为Qt提供了信号与槽机制、实时类型信息、动态属性系统。
元对象系统的三个基本条件:类必须继承自QObject
、类声明Q_OBJECT
宏(默认私有)、元对象编译器moc。
信号与槽机制是QT的核心机制,信号与槽式一种高级接口,应用于对象之间的通信,它是QT的核心特性,信号与槽是QT自行定义的一种通信机制,它独立于标准的 C/C++ 语言,要正确的处理信号与槽,必须借助一个称为
moc
(Meta-Object-Compiler),也就是"元对象编译器"。它为高层次的事件处理自动生成所需要的必要代码。Qt 程序在交由标准编译器编译之前,先要使用moc
分析 C++ 源文件。如果moc
发现在一个类头文件中包含了宏Q_OBJECT
,则会生成以 “moc_className.cpp” (自定义类名)的.cpp
文件。这个源文件中包含了Q_OBJECT
宏的实现代码。新的文件同样将进入编译系统,与原文件一起参与编译。构建生成的.o
文件包含moc
生成的cpp文件。
Q_OBJECT
定义在qobjectdefs.h
文件中:
/* qmake ignore Q_OBJECT */
#define Q_OBJECT \
public: \QT_WARNING_PUSH \Q_OBJECT_NO_OVERRIDE_WARNING \static const QMetaObject staticMetaObject; \ // 静态元对象virtual const QMetaObject *metaObject() const; \// 返回元对象指针virtual void *qt_metacast(const char *); \ // 设置元对象virtual int qt_metacall(QMetaObject::Call, int, void **); \QT_TR_FUNCTIONS \ // 调用元对象的tr方法实现字符串翻译(tr()、trUtf8())
private: \Q_OBJECT_NO_ATTRIBUTES_WARNING \Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \QT_WARNING_POP \QT_DEFINE_TAG_STRUCT(QPrivateSignal); \QT_ANNOTATE_CLASS(qt_qobject, "")/* qmake ignore Q_OBJECT */
Q_OBJECT
宏中定义的都是操作元对象,真正的信号与槽、属性等内容都是通过QMetaObject
这个元对象实现的:
struct Q_CORE_EXPORT QMetaObject
{class Connection;const char *className() const; // 类名const QMetaObject *superClass() const; // 父类元对象// 判断对象是否是QObject继承树上一个类的实例bool inherits(const QMetaObject *metaObject) const noexcept;QObject *cast(QObject *obj) const{return const_cast<QObject *>(cast(const_cast<const QObject *>(obj)));}const QObject *cast(const QObject *obj) const;#if !defined(QT_NO_TRANSLATION) || defined(Q_QDOC)QString tr(const char *s, const char *c, int n = -1) const;
#endif // QT_NO_TRANSLATION
......// internal index-based connect
static Connection connect(const QObject *sender, int signal_index,const QObject *receiver, int method_index,int type = 0, int *types = nullptr); // 连接信号与槽
// internal index-based disconnect
static bool disconnect(const QObject *sender, int signal_index,const QObject *receiver, int method_index); // 断开信号与槽
static bool disconnectOne(const QObject *sender, int signal_index,const QObject *receiver, int method_index);
// internal slot-name based connect
static void connectSlotsByName(QObject *o); // 自动连接信号与槽
......
}
- Qt元对象系统为什么要继承自QObject?
class Q_CORE_EXPORT QObject
{Q_OBJECT // Q_PROPERTY动态属性系统Q_PROPERTY(QString objectName READ objectName WRITE setObjectName NOTIFY objectNameChangedBINDABLE bindableObjectName)Q_DECLARE_PRIVATE(QObject)public:Q_INVOKABLE explicit QObject(QObject *parent = nullptr);virtual ~QObject();virtual bool event(QEvent *event);virtual bool eventFilter(QObject *watched, QEvent *event); // 事件过滤
#if defined(QT_NO_TRANSLATION) || defined(Q_QDOC)static QString tr(const char *sourceText, const char * = nullptr, int = -1){ return QString::fromUtf8(sourceText); }
#endif // QT_NO_TRANSLATION
......// 对象树机制管理QObject所有类及子类,children()返回所有当前对象的子对象inline const QObjectList &children() const { return d_ptr->children; }void setParent(QObject *parent);
......QT_CORE_INLINE_SINCE(6, 6)bool setProperty(const char *name, const QVariant &value); // 设置属性inline bool setProperty(const char *name, QVariant &&value);QVariant property(const char *name) const; // 读取属性QList<QByteArray> dynamicPropertyNames() const;QBindingStorage *bindingStorage() { return &d_ptr->bindingStorage; }const QBindingStorage *bindingStorage() const { return &d_ptr->bindingStorage; }
......
通过分析QObject
类发现,之所以QObject
为对象系统的基类,是因为其提供了元对象系统很多支持工作:信号与槽、事件处理、属性设置、国际化支持(翻译)、对象树资源管理等等。
使用QObject
作为基类而不使用Q_OBJECT
宏和元对象代码是可以的,但是如果Q_OBJECT
宏没有被使用,那么这个类声明的信号和槽,以及其他特征描述都不会被调用。
一般建议在 QObject 的所有子类中使用 Q_OBJEC 宏,而不管它们是否使用了信号与槽。
二、信号与槽
GUI 用户界面中,当用户操作一个窗口部件时,需要其他窗口部件响应,传统方式经常使用 callback(回调机制)来实现。所谓回调即事先将函数指针作为参数传递另一个函数,然后在函数处理过程中适当地方调用回调函数回调机制有两个缺陷:类型不安全,不能保证调用函数过程中使用正确的参数;强耦合:处理函数必须知道调用哪个回调函数。Qt 的信号与槽机制是松耦合:类型安全的,更灵活,更方便。
信号与槽(Signal & Slot)是 Qt 编程的基础,也是 Qt 的一大创新。因为有了信号与槽的编程机制,在 Qt 中处理界面各个组件的交互操作时变得更加直观和简单。
信号(Signal)就是在特定情况下被发射的事件,例如 PushButton 最常见的信号就是鼠标单击时发射的
clicked()
信号。发射信号使用 Qt 的emit
关键字。Qt 的signals
关键字指出进入了信号声明区,随后即可声明自己的信号。槽(Slot)就是对信号相应的函数。槽就是一个函数,与一般的C++函数是一样的,可以声明在类的任何部分(public、private 或 protected),可以具有任何参数,也可以被直接调用。槽函数与一般的函数不同的是:槽函数可以与一个信号关联,当信号被发射时,关联的槽函数被自动执行。
Qt 的信号(
signals:
中的函数原型)在编译后并不是普通的函数,而是被moc
自动展开为一些内联函数与QMetaObject::activate()
的包装。当我们在代码中emit MySignal(...)
时,实际上是调用了一个由moc
生成的静态或内联函数,这个函数最终会调用QMetaObject::activate()
:void MyClass::MySignal(int value) {// 这段代码由 moc 自动生成,省略了细节// ...QMetaObject::activate(this, &staticMetaObject, signal_index, ...) }
QMetaObject::activate()
会根据内部记录的连接(Connect)信息,依次调用与该信号相连的槽函数。在这个过程中,Qt 能够动态找到对应槽函数的地址,并将参数原样传递给槽函数,从而完成回调调用。
示例:
- 定义信号,如:
signals: void Comeon(QString& str); // 信号不能也无需实现
- 发射信号,如:
QString str = "信号发射";
emit Comeon(str);
- 声明三个槽方法,如:
private slots:void ComeonA(QString& str);void ComeonB(QString& str);void ComeonC(QString& str);
- 槽方法中处理需要处理的工作,如:
void MainWindows::ComeonGuys(QString& str)
{qDebug() << str; // 将str打印到输出控制台
}
注意:使用qDebug()
输出信息时注意添加头文件 #include <QDebug>
;
- 最后将信号与槽关联起来:
connect(this, SIGNAL(Comeon(QString&)), this, SLOT(ComeonGuys(QString&)));
// 也可以:
connect(this, &MainWindow::Comeon, this, &MainWindow::ComeonGuys);
GUI 程序设计的主要内容就是对界面上各组件的信号的响应,只需要知道什么情况下发射哪些信号,合理地去响应和处理这些信号就可以了。
信号与槽关联使用 QObject::connect()
函数实现:
static QMetaObject::Connection connect(const QObject *sender, // 信号发送者const char *signal, // 发送的信号const QObject *receiver, // 信号接收者const char *member, // 表示与信号连接方式的字符串,可以是槽或信号Qt::ConnectionType = Qt::AutoConnection // 连接方式,默认为自动连接
);
常用格式:connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));
用来表示信号和槽的参数都是字符串,Qt 提供了两个宏用于构造这样的字符串:对于信号使用
SIGNAL
,对于槽则使用SLOT
,用它们将函数的原型包围起来即可。注意connect
方法采用SIGNAL()
及SLOT()
时,这里的函数原型只能写出类型,不能有任何参数名,否则连接将会失败。
此外,信号的连接方式一般不填,使用默认的。具体的有:
-
Qt::AutoConnection
:(默认连接方式)自动方式,由系统自动选择连接方式。 -
Qt::DirectConnection
:直接方式,信号发射时,立即调用槽。 -
Qt::QueuedConnection
:队列方式,信号发射时产生一个事件进入队列,事件被处理时槽才能调用。 -
Qt::BlockQueuedConnection
:阻塞队列方式,信号发射时产生一个事件进入队列,然后当前线程进入阻塞状态,直到事件处理完毕,若接收方位于发送信号的线程中,则程序会死锁,故此连接方式仅用于多线程。
信号可以看做是特殊的函数,需要带括号,可带参数,信号无需实现也不能实现。槽函数需要带括号,有参数时还需要指明参数。当信号和槽函数带有参数时,在
connect()
函数里,要写明参数的类型。信号的参数需与槽的参数列表一致,允许比槽参数多**(槽函数的参数不能比信号函数的参数多)**。如果不匹配或参数过少,会出现编译错误或运行错误。在使用信号与槽的类中,必须在类的定义中加入宏
Q_OBJECT
。当一个信号被发射时,与其关联的槽函数通常被立即执行,就像正常调用一个函数一样。只有当信号关联的所有槽函数执行完毕后,才会执行发射信号处后面的代码。
信号与槽的关联方式有如下特点
信号、槽签名的匹配:
每个信号或槽在元对象系统中都有一个签名,包括函数名与参数类型列表。建立
connect()
时,Qt 会将信号与槽的签名进行匹配:
- 函数名要一致(例如
clicked()
对应clicked()
)。- 参数个数与类型必须兼容:如果信号参数是
(int, QString)
,槽至少要能接收(int, QString)
或更少的参数(只要前面类型都能匹配)。- 如果不匹配,老式写法(
SIGNAL()
/SLOT()
宏)会在运行时给出警告,新写法(函数指针)会在编译期直接报错,提供更好安全性。连接表(Connection Lists):
在对象内部,Qt 维护了一个 “连接表”,记录了该对象发出的每个信号分别连接到哪些槽(或信号)。当
emit
一个信号时,会根据该表逐个调用目标槽。
- 一个信号 -> 多个槽:连接表里该信号可能有多个条目。
- 多个信号 -> 一个槽:多个信号分别记录对应相同的槽地址。
- 信号 -> 信号:在底层也视作 “信号 -> 槽”,只不过被连接的 “槽” 是另一个信号的
moc
包装函数,最终会触发二次激活。
-
一个信号连接一个槽:
connect(sender, SIGNAL(single1()), receiver, SLOT(slotFun()));
如:
connect(this, SIGNAL(Comeon(QString&)), this, SLOT(ComeonGuys(QString&)));
// 也可以:
connect(this, &MainWindow::Comeon, this, &MainWindow::ComeonGuys);
-
一个信号连接一个信号:
connect(sender, SIGNAL(single1()), receiver, SIGNAL(single2()));
如:
connect(this, SIGNAL(sigSure(QString&)), this, SIGNAL(sigTest(QString&)));
connect(this, SIGNAL(sigTest(QString&)), this, SLOT(sigA(QString&)));
-
一个信号连接多个槽,关联信号的槽函数按照建立连接时的顺序依次执行:
connect(sender, SIGNAL(single1()), receiver1, SLOT(slotFun()));
connect(sender, SIGNAL(single1()), receiver2, SLOT(slotFun()));connect(sender, SIGNAL(single1()), receiver3, SLOT(slotFun()));
如:
connect(this, SIGNAL(sigSure(QString&)), this, SLOT(sigA(QString&)));
connect(this, SIGNAL(sigSure(QString&)), this, SLOT(sigB(QString&)));
-
多个信号连接一个槽:
connect(sender1, SIGNAL(single1()), receiver, SLOT(slotFun()));
connect(sender2, SIGNAL(single2()), receiver, SLOT(slotFun()));
connect(sender3, SIGNAL(single3()), receiver, SLOT(slotFun()));
如:
connect(this, SIGNAL(sigSure(QString&)), this, SLOT(sigA(QString&)));
connect(this, SIGNAL(sigCancel(QString&)), this, SLOT(sigA(QString&)));
-
信号与槽的自动关联:
ui_xxxx.h文件中
connectSlotsByName()
方法通过对象名支持信号与槽的自动关联。不采connect()
函数而是采用on_objectName_signal命名方式命名槽达到自动关联的效果。
如类头文件中声明槽方法:
private slots:void on_OK_clicked();void on_NO_clicked();
信号与槽的断开连接
QObject::disconnect(const QObject* sender,const char* signal,const QObject *receiver,const char* method);
- 断开与一个对象所有的信号的所有关联
disconnect(sender,0,0,0);
// 等价于:
sender->disconnect();
- 断开与一个指定信号的所有关联
disconnect(sender,0,0,0);
// 等价于:
sender->disconnect();
- 断开与一个指定接受者receiver的所有关联
disconnect(sender, 0, receiver, 0);
// 等价于:
sender->disconnect(SIGNAL(single1()));
- 断开指定信号与槽的关联:
disconnect(sender, SIGNAL(single1()), receiver, SLOT(slotFun()));
// 等价于:
disconnect(myConnection); //myConnection为connect()的返回值
如:
xxx.h文件中添加 m_res
变量用于保存 connect()
返回值。
private:QMetaObject::Connection m_res;
连接信号与槽:
m_res = connect(this, SIGNAL(sigSure(QString&)), this, SLOT(sigA(QString&)));
断开该连接:
disconnect(m_res);
信号与槽机制的优越性:
- 信号与槽机制是类型安全的,相关联的信号与槽参数必须匹配
- 信号与槽是松耦合的,信号发送者不知道也不需知道接受者的信息。
- 信号与槽可以使用任意类型的任意数量的参数。
常见问题
为什么非要用 Q_OBJECT
宏?
- 没有
Q_OBJECT
宏,moc
不会生成辅助代码;即使你声明了signals
或slots
,也无法被 Qt 识别到并注册进元对象系统。
为什么说信号不需要实现?
- 因为
signals
中声明的函数会被moc
解析并创建“激活函数”来调用QMetaObject::activate()
。你自己写实现毫无意义,同时编译也会报错(moc
认为这是一个信号,不期望有用户定义的实现)。
信号可以直接当普通函数调用吗?
- 技术上,旧语法下
emit
是一个宏,实际上是空的,你也可以直接调用信号名,但这只会调用QMetaObject::activate()
;若你写了与信号同名的普通函数,反而会产生冲突或未定义行为。最佳实践是只用emit
触发信号。
效率如何?
- 在同一线程使用直接连接时,调用槽的开销相当于一次函数指针调用,多一层
moc
生成代码的跳转,通常可以忽略不计。 - 在多线程使用队列连接时,会多一步事件排队和线程切换,但这正是异步通信所需的成本,Qt 在这方面已经做了大量优化,性能通常足以满足 GUI 或多数通用场景。
三、动态属性系统
为什么需要 Q_PROPERTY
在标准 C++ 中,如果要让外部能够读写一个类的数据成员,通常会写成:
class MyClass {
private:int m_value;public:void setValue(int val) { m_value = val; }int value() const { return m_value; }
};
这样的封装可读可写。但要想在运行时对这个 “value” 属性做动态反射,比如 “列举对象有哪些属性”、“对属性进行 set/get 而无需知道类名或函数名”,C++ 自身是不支持的。
Qt 的元对象编译器(moc) 与 QMetaObject
联合使用,就能让这些属性出现在运行时的元对象信息里,并可以通过 QObject::property()
、QObject::setProperty()
等函数访问。这依赖于类中使用 Q_PROPERTY
宏,以及 Q_OBJECT
宏来启用 moc
对此类进行扫描、生成辅助代码。
Q_PROPERTY 宏做了什么
Q_PROPERTY()原型:
Q_PROPERTY(type name(READ getFunction [WRITE setFunction] |MEMBER memberName [(READ getFunction | WRITE setFunction)])[RESET resetFunction][NOTIFY notifySignal][REVISION int | REVISION(int[, int])][DESIGNABLE bool][SCRIPTABLE bool][STORED bool][USER bool][BINDABLE bindableProperty][CONSTANT][FINAL][REQUIRED])
当 moc
处理这个头文件时,会将 Q_PROPERTY
中的这些信息提取到元数据表中。随后,运行时每个对象都会持有一个 QMetaObject
(元对象),其中包含:
- 该属性的名称(
name
) - 读函数的名称(
getFunction
),若有 - 写函数的名称(
setFunction
),若有 - 通知信号(
notifySignal
),若有 - 其他修饰符:
DESIGNABLE
,SCRIPTABLE
,STORED
,USER
等。
这些信息被
moc
放到一张静态数组或结构体中,最终编译进可执行文件。当调用QObject::property("属性名")
时,Qt 内部就会使用QMetaObject
找到 “读函数指针” 并进行一次动态调用,返回结果。调用setProperty("属性名", value)
时,则会找到 “写函数指针” 并进行动态调用,完成设置。
元对象与 QMetaProperty
在运行时,每个继承自 QObject
并含有 Q_OBJECT
宏的类,都有一个关联的 QMetaObject
。这个 QMetaObject
包含了:
- 类名
- 所有属性(Property)信息
- 所有信号与槽信息
- 枚举(Enum)信息
- 方法签名(函数)信息
对于属性而言,Qt 还提供 QMetaProperty
类来详细描述属性。我们可以通过:
const QMetaObject *metaObj = myObject->metaObject();
int count = metaObj->propertyCount();
for(int i = 0; i < count; ++i) {QMetaProperty mp = metaObj->property(i);qDebug() << mp.name() << mp.typeName();
}
来遍历这个对象拥有的全部属性名、类型名等,并可进一步做动态调用。这就是 Qt 属性反射的基础原理——所有信息都在 metaObject()
的元数据里。
示例:
- 新建桌面应用程序TestProperty,父类QWidget,其他采用默认。
- 右键单击项目添加自定义类MyPropertyClass,父类QObject.
- mypropertyclass.h文件中Q_OBJECT下方声明属性宏:
class mypropertyclass : public QObject
{Q_OBJECTQ_PROPERTY(type mask READ mask WRITE setMask NOTIFY maskChanged FINAL)
- READ: 指定属性读取函数,如
READ getFunction
;若没有提供READ
,也可用MEMBER myMember
指定直接和某个成员变量绑定,这样就无需专门写 getter 函数。- WRITE: 指定属性写入函数,如
WRITE setFunction
。- MEMBER: 指向类的一个成员变量,用于自动生成读写逻辑;如果同一个属性同时指定了
READ
/WRITE
与MEMBER
,则READ
/WRITE
优先级更高。- NOTIFY: 关联一个信号,例如
NOTIFY maskChanged
,这个信号通常在属性值变更时触发,既能让 QtQuick(QML) 进行属性绑定更新,也能让 C++ 层面监听属性变化。如果你仅仅声明了一个
Q_PROPERTY
而没有写NOTIFY maskChanged
,则在 QML 或者其它绑定场景下可能不知道何时属性发生改变。要想自动刷新界面,需要借助通知信号来触发更新。
- 声明属性读取、设置函数,定义属性变更时发送的信号,定义成员变量m_mask保存属性值。
public:explicit mypropertyclass(QObject *parent = nullptr);QString mask() const; // 读取属性void setMask(QString strMaskNum); //设置属性signals:void maskChanged(QString str); // 属性变更时发送的信号
private:QString m_mask; // 保存属性流
- widget.h添加槽函数声明
private slots:void setChanged(QString str); // 响应属性变更信号
widget.cpp添加槽方法定义:
void Dialog::setChanged(QString str)
{qDebug() << "测试信号" << str;
}
- Widget类构造函数中添加如下代码
mypropertyclass* mypC = new mypropertyclass;
connect(mypC, SIGNAL(maskChanged(QString)), this, SLOT(setChanged(QString)));
mypC->setMask("哔哔~"); // 属性WRITE写操作
qDebug() << "当前信号:" << mypC->mask(); // 属性READ读操作QObject* obj = mypC;
qDebug() << "obj进行属性读取:" << obj->property("mask").toString();
qDebug() << "obj进行第二次属性读取:" << obj->property("mask").toString();
动态操作属性:property() 与 setProperty()
property() 机制
当我们调用:
QObject *obj = myPropertyObject;
QVariant val = obj->property("mask");
时,Qt 会先查找 obj->metaObject()
里的所有属性列表,找到名字为 “mask” 的 QMetaProperty
,然后再调用它的 “读函数指针” 或 “MEMBER 直接访问” 来获取值。这就是动态调用,无需知道类的名称、头文件、也不需要包含任何声明。
setProperty() 机制
类似地:
obj->setProperty("mask", "哔哔~");
Qt 会查找到 “mask” 属性的写函数指针或 MEMBER
写入功能,然后调用之/写入之。当写操作完成后,如果该属性声明了 NOTIFY
信号,Qt 会自动发射通知信号(前提是你在写函数中或者 MEMBER 改变时手动 emit maskChanged(...)
),以便让界面或其他模块获知这一变动。
何时触发 NOTIFY 信号
- 如果是使用 READ/WRITE:在
setMask()
函数里,你要手动检测值是否改变,然后emit maskChanged(newVal)
。这样 Qt 才能在外部监听到属性变更。 - 如果是使用 MEMBER 绑定并指定了
NOTIFY
:当你使用setProperty()
或者直接给这个成员赋值时,需要在合适时机手动emit maskChanged(m_mask)
。MEMBER 并不会自动生成更新检测逻辑,需要你自己在写代码时处理值变化。 - 如果属性没标注
NOTIFY
信号,则外部不知道何时发生变化(C++ 层面可以用property()
主动轮询,QML 层面没法自动刷新)。
Qt 对象树
父子关系与对象链表
当我们创建一个继承自 QObject
的对象时,如果在构造函数中传入了一个父对象(parent
),那么 Qt 会将该子对象加入到父对象内部维护的对象链表(QObjectList
)中。这样,父对象就会在析构时自动析构其所有子对象,开发者无需手动对每个子对象进行 delete
操作。
内存安全
- 自动析构:父对象析构时会自动销毁所有子对象,避免内存泄漏。
- 避免二次删除:Qt 保证不会重复
delete
同一个对象。如果你需要手动销毁一个对象,建议使用deleteLater()
而不是delete
,因为deleteLater()
可以在事件循环空闲时安排删除操作,多次调用也是安全的,而直接delete
多次则会导致不安全行为(崩溃或不可预期错误)。
层级结构
- 通过
children()
函数可以获取父对象所拥有的所有子对象列表。 - 如果一个对象有子对象,这些子对象又可以有自己的子对象,形成树形结构。
children()
只会返回 当前层级 的所有直接子对象,而不包含更深层级的孙子对象。
Qt的对象树机制是其内存管理的核心特性,下面为您详细解析并提供代码示例:
#include <QCoreApplication>
#include <QObject>
#include <QDebug>class MyObject : public QObject
{Q_OBJECT
public:// 构造函数中可接受一个父对象explicit MyObject(const QString &name, QObject *parent = nullptr): QObject(parent), m_name(name){qDebug() << "Construct MyObject:" << m_name;}~MyObject() override{qDebug() << "Destruct MyObject:" << m_name;}private:QString m_name;
};int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);// 创建一个父对象MyObject *parentObj = new MyObject("Parent");// 创建子对象,并指定父对象MyObject *childObj1 = new MyObject("Child1", parentObj);MyObject *childObj2 = new MyObject("Child2", parentObj);// 查看父对象的子对象列表QObjectList childrenList = parentObj->children();qDebug() << "Number of children:" << childrenList.size(); // 这里会输出 2// 打印子对象指针(仅用于演示)for (QObject *obj : childrenList) {qDebug() << " -> Child object:" << obj;}// 手动释放资源的方式1:deleteLater()// 只要调用一次就行,多次调用也不会报错,Qt 会在事件循环空闲时自动删除。// childObj1->deleteLater();// childObj2->deleteLater();// 手动释放资源的方式2:直接 delete 父对象// 父对象析构会自动析构所有子对象。此时不需要对 childObj1 和 childObj2 再做处理。delete parentObj;// 至此,Child1 和 Child2 也自动被销毁了// 不建议同时对 childObj1, childObj2 再执行 delete 或 deleteLaterreturn 0;
}
窗口部件
一、默认部件基类
在 Qt 中,QMainWindow
、QDialog
和 QWidget
都继承自 QWidget
,并且它们的设计目的是为了满足不同类型的用户界面需求。
QWidget 类
QWidget
类堪称所有用户界面控件的根基,代表着各类窗口部件。它具备多方面关键能力:在事件处理层面,能够敏锐接收并妥善响应鼠标点击、键盘输入及其他各类事件;于绘制机制而言,承担着将控件外观精准绘制在屏幕上的重任;在布局管理方面,大力支持运用如QVBoxLayout
、QHBoxLayout
等布局管理器,实现对控件排列的高效把控。作为高度灵活的基类,QWidget
既可以作为任意类型窗口的父类,又能在用户界面中无缝嵌入其他QWidget
或派生控件,为构建复杂多样的用户界面提供了坚实基础。QMainWindow 类
QMainWindow
由QWidget
派生而来,为应用程序的主窗口搭建起标准架构。其内部包含多个重要组成部分:菜单栏,用于罗列应用程序的各项菜单选项,方便用户进行功能选择;工具栏,通常放置常用工具按钮,为用户提供便捷操作途径;状态栏,主要用于展示应用程序当前状态或提供相关帮助信息;中央区域则是应用程序主要内容的展示核心,借助setCentralWidget()
方法可轻松设置。在设计主窗口时,QMainWindow
凭借丰富的功能组件,成为构建复杂应用程序界面的不二之选,特别是对于那些依赖菜单、工具栏、状态栏协同工作的应用场景。QDialog 类
同样继承自QWidget
的QDialog
,专注于实现对话框窗口。对话框作为与用户交互的临时性窗口,广泛应用于诸多场景,像提示框、确认框这类用于简单信息提示与确认的窗口,以及登录窗口、设置窗口等需要用户输入特定信息的窗口。与QMainWindow
不同,QDialog
主要聚焦于完成短期任务,一旦任务结束,通常会自动关闭,以提升用户交互的流畅性与便捷性。基于 QWidget 创建控件的策略
- QMainWindow:适用于需要完整主窗口架构(如菜单栏、工具栏、状态栏等)的应用。
- QDialog:适用于临时弹出的窗口(如设置窗口、文件选择窗口等)。
- QWidget:适用于没有复杂窗口结构的控件,可以作为顶级窗口或嵌入其他控件中。
- QFrame、QStackedWidget 等其他派生类:根据具体需求来选择,
QFrame
可以提供可定制的边框效果,QStackedWidget
可以管理多个页面。
QWidget

QWidget
的构造函数有两个参数:
- QWidget *parent = 0:
parent
参数指定当前窗口部件的父窗口部件。如果为0
,表示当前窗口没有父窗口部件,它是一个顶级窗口。如果指定了parent
,则当前窗口部件是该父窗口的子部件。- 顶级窗口部件通常是应用程序的主窗口,而非顶级窗口部件则会被嵌入到父窗口部件中作为子部件显示。
- 如果没有父窗口,窗口会被系统视为独立的窗口;有父窗口时,窗口则会被视为嵌入在父窗口中的一个子窗口。
- Qt::WindowFlags f = 0:
f
参数是用来设置窗口的属性,类型是Qt::WindowFlags
,它是Qt::WindowType
枚举值的组合。Qt::WindowFlags
定义了窗口的行为和外观属性,比如是否可调整大小、是否为弹出窗口等。常见的窗口类型包括:Qt::Widget
:默认值,表示普通窗口。Qt::Dialog
:对话框窗口。Qt::FramelessWindowHint
:没有边框的窗口。Qt::WindowStaysOnTopHint
:窗口总是显示在其他窗口之上。
- 通过组合这些标志,用户可以定制窗口的各种行为。
- 顶级窗口:没有父窗口的窗口部件会被认为是顶级窗口部件。顶级窗口通常是整个应用程序的主窗口,如
QMainWindow
或QWidget
。 - 子窗口:如果指定了
parent
窗口部件,那么当前窗口部件就是该父窗口的子窗口部件。子窗口通常会在父窗口内作为嵌入的部分显示。
setWindowState()
方法用于设置窗口的状态。它接受一个参数,这个参数是Qt::WindowStates
枚举值的组合,表示窗口的不同状态。常见的窗口状态包括:
窗体状态 | 作用 |
---|---|
Qt::WindowNoState | 窗体为正常状态 |
Qt::WindowMinimized | 窗体最小化 |
Qt::WindowMaximized | 窗体最大化 |
Qt::WindowFullScreen | 窗体全屏显示 |
Qt::WindowActive | 窗体为活动窗体 |
QWidget设计模式属性设置
-
enabled:启用或禁用 widget,默认启用。
-
geometry:控件的位置和尺寸,表示为
(x, y, 宽度, 高度)
。 -
sizePolicy:设置widget在水平和垂直方向的伸缩策略以及伸缩因子(Stretch Factors),所谓伸缩策略实际就是widget对待部件大小提示的策略,需结合布局管理器一起使用。伸缩策略可通过调用setSizePolicy()方法设置,大小提示可通过sizeHint()函数返回值获取,也可重载sizeHint()方法进行重置。
拉伸因子描述了各个部件在进行拉伸时,部件间以指定的比例进行拉伸,如水平布局的三个按钮其拉伸因子分别设为1,2,3则表示该3个按钮将会以1:2:3的比例进行拉伸。
注意:1.当主窗口的大小不能按计算出来的比例容纳下所有子部件时,子部件不一定会按设计好的比例进行排列。
大小策略与拉伸因子之间的关系:
若部件的拉伸因子大于0,则按照拉伸因子的比例分配空间;若拉伸因子为0,则只有在其他部件不需要空间时才会获得空间;也就是说若一些部件拉伸因子大于0,而一些部件拉伸因子为0,则只有拉伸因子大于0的部件会被拉伸,而拉伸因子为0的部件不会被拉伸。若所有部件的拉伸因子都为0,则按照大小策略的规则对部件进行拉伸。注意:2.若部件的大小策略为Fixed,则即使设置了拉伸因子,该部件也不会被拉伸。故拉伸因子会使大小策略不起作用或失效(除了Fixed策略外)
属性值 | 作用 |
---|---|
Fixed | 尺寸不能改变,尺寸为sizeHint大小 |
Minimum | 尺寸可以拉伸,尺寸可变范围:≥sizeHint |
Maximum | 尺寸可以缩小,尺寸可变范围:minimumSizeHint ~ sizeHint |
Preferred | 可以变大缩小,尺寸可变范围:≥minimumSizeHint |
Expanding | 可以变大缩小,尺寸可变范围:≥minimumSizeHint,且部件有优先扩展权(注:优先扩展权表部件将尽可能多的占用空间,如Preferred与Expanding同时存在则优先分配空间给Expanding) |
MinimumExpanding | 尺寸可以拉伸,尺寸可变范围:≥minimumSizeHint,且部件有优先扩展权 |
Ignored | 任意变大缩小,尺寸可变范围:≥minimumSizeHint(若minimumSizeHint为0,则可缩小至0,此时部件不可见) |
- minimumSize:控件的最小尺寸,调整时不可缩小到此尺寸以下。
- maximumSize:控件的最大尺寸,调整时不可增大到此尺寸以上。
- palette:设置控件的调色板,控制控件的基本样式,如背景色、前景色等。
- mouseTracking:控件是否启用鼠标跟踪。启用时,控件可以接收鼠标移动事件,即使鼠标不在控件范围内。
- tableTracking:控件是否启用平板或手机的触摸屏追踪。
- focusPolicy:焦点策略,按钮可以通过NoFocus使虚线消失,lineedit这类文本编辑框必须能获得焦点。
属性值 | 作用 |
---|---|
NoFocus | 无法通过点击和键盘获得焦点 |
TabFocus | 鼠标无法获得焦点,Tab键获得焦点 |
ClickFocus | 鼠标点击获得焦点,Tab键无法获得焦点 |
StrongFocus | 鼠标和Tab键都可以获得焦点 |
WheelFocus | 通过滚轮获得焦点 |
- contextMenuPolicy:上下文菜单策略,指定菜单的显示方式。
属性值 | 作用 |
---|---|
NoContextMenu | 部件无菜单,菜单处理延迟到部件父亲 |
PreventContextMenu | 部件无菜单,菜单处理不延迟到父亲,而是传递到本身。 |
DefaultContextMenu | 调用部件的contextMenuEvent方法,默认处理方式为忽略上下文事件。 |
ActionsContextMenu | 部件菜单由 actions定义构成 |
CustomContextMenu | 部件菜单自定义,发送customContextMenuRequested信号 |
-
acceptDrops:设置部件是否接受拖拽事件,默认启用。
-
toolTip:设置部件的提示,鼠标悬浮时会显示。
-
toolTipDuration:设置widgettoolTip的显示持续时间,毫秒为单位,默认为-1,会一直显示。
-
statusTip:设置部件的状态提示,当窗口有statusBar时会显示在上面。
-
whatsThis:显示帮助信息,通常通过点击 “What’s This?” 按钮来获取相关信息。
-
accessibleName:辅助功能客户端应用程序所使用的控件名称。
-
accessibleDescription:主要用来为视力较差或盲人用户,提供更大的上下文,也可以使用上下文搜索或其他应用程序。。
-
layoutDirectionwidget:布局的方向,LeftToRight,RightToLeft,LayoutDirectionAuto,字面意思。
-
autoFillBackground:设置widget背景是否被画板颜色自动填充,默认不勾选。
-
styleSheet:设置控件的样式表(QSS),可以自定义控件的外观。
-
locale:设置widget的区域和语言,在将时间等信息转成字符串后,年月日几个字会显示不同语言。
-
inputMethodHint:设置widget输入时的屏幕键盘模式,有纯数字、纯字母等多种模式,用在手机端。
QDialog
QDialog
是各种对话框的基类,继承自 QWidget
。对话框有两种表现形式:模态对话框 和 非模态对话框。
模态对话框
模态对话框会阻塞应用程序中其他窗口的输入,直到当前对话框关闭,用户才能操作其它窗口。模态对话框有自己的本地事件循环。通过调用 exec()
方法,可以使对话框以模态方式运行。当对话框关闭时,exec()
返回一个值,并继续执行调用 exec()
之后的代码。
通常,将默认按钮(如 “OK”)连接到 accept()
槽,将 “Cancel” 按钮连接到 reject()
槽,从而关闭对话框并返回相应的值。也可以使用 done()
槽,传递 Accepted
或 Rejected
参数。
- 使用
exec()
方法:
QDialog dlg;
dlg.exec(); // 启动模态对话框
- 使用
setModal()
方法:
QDialog dlg;
dlg.setModal(true); // 设置为模态
dlg.show(); // 显示对话框
- 使用
setWindowModality()
设置窗口模态:
QWidget widget;
widget.setWindowModality(Qt::ApplicationModal); // 设置为应用级模态窗口
widget.show(); // 显示窗口
阻塞方式 | 阻塞效果 |
---|---|
Qt::ApplicationModal | 阻塞应用程序的所有窗口 |
Qt::WindowModal | 阻塞阻塞父窗口、祖先窗口及它们的子窗口 |
Qt::NoModal | 不阻塞,默认值 |
其他常用部件
1.QLabel - 用于显示文本、数字、图片和 GIF 动图
QLabel
是一个常用的控件,用于显示文本、数字、图片和 GIF 动图。它是 UI 中的静态显示元素。
- 显示文本:可以设置静态文本。
- 显示图片:可以用
setPixmap()
设置显示图片。 - 显示 GIF 动图:通过
setMovie()
设置 GIF 动画。
QLabel *label = new QLabel(this); // 创建 QLabel 对象
label->setText("Hello, World!"); // 设置文本
label->setPixmap(QPixmap("image.png")); // 显示图片
label->setMovie(new QMovie("animation.gif")); // 显示 GIF 动画
label->show();
与其他控件的伙伴关系:QLabel
可以与其他控件建立伙伴关系,用于设置快捷键。通过设置伙伴关系,您可以让标签成为其他控件(如按钮)的快捷键触发器。按下快捷键时,伙伴控件会响应(例如按钮被按下)。
QPushButton *button = new QPushButton("Click Me", this);
QLabel *label = new QLabel("Press Alt+P", this);
label->setBuddy(button); // 设置按钮为标签的伙伴
此时,当用户按下 Alt+P
快捷键时,按钮将被点击。
另外再设计模式下是伙伴关系的操作是这样的:
设计模式属性设置:
- frameShape:定义 QFrame 的框架形状,不同取值呈现各异的外观风格:
取值 | 说明 |
---|---|
NoFrame | 无框架,QFrame 如同普通容器,无边界装饰。 |
Box | 显示矩形盒子状边框,轮廓清晰。 |
Panel | 类似面板,通过边框营造内容区域的凹陷或凸起感。 |
HLine/VLine | 水平或垂直线,常用于分隔界面区域。 |
StyledPanel | 依当前样式(如 QSS)绘制框架,适配界面风格。 |
WinPanel | 模拟 Windows 风格的面板框架效果。 |
- frameShadow:控制框架阴影效果,影响立体感
取值 | 说明 |
---|---|
Plain | 无阴影,边框线条平实,无立体凹凸。 |
Raised | 框架凸起,从背景 “隆起”,层次感强。 |
Sunken | 框架凹陷,似嵌入背景,视觉层次不同。 |
-
lineWidth:设定框架边框宽度(像素单位)。值越大,边框越粗。例如
1
为细边框,5
则明显加粗,直接改变边框视觉粗细。 -
midLineWidth:用于特定框架形状(如
StyledPanel
)的中间线宽度。当框架含复杂线条结构时,调整此值改变中间分隔线粗细。若为0
,可能不显示中间线或按默认处理。 -
text:定义 QLabel 显示的文本内容,通过设置此属性确定标签展示的文字信息。
-
textFormat:规定文本显示格式。
取值 | 说明 |
---|---|
AutoText | 自动识别普通文本或富文本并显示 |
RichText | 按富文本(如带格式、超链接等)显示 |
PlainText | 仅显示无格式的普通文本 |
- pixmap:用于设置 QLabel 展示的像素图(如图片),使标签具备图像显示能力。
- scaledContents:控制内容是否缩放适配标签大小。
true
:像素图或内容缩放以适应 QLabel 尺寸;false
:内容按原始尺寸显示,超出部分可能隐藏。
- alignment:决定文本对齐方式,支持多种组合(如左对齐 + 垂直居中、右对齐 + 顶部对齐等),满足不同布局的排版需求。
- wordWrap:设置文本是否自动换行。启用后,文本超出标签宽度时自动换行显示。
- margin:指定文本与 QLabel 边框的空白距离,单位为像素,默认
0
表示无边距。 - indent:定义文本缩进量(像素单位)。值为
-1
时,遵循默认缩进规则。 - openExternalLinks:控制是否允许点击文本中的外部链接(如超链接)。启用后,点击链接可执行跳转操作。
- textInteractionFlags:定义文本交互行为。例如
LinksAccessibleByMouse
表示鼠标可点击访问链接,还可组合其他标志(如键盘交互),灵活控制文本交互方式。 - buddy:设置 QLabel 的伙伴控件,常将标签与输入类控件(如文本框)关联,使标签快捷键能聚焦到对应控件,提升交互便捷性。
2.QLineEdit - 用于接收用户输入
QLineEdit
是一个常用的输入框控件,用于接收用户输入的文本。
显示模式:QLineEdit
提供了几种不同的显示模式,允许对用户输入进行格式化显示。
显示模式 | 效果 |
---|---|
QLineEdit::Normal | 正常显示输入的字符 |
QLineEdit::NoEcho | 输入的字符不显示(用于密码等隐私信息) |
QLineEdit::Password | 输入的字符显示为星号(* ),常用于密码输入框 |
QLineEdit::PasswordEchoOnEdit | 编辑时正常显示,其他时候显示为星号(* ) |
QLineEdit *lineEdit = new QLineEdit(this);
lineEdit->setEchoMode(QLineEdit::Password); // 设置为密码输入框
输入掩码:QLineEdit
支持掩码功能,限制用户输入的内容。掩码中的字符定义了可接受的输入类型。
QLineEdit *lineEdit = new QLineEdit(this);
lineEdit->setInputMask("A9-99A"); // 输入格式:字母+数字-数字+字母
字符(必须输入) | 字符(可留空) | 含义 |
---|---|---|
A | a | 只能输入A-Z,a-z |
N | n | 只能输入A-Z,a-z,0~9 |
X | x | 可以输入任意字符 |
9 | 0 | 只能输入0-9 |
D | d | 只能输入1-9 |
# | 只能输入+,-,0-9 | |
H | h | 只能输入十六进制字符(0-9,a-f,A-F) |
B | b | 只能输入二进制字符(0,1) |
> | 后面的字母字符自动转换为大写 | |
< | 后面的字母字符自动转换为小写 | |
! | 停止字母字符的大小写转换 | |
\ | 将该表中的特殊字符正常显示用作分隔符 |
设计模式属性设置:
-
inputMask:设置输入掩码,强制用户按指定格式输入内容,例如约束输入 IP 地址、电话号码等固定格式数据。
-
text:获取或设置 QLineEdit 编辑框内的文本内容,即用户输入的文字或程序预设的文字信息。
-
maxLength:限制输入文本的最大字符数,默认值为
32767
,超出此长度后无法继续输入。 -
frame:控制 QLineEdit 是否显示边框。
-
echoMode:定义文本显示模式,适配不同场景,如下表:
取值 | 说明 |
---|---|
Normal | 正常显示输入字符,用于普通文本输入。 |
NoEcho | 完全隐藏输入内容,用于极高隐私场景(如密码输入但不显示任何符号)。 |
Password | 用占位符号(如圆点• )替代真实字符,常见于密码输入框。 |
PasswordEchoOnEdit | 编辑时显示字符,停止编辑后隐藏,平衡输入确认与隐私需求。 |
-
cursorPosition:获取或设置光标在文本中的位置(以字符索引表示),如
0
表示光标在文本开头。 -
alignment:设置文本在编辑框内的对齐方式(如 “左对齐,垂直中心对齐”),确保文本排版效果。
-
dragEnabled:允许用户拖拽选中文本,默认不勾选。
-
readOnly:编辑框为只读状态,用户无法修改内容,默认不勾选。
-
placeholderText:设置占位提示文本,编辑框无内容时显示,引导用户输入(如 “请输入邮箱”)。
-
cursorMoveStyle:定义光标移动逻辑风格,如
LogicalMoveStyle
表示按文本逻辑位置移动,影响光标操作行为。 -
clearButtonEnabled:编辑框右侧显示清除按钮,点击可一键清空内容,默认不勾选(隐藏清除按钮)。
3.QPushButton - 用于按钮控件
QPushButton
是一个常用的按钮控件,通常用于触发用户的操作或事件。
- 显示文字或图标:可以设置按钮的文本或图标。
- 连接信号和槽:当按钮被点击时,可以触发特定的操作。
代码示例:
QPushButton *button = new QPushButton("Click Me", this);
connect(button, &QPushButton::clicked, this, &Widget::onButtonClicked);
button->show();
设计模式属性设置:
-
text:设置按钮上显示的文本内容,用于定义按钮的标识文字,如 “确定”“提交” 等。
-
icon:为按钮添加图标,通过加载图片资源,使按钮具备可视化图标提示功能。
-
iconSize:规定图标显示尺寸,格式为 “宽 × 高”(如
20×20
),控制图标在按钮上的大小。 -
shortcut:配置按钮的快捷键,用户可通过键盘快捷键触发按钮功能,提升操作便捷性。
-
checkable:按钮支持勾选,具备选中 / 未选中两种状态。默认,按钮为普通点击模式,无勾选功能。
-
checked:按钮处于勾选状态(需配合
checkable=true
),默认,处于未勾选。 -
autoRepeat:按住按钮不放时,自动重复触发点击信号,默认,关闭。
-
autoExclusive:
true
:QRadioButton 默认启用自动独占特性,在同一组单选按钮中,确保仅有一个按钮可被选中,实现标准的单选互斥效果;false
:关闭自动独占特性,可能出现多个单选按钮同时选中的情况(不符合常规单选逻辑,实际开发中极少使用)。
-
autoRepeatDelay:设置自动重复触发的延迟时间(单位:毫秒),默认
300
,即按住按钮后延迟指定时间开始重复触发。 -
autoRepeatInterval:定义自动重复触发的时间间隔(单位:毫秒),默认
100
,控制每次重复触发的间隔时长。 -
autoDefault:默认,按钮自动成为默认按钮(如对话框中按回车可触发)。取消勾选则,无默认按钮特性。
-
default:将按钮设为默认按钮(需对话框等环境支持默认按钮机制)。默认,非默认按钮。
-
flat:按钮以扁平风格显示,隐藏立体效果。默认,按钮显示默认的立体样式。
4.QRadioButton - 单选按钮
QRadioButton
是单选按钮类,它通常用于提供多个选项,但只能选择其中一个。单选按钮通常被放置在一个分组框中,保证同一组中只有一个按钮可以被选中。
组内排他性:在同一组内,只能选择一个选项,其他选项会被自动取消选择。
QRadioButton *radioButton1 = new QRadioButton("Option 1", this);
QRadioButton *radioButton2 = new QRadioButton("Option 2", this);
radioButton1->setChecked(true); // 默认选中第一个选项
设计模式属性设置几乎与 QPushButton 相同。
5.QCheckBox - 多选按钮
QCheckBox
是多选按钮类,用户可以选择多个选项。每个复选框的选中状态是独立的。
- 多选功能:用户可以选择多个选项,而不像单选按钮那样具有排他性。
QCheckBox *checkBox1 = new QCheckBox("Option 1", this);
QCheckBox *checkBox2 = new QCheckBox("Option 2", this);
checkBox1->setChecked(true); // 选中第一个选项
- tristate:启用三态,支持选中、未选中、中间不确定状态。默认,仅两种状态(选中 / 未选中)。
QCheckBox checkBox;
// 启用三态,支持中间状态
checkBox.setTristate(true); // 设置不同状态并获取判断
checkBox.setCheckState(Qt::Checked); // 设置为选中状态
if (checkBox.checkState() == Qt::Checked) {qDebug() << "当前状态:Checked(选中)";
}checkBox.setCheckState(Qt::Unchecked); // 设置为未选中状态
if (checkBox.checkState() == Qt::Unchecked) {qDebug() << "当前状态:Unchecked(未选中)";
}checkBox.setCheckState(Qt::PartiallyChecked); // 设置为中间状态,只有设置了tristate才会出现
if (checkBox.checkState() == Qt::PartiallyChecked) {qDebug() << "当前状态:PartiallyChecked(中间状态)";
}
相关文章:
【QT】学习笔记1
QT概述 Qt是一个1991年由QtCompany开发的跨平台C图形用户界面应用程序开发框架。它既可以开发GUI程序,也可用于开发非GUI程序,比如控制台工具和服务器。Qt是面向对象的框架,使用特殊的代码生成扩展(称为元对象编译器(…...
【Kafka基础】生产者命令行操作指南:从基础到高级配置
Kafka作为分布式消息系统,其生产者是数据管道的起点。掌握kafka-console-producer.sh工具的使用对于开发测试和运维都至关重要。本文将系统介绍该工具的各种用法,帮助您高效地向Kafka发送消息。 1 基础消息生产 1.1 最简单的消息发送 /export/home/kafk…...
【Java面试系列】Spring Boot中自动配置原理与自定义Starter开发实践详解 - 3-5年Java开发必备知识
【Java面试系列】Spring Boot中自动配置原理与自定义Starter开发实践详解 - 3-5年Java开发必备知识 引言 Spring Boot作为Java生态中最流行的框架之一,其自动配置机制和Starter开发是面试中的高频考点。对于3-5年经验的Java开发者来说,深入理解这些原理…...
reid查找余弦相似度计算修正(二)
上一篇文章 reid查找余弦相似度计算(一) 上一篇的遗留问题就是reid 的结果部分正确,我们参考一下 fast-reid的demo,把里面的抽取特征提取出来 修改提取特征 首先发现图像改变大小的不同,fast 使用的是[128,384], 如…...
嵌入式---加速度计
一、基本概念与定义 定义 加速度计(Accelerometer)是一种测量物体加速度(线性加速度或振动加速度)的传感器,可检测物体运动状态、振动幅度、倾斜角度等,输出与加速度成比例的电信号(模拟或数字信…...
Redis如何判断哨兵模式下节点之间数据是否一致
在哨兵模式下判断两个Redis节点的数据一致性,可以通过以下几种方法实现: 一、检查主从复制偏移量 使用INFO replication命令 分别在主节点和从节点执行该命令,比较两者的master_repl_offset(主节点)和slave_repl_offs…...
Spring 核心注解深度解析:@Autowired、@Repository 与它们的协作关系
引言 在 Spring 框架中,依赖注入(DI) 是实现松耦合架构的核心机制。Autowired 和 Repository 作为两个高频使用的注解,分别承担着 依赖装配 和 数据访问层标识 的关键职责。本文将深入探讨它们的功能特性、协作模式…...
LeetCode541反转字符串②
思路: 关键是判断反转的右边界, ①当剩余字符数<k,是反转当前所有字符,右边界就是rightlen-1,不可以超过len-1,会越界; ②当剩余字符数>k且<2k,反转k个字符,右边界就是righ…...
Ubuntu 22 Linux上部署DeepSeek+RAG知识库操作详解(Dify方式)之2
上一篇在ubuntu上通过docker拉取了dify并启动与它相关的服务,本篇主要介绍两个知识点: 一是配置模型,使用之前通过Xinference搭建的本地deepseek模型,启动过程参考前期文档,这里就不做介绍了。(注意一点&a…...
如何在多线程中安全地使用 PyAudio
1. 背景介绍 在多线程环境下使用 PyAudio 可能会导致段错误(Segmentation Fault)或其他不可预期的行为。这是因为 PyAudio 在多线程环境下可能会出现资源冲突或线程安全问题。 PyAudio 是一个用于音频输入输出的 Python 库,它依赖于 PortAu…...
Spring MVC与Spring Boot文件上传配置项对比
Spring MVC与Spring Boot文件上传配置项对比 一、Spring MVC配置项(基于不同MultipartResolver实现) 1. 使用 CommonsMultipartResolver(Apache Commons FileUpload) Bean public MultipartResolver multipartResolver() {Common…...
多类型医疗自助终端智能化升级路径(代码版.上)
大型医疗自助终端的智能化升级是医疗信息化发展的重要方向,其思维链一体化路径需要围绕技术架构、数据流协同、算法优化和用户体验展开: 一、技术架构层:分布式边缘计算与云端协同 以下针对技术架构层的分布式边缘计算与云端协同模块,提供具体编程实现方案: 一、边缘节点…...
Chrome 浏览器插件收录
1. Responsive Viewer 可以在同个窗口内,针对同一网站,添加多个不同设备屏幕显示。 在前端开发,需要多端适配,尤其是移动端响应式适配的网站开发中,可以同时测试多个不同屏幕的适配效果。 2. VisBug 提供工具栏&#x…...
力扣hot100_回溯(2)_python版本
一、39. 组合总和(中等) 代码: class Solution:def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:ans []path []def dfs(i: int, left: int) -> None:if left 0:# 找到一个合法组合ans.append(pa…...
文档大模型
处理流程: 对表格或者文章文档切分成chunk,将其存入DB根据chunk文档内容,通过prompt生成问题(qwen)通过sentencetransformer生成embbedding(Text embedding 模型 stella_large 模型,长文本编码), 第二步 抽…...
基于分布式指纹引擎的矩阵运营技术实践:突破平台风控的工程化解决方案
一、矩阵运营的技术痛点与市场现状 风控机制升级 主流平台通过复合指纹识别(Canvas渲染哈希WebGL元数据AudioContext频率分析)检测多账号关联传统方案成本:单个亚马逊店铺因关联封号月均损失$5000,矩阵规模越大风险指数级增长 …...
SpringBoot 统一功能处理
1.拦截器 1.1什么是拦截器 拦截器是Spring框架提供的核心功能之一,主要是用来拦截用户的请求,在用户请求指定的方法执行前后,可以根据业务需要执行实现预定的代码。 通过拦截器,开发人员就可以根据需求针对一些特殊的请求&#…...
Redis到底能不能做主数据库?
张三拍案而起:“Redis 是缓存数据库,怎么能当主数据库用?简直是天方夜谭!” 李四冷笑回应:“你没用过,凭什么说不行?我已经用 Redis 做主数据库好几年了,系统稳定得像铁板一块&…...
C++ 基础进阶
C 基础进阶 内容概述: 函数重载:int add(int x, inty);,long long add(long long x, long long y);,double add(double x, double y);模板函数:template<typename T> 或 template<class T>结构体&#x…...
从C语言到Go语言:新手快速入门指南
对于刚学会C语言的新手来说,学习Go语言(Golang)可能是一个既有趣又有挑战性的过程。Go语言由Google开发,以简洁、高效和并发支持著称,被广泛用于现代软件开发。相比C语言,Go语言在语法上更加现代化…...
Vue.js 中 v-model 的使用及其原理
在 Vue.js 开发中,v-model是一个非常重要且常用的指令。它极大地简化了表单元素与数据之间的双向绑定操作,让开发者能够更高效地处理用户输入和数据更新。接下来,我们将深入探讨v-model的使用场景及其背后的工作原理。 一、v-model 的基本…...
深入解析哈希表:从原理到实现(拉链法详解)
哈希表(Hash Table)是计算机科学中最重要的数据结构之一,它能够在平均 O(1) 时间内完成数据的插入、删除和查找操作。本文将围绕**拉链法(Chaining)**的实现,结合代码示例和图示,深入讲解哈希表…...
okcc呼叫中心系统坐席签入长签和普通签入的区别
在OKCC呼叫中心系统中,坐席的长签(持久签入)与普通签入(常规签入)是两种不同的登录模式,主要区别体现在 会话保持时长、资源占用、业务场景适配性 等方面。以下是具体对比: 一、核心区别对比 维…...
2024年博客之星的省域空间分布展示-以全网Top300为例
目录 前言 一、2024博客之星 1、所有排名数据 2、空间属性管理 二、数据抓取与处理 1、相关业务表的设计 2、数据抓取处理 3、空间查询分析实践 三、数据成果挖掘 1、省域分布解读 2、技术开发活跃 四、总结 前言 2024年博客之星的评选活动已经过去了一个月…...
7.3 在通知中显示图片或视频(UNNotificationAttachment)
在iOS通知中显示富媒体内容可以显著提升用户体验。通过UNNotificationAttachment,我们可以为本地和远程通知添加图片、音频、视频等内容。 基本实现方法 1. 创建带附件的通知 func scheduleNotificationWithImage() {// 1. 创建通知内容let content UNMutableNo…...
1.5-APP的架构\微信小程序的架构
1.5-APP的架构\微信小程序的架构 APP的三种开发架构: 原生态APP类型 APP-开发架构-原生态-IDEA 演示:remusic项目源码 NP管理器: http://normalplayer.top/ HttpCanary:https://github.com/mingww64/HttpCanary-SSL-Magisk 安全影…...
Python缩进完全指南:语法规则、使用场景与最佳实践
一、Python缩进的核心概念 Python的缩进不仅是代码风格问题,更是语法的一部分,这是Python区别于其他编程语言最显著的特征之一。 1.1 什么是缩进? 缩进是指在代码行前添加空格或制表符来实现代码块的层级结构。在Python中,缩进…...
高通音频数据从HAL到DSP
概述 参考高通平台8155 从数据流的角度整理下安卓平台音频数据从HAL层到达DSP这个流程; 以 MultiMedia22 --> QUIN_TDM_RX_0 播放为例; 主要关注pcm数据写到dsp, 以及将前后端路由信息告知dsp两个点。 <!-- more --> [Platform:高通 8155 gvmq Android 11] [Ker…...
第六天 开始Unity Shader的学习之Unity中的基础光照之漫反射光照模型
Unity Shader的学习笔记 第六天 开始Unity Shader的学习之Unity中的基础光照之漫反射光照模型 文章目录 Unity Shader的学习笔记前言一、漫反射光照模型1.逐像素光照① 更改v2f② 传递法线信息给片元着色器③ 片元着色器计算漫反射光照模型 二.半兰伯特模型总结 前言 提示&am…...
【RabbitMQ】队列模型
1.概述 RabbitMQ作为消息队列,有6种队列模型,分别在不同的场景进行使用,分别是Hello World,Work queues,Publish/Subscribe,Routing,Topics,RPC。 下面就分别对几个模型进行讲述。…...
【Java设计模式】第3章 软件设计七大原则
3-1 本章导航 学习开辟原则(基础原则)依赖倒置原则单一职责原则接口隔离原则迪米特法则(最少知道原则)里氏替换原则合成复用原则(组合复用原则)核心思想: 设计原则需结合实际场景平衡,避免过度设计。设计模式中可能部分遵循原则,需灵活取舍。3-2 开闭原则讲解 定义 软…...
Axure中继器(Repeater): 列表展示
文章目录 引言I 中继器说明中继器的作用中继器的结构中继器例子II 中继器基础应用:列表展示表头制作列表内容表头中的列与中继器的列绑定填充数据内容引言 中继器是Axure RP 7.0推出的新功能,用于快速设计一些复杂的交互界面(制作“高保真”的动态原型)。 I 中继器说明 中…...
mybatis的第五天学习笔记
12. 动态SQL 12.1 动态SQL概述 新增内容: 动态SQL执行流程 MyBatis如何解析动态SQLSQL语句构建过程参数绑定机制 新增示例 // 动态条件查询接口示例 List<User> searchUsers(Param("name") String name,Param("age") Integer age,Para…...
LeetCode 941 有效的山脉数组
算法探索:如何精准判断有效山脉数组 在计算机科学领域,算法和数据结构堪称基石,它们不仅是解决复杂问题的有力工具,更是衡量程序员技术水平的重要指标。数组作为最基础、应用最广泛的数据结构之一,围绕它衍生出了大量…...
java设计模式-单例模式
单例模式 1、饿汉式(静态常量) Slf4j public class SingletonTest01 {public static void main(String[] args) {Singleton singleton Singleton.getInstance();Singleton singleton2 Singleton.getInstance();log.info("比对结果:{}",singletonsingl…...
对抗Prompt工程:构建AI安全护栏的攻防实践
大语言模型的开放性与自然语言交互特性使其面临前所未有的Prompt工程攻击威胁。本文通过分析2021-2023年间157个真实越狱案例,揭示语义混淆、上下文劫持、多模态组合三重攻击路径的技术原理,提出融合动态意图拓扑分析(DITA)、对抗…...
CentOS 环境下 MySQL 数据库全部备份的操作指南
最近阿里云个人服务到期,因为是很久之前买的测试机器,配置较低,上面运行的有技术博客 和以往的测试项目,所以准备放弃掉。 需要备份下上面的表结构和数据、以及代码仓库。 下面是一个完整的 CentOS 环境下 MySQL 数据库全部备份…...
回溯算法补充leetcode
1. 组合 leetcode题目链接:77. 组合 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 示例 1: 输入:n 4, k 2 输出: [[2,4],[3,4],[2,3],[1,2],[1,3],[1,4], ] 示…...
利用 AI 实现雷池 WAF 自动化运维
欢迎加入雷池社区:雷池 WAF | 下一代 Web 应用防火墙 | 免费使用 已经升级到 8.4.0 的兄弟们应该会发现雷池又多了一些 AI 能力,8.4.0 更新公告。 感谢 Web2GPT 为雷池提供的 AI 能力支持。 主要变化 右下角多了一个 AI 小助手 按钮右上角多了一个 连…...
【嵌入式面试】
1、如果中断函数中有耗时较长的内容,会导致以下问题,如何解决? 对系统实时性的影响 阻塞低优先级中断:中断函数执行时间过长,会阻塞其他低优先级中断的响应。例如,如果一个高优先级中断处理程序中包含耗时…...
【Hadoop入门】Hadoop生态之HDFS
1 HDFS核心设计原理 HDFS(Hadoop Distributed File System)是专为大规模数据存储设计的分布式文件系统,其核心设计基于以下原则: 数据分块与分布式存储: 分块机制:文件被切分为固定大小的数据块(…...
试剂SYBR 14核酸染料在染色时的操作步骤(说明)
化学试剂的基本内容||试剂参数 ---中文名:SYBR 14核酸染料 ---英文名:SYBR 14 Nucleic Acid Stain ---浓度:通常以5mM的DMSO储存液形式提供。 ---吸收波长:488nm ---发射波长:518nm ---出厂商:西安强…...
Spring Boot 国际化配置项详解
Spring Boot 国际化配置项详解 1. 核心配置项分类 将配置项分为以下类别,便于快速定位: 1.1 消息源配置(MessageSource 相关) 控制属性文件的加载、编码、缓存等行为。 配置项作用默认值示例说明spring.messages.basename指定属…...
Python之禅:深入理解Python设计哲学
Python之禅(The Zen of Python)是Python语言的核心设计哲学,由Python创始人Guido van Rossum和Tim Peters共同制定。理解Python之禅不仅能帮助我们写出更"Pythonic"的代码,还能深入把握Python语言的设计理念。 Python之禅的由来 Python之禅最…...
Rancher 全面介绍
目录 Rancher 全面介绍1. **Rancher 的定义与核心功能**2. **Rancher 的应用场景**3. **Rancher 的生态系统**4. **Rancher 的优势**5. **总结** Rancher 全面介绍 1. Rancher 的定义与核心功能 Rancher 是一个开源的企业级多集群 Kubernetes 管理平台,旨在简化容…...
Docker常用命令
镜像命令 搜索镜像 docker search nginx 拉取镜像 docker pull nginx,默认拉取最新镜像 docker pull nginx:1.25.3,拉取指定版本 查看镜像 docker images 删除镜像 docker rmi nginx:1.25.3 docker rmi -f $(docker images -aq),删除全…...
项目中如何防止超卖
什么是超卖?假如只剩下一个库存,却被多个订单买到了,简单理解就是库存不够了还能正常下单。 方案1:数据库行级锁 1. 实体类 Data TableName("product") public class Product {TableId(type IdType.AUTO)private Lon…...
龙虎榜——20250408
行情如下 根据2025年4月8日的龙虎榜的行业分析如下: 一、农业种植与乡村振兴 • 政策催化:推进种业自主创新、农机装备升级等目标,叠加中美关税反制逻辑。 • 市场表现: • 农业种植:种子类企业因国产替代预期受资…...
快速上手Vue3国际化 (i18n)
文章目录 一、背景介绍二、页面效果三、使用步骤四、代码1.src/App.vue2.src/main.js3.src/locales/index.js4.src/views/login/_request.js5.src/locales/en.json6.src/locales/zh.json7.SystemParam.vue8.I18NController.java9.DataServiceConfigValue.java10.ConfigValue.ja…...
Mistral OCR:重新定义文档理解的下一代 OCR 技术
引言 在数字化时代,文档处理和理解是企业、科研机构以及个人工作流程中的重要环节。然而,传统的光学字符识别(OCR)技术往往难以应对复杂文档中的多语言、多模态内容。近日,法国 AI 明星创企 Mistral AI 推出了一款名为 Mistral OCR 的光学字符识别 API,以其卓越的性能和…...