一文入门Qt Quick

news/2024/5/3 17:11:22/文章来源:https://www.cnblogs.com/englyf/p/16733091.html

以下内容为本人的著作,如需要转载,请声明原文链接 微信公众号「englyf」https://www.cnblogs.com/englyf/p/16733091.html


初识Qt Quick

很高兴可以来到这一章,终于可以开始讲讲最近几年Qt的热门技术Quick这一块了。

啥是Qt?

哦,这是一个宣称可以跨任意平台,开发各种场景应用软件的开发框架。从三个维度来讲,就是开发库framework,集成开发平台IDE,以及成熟的开发思维模式。

Qt Quick最早出现在Qt的4.7版本中,目标是在UI设计者与开发者之间搭建一个更高效合作平台,给开发者更好的UI开发体验。虽然几经易手,Qt在digia公司这些年的努力迭代更新下,Qt Quick终于迎来了成熟稳定的版本(这也是我愿意在最近的项目里转用它的原因)。

至于Qt Quick和老一套开发核心Qwidget的区别,其中最重点的就是提供了新的UI描述语言QML(Qt Meta-object Language,Qt元对象描述语言)。QML乍看起来有点像json,但是核心思想却是模仿web页面。没错,在QML文件中允许搭配Javascript代码,就可以辅助实现丰富的UI交互逻辑。

如果你以往习惯QWidget开发,那么Qt Quick真的非常值得上手试试。

好了,口水吐多了招人厌,下面直入庐山一窥真面目!

手剥一个简单的功能程序开发栗子

在Qt开发过程中,Qt官方IDE(Qt Creator)提供了好几种工程构建工具,比如简单易懂的qmake,火上天的cmake,还有貌似没人听说过的Qbs。而目前Qt主推的构建方式就是cmake,下面要讲的例子也是用cmake。

1.开发环境配置

Win10
Qt 6.2.4
Qt Creator 8.0.1
Mingw 11.2.0 64bit
Cmake 3.23.2

这里选用的Qt版本是写作时最新的LTS版本,LTS意思就是官方长期支持更新。比如说,一两年内还会发布一下补丁和安全更新,至于新功能特性就别想了。

2.创建Qt Quick工程

先用Qt Creator创建一个简单的quick工程,工程构建描述的内容就保存在工程根目录的配置文件CMakeLists.txt中,如下:

cmake_minimum_required(VERSION 3.16)project(instance VERSION 0.1 LANGUAGES CXX)set(CMAKE_AUTOMOC ON)
#set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD_REQUIRED ON)find_package(Qt6 6.2 COMPONENTS Quick REQUIRED)file(GLOB_RECURSE SOURCE_FILES./src/*.cpp./src/*.h
)qt_add_resources(SOURCE_FILES instance.qrc)qt_add_executable(instance${SOURCE_FILES}
)set_target_properties(instance PROPERTIESMACOSX_BUNDLE_GUI_IDENTIFIER my.example.comMACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}MACOSX_BUNDLE TRUEWIN32_EXECUTABLE TRUE
)target_link_libraries(instancePRIVATE Qt6::Quick)install(TARGETS instanceBUNDLE DESTINATION .LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})

cmake_minimum_required用于声明当前的配置文件适用于的cmake最低版本,同时为了防止使用过于低级的版本来构建当前工程,避免某些指令不支持或者不兼容。

project用于声明当前工程名称,和开发语言。CXX代表了C++。

CMAKE_AUTOMOC用于标记是否开启自动MOC。Qt不仅仅是开发库,它同时也对开发语言(比如C++)做了拓展,那么源码文件中就会多多少少会包含有通用编译器无法识别的部分内容。MOC就是用于对Qt的扩展内容进行转换的工具。

CMAKE_AUTORCC用于标记是否开启自动RCC。在Qt工程中会包含有被最终输出的执行程序所需要的资源内容,比如音视频,图片等等。那么为了高效调用这些资源,势必需要对原本的资源文件进行处理再保存到额外的二进制文件中,甚至内嵌到执行文件中。RCC就是对这些资源文件进行处理和再输出工具。

由于我的例子工程中需要用到MOC和RCC,所以CMAKE_AUTOMOCCMAKE_AUTORCC都打开。

CMAKE_AUTOUIC用于标记是否开启自动UIC。如果开发界面用的技术栈是QWidget,那么在Qt工程中就需要创建.ui文件并保存设计内容到其中,编译的时候也需要用UIC把.ui文件转换成.h文件。不过,这里用Quick技术栈开发界面,因此无需打开CMAKE_AUTOUIC,在最前面添加#表示注释掉该行语句(该行语句会被解析器忽略)。

find_package导入Qt的Quick模块。

由于本工程需要用到多个C++源文件,所以这里采用了递归引用文件的方式把特定文件夹下面的所有.cpp、.h等文件都囊括进来,需要辅以通配符*。所有被囊括的文件路径被追加到动态数组SOURCE_FILES中,方便后边引用。语法格式如下:

file(GLOB_RECURSE <variable> [FOLLOW_SYMLINKS][LIST_DIRECTORIES true|false] [RELATIVE <path>][<globbing-expressions>...])

格式里的variable实际使用SOURCE_FILES代替。

qt_add_resources的作用是调用RCC对资源文件(.qrc)编译成qrc_开头的源文件再输出,并且把输出的源码文件路径追加到动态数组SOURCE_FILES中。

当然,动态数组SOURCE_FILES这个名字可以按照需求自定义设定,这里取名为源文件。

qt_add_executable指明构建的目标是二进制文件instance,引用的源文件来自于动态数组SOURCE_FILES。

target_link_libraries用于指明构建时链接Qt6::Quick的相关库。

剩余的语句都是Qt Creator创建工程时自动添加的内容,这里略过。

然后看看我的工程目录结构在Qt Creator中的展示:

如果用VSCODE打开工程目录,可以看到:

3.使用元对象描述文件(QML)描述界面

使用Qt Creator自动创建的Quick应用,除了会自动生成配置文件CMakeLists.txt之外,还包含了main.cpp和main.qml文件,源码只实现了启动之后弹出一个窗口。

这里稍作修改,实现简单的文件选择,以及将选中的文件路径名显示出来。这个功能用QWidget技术栈来实现其实是很简单的啦,不过我们这里目的是演示Quick技术框架怎么用,所以下面来具体看看界面这块怎么玩:

1)主页面

// main.qml

import QtQuickWindow {width: 640height: 200visible: truetitle: qsTr("Tool V1.0.0")Viewer {anchors.fill: parent}
}

main.qml 这个文件是首页元对象的描述文件,一般QML引擎加载的第一个元对象所在的文件就命名为main.qml。不过,命名为main.qml不是硬性规定。

首先,可以看到这里通过import导入了模块QtQuick。同一行,后边还可以加上版本号。

Window是一种模块里预定义的类型,用于窗体描述。当然,类型也可以自定义,下面会说到。这里通过对类型Window的实例化来描述一个窗体对象。

类型后边的{}内部包含了类型实例化后的成员属性、函数、信号、信号处理句柄等,比如width、height、visible、title等都是预定义的属性,这些属性如字面意思比较简单易懂就不一一展开了,大伙要是有兴趣可以反馈给我,我再看看意见给大家细聊。

Viewer其实是自定义的类型,这里通过对类型Viewer的实例化来补充添加新的界面元素。Viewer对象内部的属性anchors.fill: parent描述的是对象在其父对象(Window)中把父对象填充满。QML一般通过anchors属性来锚定对象的位置。

上面这个对象里并没有定义或者引用到函数或者信号等。

2)自定义类型

下面来看看怎么自定义类型

// Viewer.qml

import QtQuick 2.15
import QtQuick.Controls 6.2
import Qt.labs.platform 1.1Item {function log(...msg) {let msgs = "";msg.forEach((item) => {if (msgs.length != 0) {msgs += " ";}msgs += item;});console.log(msgs);}FileDialog {id: fileDialogobjectName: "fileDialog"currentFile: selectedFileTextArea.textonFileChanged: {log(objectName + ".file =", file.toString().slice(8));fileMgrInstance.run(file.toString().slice(8));}}Label {id: fileLablex: 292y: 26text: qsTr("文件:")verticalAlignment: Text.AlignVCenterfont.pointSize: 14}TextField {id: selectedFileTextAreax: 70y: 70width: 500objectName: "selectedFileTextArea"text: fileDialog.file.toString().slice(8)font.pointSize: 12placeholderText: qsTr("选择文件")}Button {id: selectFileButtonx: 268y: 124width: 105height: 54text: qsTr("选择")font.pointSize: 10onClicked: {log(text, "clicked");fileDialog.open();}}
}

Item是类库QtQuick的预定义组件类型,描述的是一个基础可视组件,quick中所有的可视组件都继承于它。

一般在QML中自定义类型都会使用基础的类型Item,然后在其基础上定制内部属性、函数、信号、信号处理句柄等。

Item的继承链是这样的:

Item -> QtObject -> QObject

看到这里,可以猜测一下,其实所有的Quick预定义组件都是继承于QObject,和QWidget里提供的类库太相似了。

function log(...msg)定义了函数log,function是关键词,log是函数名,后边小括号里的...表示参数不定,这样子在调用log时就可以不限制输入的参数个数了。

要注意的是,QML内部的函数使用的语法是ECMAScript,也就是我们常常听到的JavaScript。

FileDialog是类库Qt.labs.platform的预定义组件类型,描述的是一个文件选择窗口。属性id,继承于QObject,用于标记唯一的对象,也就是说所有对象的id都不能重复,无论对象是否处于同一个QML文件。objectName描述的属性可用于对对象树中的对象进行查找。currentFile描述了当前选中的文件名(包括路径),在确定最后选中的文件之前,此属性也会跟随选择而改变。onFileChanged描述了当属性file值改变时,自动产生的信号的处理句柄(handle),用{}限定处理范围。log是上面定义的函数调用,输入两个参数。fileMgrInstance是C++源文件暴露给QML引擎的特定对象id,通过该id可以调用C++中的相应对象的方法属性(代码中调用了run方法,方法的详情定义看下文)。

C++和QML源文件之间的对象相互调用,会有后续的文章专门介绍,这里不再细聊,敬请关注。

Label是类库QtQuick.Controls的预定义组件类型,描述的是一个文本标签。x、y描述的是坐标。text描述的是显示文本。qsTr()用于标识文本可被翻译,类似Qt C++里的tr()。verticalAlignment描述的是垂直排列方式,这里的属性值标识垂直中间排列。font.pointSize描述字体的大小。

TextField是类库QtQuick.Controls的预定义组件类型,描述的是一个单行文本编辑窗。width是几何宽度。placeholderText描述的是占位符。

Button是类库QtQuick.Controls的预定义组件类型,描述的是一个可点击的按键。height描述的是几何高度。onClicked描述了当信号clicked发生时,该信号的处理句柄(handle),用{}限定处理范围,这里调用了上面的文件选择窗的打开函数。

信号的处理句柄(handle)中,在on后边书写时信号的首字母需要大写。

3)预览界面

什么?代码没写完就可以预览界面了?

是的,QML文件支持用工具预览,非常方便于UI设计过程中的调试。

打开预览的方式是调用qmlscene或者用Qt Design Studio,如下图用的是qmlscene。

看看Viewer.qml页面预览的实际效果。

4.使用C++代码实现逻辑处理

Qt Quick使用QML的目的是为了简化界面的设计开发,而软件除了界面的互动之外还有大量的后台逻辑处理功能也需要实现,针对这块业务,Qt其实还是推荐使用C++,正所谓术业有专攻,毕竟C++对性能的利用还是有两把刷子的。废话不多说,马上看下文。。。

既然如此,那么就来看看负责逻辑处理功能的C++代码部分。不过,这里假设各位看官已经熟悉C++的各项业务技能,所以下面只针对和QML对象的互动来简单介绍一下。

后续也会有更加详细的专题文章介绍这部分,敬请留意哈!

1)QML对象的加载和C++对象传递

QML对象的创建和展现是通过QML引擎来加载的,一般每个程序会由单个引擎对象负责管理。不过,QML引擎对象不是直接管理QML对象,而是通过管理上下文(context)对象来分别管理QML对象。所以在C++里边如果需要往QML对象传递信息也是直接传给对应的上下文对象,然后再在QML对象中通过传入对象时指定的id名调用对应的方法属性。

// main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "./FileMgr/FileMgr.h"int main(int argc, char *argv[])
{QGuiApplication app(argc, argv);QQmlApplicationEngine engine;const QUrl url(u"qrc:/src/QML/main.qml"_qs);QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,&app, [url](QObject *obj, const QUrl &objUrl) {qInfo("%s start\n", QCoreApplication::applicationName().toLatin1().data());if (!obj && url == objUrl)QCoreApplication::exit(-1);}, Qt::QueuedConnection);FileMgr fileMgr;engine.rootContext()->setContextProperty(QStringLiteral("fileMgrInstance"), &fileMgr);engine.load(url);return app.exec();
}

上面的main.cpp文件代码中,把对象fileMgr传入引擎的根上下文中,并设定id为fileMgrInstance。传入根上下文,意味着引擎加载的所有QML对象都可以通过id=fileMgrInstance访问fileMgr对象内容。这里要注意,fileMgr对象是在C++源码中实例化了的。

把C++对象暴露给QML对象的方法,除了上面这种通过上下文的方式外,还有一种是通过直接往元对象系统(Meta-Object System)注册类型的方式,这种方式也是最根本的方式,因为Qt Quick框架的底层实现原理就依赖于元对象系统。

使用的接口原型:

template <typename T> int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)

如果通过这种注册的方式实现,上面的栗子可以掰成这样:

 qmlRegisterType<FileMgr>("com.englyf.qmlcomponents", 1, 0, "FileMgrItem");

根据上面的定义,com.englyf.qmlcomponents是命名空间,1.0是命名空间的版本号,FileMgrItem是QML中的类型名。

然后在QML文件内,导入并实例化这个类:

 import com.englyf.qmlcomponents 1.0FileMgrItem {// ...}

要强调的是,通过注册的方式,类型的实例化会放在QML里边做,而C++源码就不需要再对类FileMgr作实例化了

2)C++类型的定义

既然Qt Quick依赖于元对象系统,那么对C++类型的定义就有必然的要求了。

C++类型需要继承于QObject,并且类开头应该声明宏Q_OBJECT,这样才可以使用元对象系统提供的服务,包括信号槽机制等等。

需要被QML对象调用的方法应该添加修饰Q_INVOKABLE。这个修饰符表明该方法可被元对象系统调用。同时,该方法的参数类型和返回类型,都推荐使用类型QVariant。

如有开放给QML对象的可访问属性,那么也需要对属性声明为Q_PROPERTY。这里暂不举例,可关注后续的专题文章。

// FileMgr.h

#ifndef FILEMGR_H
#define FILEMGR_H#include <QObject>
#include <QVariant>class FileMgr : public QObject
{Q_OBJECT
public:explicit FileMgr(QObject *parent = nullptr);Q_INVOKABLE QVariant run(QVariant file);
};#endif // FILEMGR_H

// FileMgr.cpp

#include "FileMgr.h"FileMgr::FileMgr(QObject *parent): QObject{parent}
{}QVariant FileMgr::run(QVariant file)
{QString fileStr = file.toString();qDebug("C++ get file:%s selected", fileStr.toStdString().data());return 0;
}

自动化部署

这部分讲点高级的内容,以往看到网上的教程都是教初学者部署的时候,进入exe生成的目录,然后手动调用windeployqt执行部署。这个程序是Qt自带的,会自动把所有依赖的动态库拷贝过来存放在指定目录下。

这里就介绍一下怎么在Qt Quick软件工程编译结束时自动部署所有依赖项。

首先,debug开发模式下是不需要部署软件的,那么我们就先切换到release模式下。

然后,在Build的步骤下,Build步骤之后新添加一个Custom Process Step的步骤。

我把配置都拷过来:

Command:            windeployqt
Arguments:          --qmldir %{ActiveProject:NativePath}\src\QML\ %{ActiveProject:RunConfig:Executable:NativeFilePath}
Working directory:  %{Qt:QT_INSTALL_BINS}

由于Qt Quick工程涉及到QML文件,所以这里需要带上选项--qmldir,这个选项后边紧跟着参数值是代码工程中存放自定义的QML文档的根目录。

%{ActiveProject:NativePath}代表着当前工程的主目录的本地化路径。

%{ActiveProject:RunConfig:Executable:NativeFilePath}代表着当前工程的exe文件输出目录的本地化路径。

Working directory项意思是Command命令的工作目录,这里填上%{Qt:QT_INSTALL_BINS},代表Qt安装目录下的bin目录。

按照上面的介绍过程配置完整,以后如果需要部署输出,只需要切换到release模式下,然后点击编译,等编译完成就会自动进入部署流程,整个过程就是这么舒心。

生活简单才是美好,部署也不例外!


到最后,一起来看看跑起来的程序:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_14339.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

m基于matlab的光通信的信道估计,均衡,抑制papr误码率仿真,对比ZF,RLS,MMSE三种算法(包括matlab仿真录像)

目录 1.源码获取方式 2.算法描述 3.部分程序 4.部分仿真图预览 1.源码获取方式 使用版本matlab2013b 获取方式1&#xff1a; 点击下载链接&#xff08;解压密码C123456&#xff09;&#xff1a; m基于matlab的光通信的信道估计&#xff0c;均衡&#xff0c;抑制papr误码…

libxml编译时问题解决记录

在对libxml进行模糊测试时&#xff0c;需要先将其拉去并进行编译&#xff0c;可参考此链接&#xff1a;magma本地编译 或者直接参考这个链接&#xff1a;magma编译libxml2 然而在编译的过程中&#xff0c;拉去完libxml2执行到这一句时报错如下&#xff1a; configure.ac:42: e…

Python骚操作,实现驾考自动答题,这就直接满分了?

Python骚操作来了~ 用Python来实现科目一/四自动答题&#xff0c;100分不要太简单&#xff01; 最初是表弟最近想买车&#xff0c;但是驾照都没有&#xff0c;买什么车&#xff0c;只能先考驾照~ 看他在网页上练习题目慢吞吞的&#xff0c;我就看不下去了&#xff0c;直接给他…

《数据结构》队列及其经典面试题

前言 上一篇讲了栈和栈的经典面试题&#xff0c;链接如下&#xff1a; 栈与栈的经典面试题 其实栈和队列是一码事&#xff0c;都是对只能再线性表的一端进行插入和删除。 因此&#xff0c;其实栈和队列可以互相转换&#xff01; 一、队列的特点 先进先出的数据结构&#…

Android系统安全 — 2.0-移动终端栈溢出的保护机制设置

简介 操作系统提供了许多安全机制来尝试降低或阻止缓冲区溢出攻击带来的安全风险。例如 NX/DEP、 ASLR&#xff08;PIE&#xff09;、CANARY、FORTIFY、RELRO 等手段。 栈保护 1.NX/DEP Linux 和 Windows 平台都支持对非可执行代码的保护&#xff0c;在 Linux 平台中被称为…

【Mybatis框架】初识Mybatis

CSDN话题挑战赛第2期 参赛话题&#xff1a;学习笔记 MyBatis1、MyBatis简介1.1、MyBatis历史1.2、MyBatis特性2. 搭建MyBatis2.1 创建一个Maven项目2.2 在项目下新建我们的MyBatis项目2.3 引入依赖2.4 创建MyBatis的核心配置文件2.5 创建mapper接口2.6 创建MyBatis的映射文件2.…

AWS 中文入门开发教学 34- MySQL@RDS - 准备工作 - VPC子网,安全组,DB子网组,参数组,选项组

知识点 建立RDS MySQL前的准备工作实战演习 VPC子网,安全组,DB子网组,参数组,选项组 VPC子网 Name: deeplearnaws-db-1cCIDR: 172.16.21.0/24 安全组 Name: deeplearnaws-db-sg <- 可以直接使用之前创建的,但生产环境时应只保留3306端口 DB子网组 Name: deeplearnaws-db-su…

JavaScript学习Day008(jQuery操作)

DOM操作分类 DOM操作分为三类 DOM Core&#xff1a;任何一种支持DOM的编程语言都可以使用它&#xff0c;如getElementById() HTML-DOM&#xff1a;用于处理HTML文档&#xff0c;如document.forms CSS-DOM&#xff1a;用于操作CSS&#xff0c;如element.style.color"gree…

【NLP】第12章 检测客户情绪以做出预测

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

JavaScript数组与对象

数组对象 「创建数组的两种方式」 1. 字面量方式var arr [1,"test",true];2. 实例化数组对象 new Array() var arr new Array(); 注意&#xff1a;上面代码中arr创建出的是一个空数组&#xff0c;如果需要使用构造函数Array创建非空数组&#xff0c;可以在创建数…

SpringCloud-19-Spring Cloud Hystrix介绍和服务端降级

8 Hystrix&#xff1a;Spring Cloud服务熔断与降级组件 8.1 分布式系统面临的问题 复杂分布式体系结构中的应用程序往往由多个服务组成&#xff0c;这些服务之间相互依赖&#xff0c;依赖关系错综复杂&#xff0c;每个依赖关系在某些时候将不可避免的失败&#xff01; 若一个…

最优化理论与方法2

凸优化问题&#xff1a; 对于最优化问题P&#xff1a; min f(x1, x2 , …,xn) s.t. : gi ( x1 , x2 , … , xn) < 0 , i 1 , … , m hi ( x1 , x2 , … , xn) 0 ,i 1 , … , l 1 . 记可行域为S { x ∈ Rn | gi(x)<0 , i1,…,m , hi(x)0 , i 1 , … , l.} 2.当f(x…

交通流域关键词

关键词&#xff1a; ●交通拥堵&#xff1a;traffic jam 或 traffic congestion ●元胞传输模型&#xff1a;cellular transport model 或 cell transport model(细胞传输模型) ●元胞自动机&#xff1a;cellular automata ●VSL(可变速度限制)&#xff1a;variable speed …

Python3 安装软件出现 cl.exe failed with exit status 2 错误

最近因项目需要&#xff0c;开始深入接触python。遇到的一些环境问题&#xff0c;分享下。 requirements.txt中包含一系列所需组件&#xff0c;部分组件安装会报cl.ext错误。 如错误问题&#xff1a;Python3 安装pycrypto 2.6.1 出现 cl.exe failed with exit status 2 错误 …

Android国际化多语言切换

关于App国际化&#xff0c;之前有讲到国际化资源、字符换、布局相关&#xff0c;想要了解的猛戳用力抱一下APP国际化。借着本次重构多语言想跟大家聊一下多语言切换&#xff0c;多语言切换对于一款国际化App来讲是重中之重&#xff0c;并非难事&#xff0c;但是若要做好也是一件…

LeetCode-136-只出现一次的数字

1、哈希表 利用哈希表记录每个元素和其出现的次数&#xff0c;最后遍历哈希表找到只出现一次的数字。缺点在于额外空间为O(n)O(n)O(n)。 class Solution { public:int singleNumber(vector<int> &nums) {unordered_map<int, int> hs;for (auto i: nums) {hs[…

疫情下低代码平台将是企业的曙光

全球疫情的爆发&#xff0c;加速了企业数字化转型进程&#xff0c;为了响应不断变化和增加的业务需求&#xff0c;需要充足的资金以及专业的开发人员才能够有效推行数字化管理。然而在这样的情景下&#xff0c;人员的缺少&#xff0c;时间的效率等问题&#xff0c;导致很多企业…

图像分类数据集(线性神经网络,需结合从零实现softmax回归一起学习)

文章目录图像分类数据集读取小批量整合所有组件小结图像分类数据集 导入必要的类包。 import torch import torchvision from torch.utils import data #torchvision是pytorch的一个图形库&#xff0c;它服务于PyTorch深度学习框架的&#xff0c;主要用来构建计算机视觉模型。…

Kafka设计原理——副本数据同步机制(watermark 和 leader epoch)

文章目录LEO更新机制follower副本LEO更新leader副本LEO更新HW更新机制follower更新HWleader更新HW使用HW衡量数据同步情况的缺陷LEO更新机制 follower副本LEO更新 Kafka设计了两套follower副本LEO属性&#xff0c;一套LEO值保存在follower副本所在的broker缓存上&#xff1b;…

详解 B2B 用户、组织、员工、角色

整理了一下 toB 多组织系统中常见的实体关系&#xff0c;往往在实际项目中这些基础模块是公司老前辈已经开发完成的&#xff0c;因此新人在此基础上开发一些相关的业务模块很容易被这些模糊不清的关系搞晕。 一、定义 user 用户&#xff0c;操作者的唯一标识&#xff0c;通常…