C++ cmake工程引入qt6和Quick 教程
目录标题
- 前言
- QML简介
- 锻炼C++水平
- cmake修改方法
- 方式一(qt6_add_resources)
- 方式二 (qt_add_qml_module )
- 其他相关知识
- 为什么会有`_other_files`?
- `qt_standard_project_setup()` 函数
- `qt_add_qml_module()` 和 `qt6_add_resources()`的方式差异
- const QUrl url(u"qrc:///Main.qml"\_qs);和const QUrl url(QStringLiteral("qrc:///Main.qml"));的区别
- qt种qrc查找原理
- 使用无前缀的 URL 引用资源文件
前言
在现代软件开发中,跨平台的图形用户界面(GUI)和可视化功能已经变得非常重要。Qt和Qt Quick(基于QML)是强大而灵活的工具,可以帮助开发者快速构建出色的应用程序。然而,当你已经有一个基于C++和CMake的工程时,将Qt和Qt Quick引入可能需要一些指导。
本教程将帮助具有C++和CMake基础知识的开发者将Qt和Qt Quick引入现有的CMake工程。我们将介绍如何设置CMakeLists.txt文件以便使用Qt模块,以及如何在C++和QML代码中实现跨语言的交互。通过本教程,你将能够将Qt和Qt Quick应用到你的项目中,创建出富有吸引力的用户界面和可视化效果。
QML简介
QML是Qt的一种声明式编程语言,用于设计和实现跨平台的用户界面。与Qt Widgets相比,QML具有以下优势:
- 简洁的语法:QML具有简洁、易读的语法,使得创建和修改用户界面变得非常直观。它允许你以更少的代码实现相同的功能,从而提高开发效率。
- 强大的动画和特效支持:QML内置了丰富的动画和特效支持,使得创建具有吸引力的用户界面变得更加容易。你可以方便地为界面元素添加动画效果,提高用户体验。
- 跨平台兼容性:QML可以很好地支持不同平台和设备,使得跨平台应用开发变得更加容易。使用QML,你可以为桌面、移动和嵌入式设备创建统一的用户界面。
- 面向对象的编程:QML支持面向对象编程,允许你创建可重用的组件和模块。这有助于提高代码的模块化和可维护性。
- 与C++的紧密集成:QML可以轻松地与C++代码进行集成,允许你在QML界面中使用C++实现的功能。这使得QML非常适合与现有的C++项目一起使用。
尽管QML具有这些优势,但它并不总是比Qt Widgets更容易实现。实际上,两者之间的难易程度取决于你的需求和经验。Qt Widgets在某些场景下可能更适用,尤其是对于传统的桌面应用程序,以及对性能要求较高的场景。
总的来说,QML在许多方面具有优势,但你应该根据项目需求和个人喜好来选择最适合的技术。如果你对QML感兴趣,我建议你尝试使用它来实现一些简单的项目,以便更好地了解它的特点和优势。
锻炼C++水平
- 使用Qt Widgets:虽然QML是一种强大的界面设计语言,但使用Qt Widgets同样可以创建出优秀的界面,同时更多地使用C++代码。通过使用Qt Widgets,你可以在实际项目中应用和提高C++编程技能。
- 将C++和QML结合:QML和C++可以很好地集成在一起。你可以使用C++编写应用程序的核心逻辑和算法,然后将这些功能暴露给QML以在用户界面中使用。这样,你既能锻炼C++编程能力,又能学习QML的使用方法。
- 参与开源项目:加入一个使用C++的开源项目,可以让你在实际项目中应用和提高C++编程技能。参与开源项目可以帮助你了解更多关于C++的最佳实践和技巧,同时还能扩展你的技术网络。
- 阅读C++相关书籍和教程:阅读高质量的C++书籍和教程可以帮助你深入了解C++语言的特性和最佳实践。一些经典的C++书籍,如《Effective C++》、《C++ Primer》和《The C++ Programming Language》,都是值得一读的好书。
- 解决编程挑战和问题:在网上寻找C++编程挑战和问题,例如LeetCode、HackerRank等平台上的编程题目。这些挑战可以帮助你锻炼编程能力,提高解决问题的速度和效率。
- 学习C++新特性:C++语言一直在不断发展,新的标准和特性会定期推出。关注并学习这些新特性,可以让你保持C++知识的更新,同时提高编程能力。
通过采取这些策略,你可以在实际项目中锻炼和提高C++编程技能。同时,学习QML可以帮助你更好地应对不同类型的项目需求,让你在软件开发领域具有更强的竞争力。祝你在C++和QML的学习过程中取得好成绩!
cmake修改方法
方式一(qt6_add_resources)
要将现有的C++ CMake工程引入Qt6环境并使用Qt和QML,你需要执行以下步骤:
- 安装Qt6:如果你还没有安装Qt6,请从官方网站下载并安装。确保你安装了Qt6的CMake模块。
- 修改CMakeLists.txt:在你的C++ CMake工程中,打开
CMakeLists.txt
文件。首先,确保找到Qt6包,然后链接到需要的Qt6模块。例如,如果你需要使用Qt6 Core、Gui和Quick模块,可以添加以下内容:
然后,将这些模块链接到你的目标(例如,你的可执行文件):find_package(Qt6 COMPONENTS Core Gui Quick REQUIRED)
target_link_libraries(your_target_name PRIVATE Qt6::Core Qt6::Gui Qt6::Quick)
- 添加QML文件:在工程目录下创建一个QML文件夹,将所有QML文件放在该文件夹中。然后,在
CMakeLists.txt
中使用file(GLOB ...)
命令将这些文件添加到工程中。例如:
将QML文件添加到可执行文件的资源文件中:file(GLOB QML_FILES qml/*.qml)
qt6_add_resources(your_target_name "qml"PREFIX"/"FILES${QML_FILES} )
- 创建主入口:在你的C++工程中创建一个
main.cpp
文件(如果尚未创建),并添加以下代码以设置Qt和QML环境:#include <QGuiApplication> #include <QQmlApplicationEngine>int main(int argc, char *argv[]) {QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);QGuiApplication app(argc, argv);QQmlApplicationEngine engine;const QUrl url(QStringLiteral("qrc:/main.qml"));QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,&app, [url](QObject *obj, const QUrl &objUrl) {if (!obj && url == objUrl)QCoreApplication::exit(-1);}, Qt::QueuedConnection);engine.load(url);return app.exec(); }
- 注册C++类:在
main.cpp
中,使用qmlRegisterType
函数注册你的C++类,使其可以在QML中使用。例如:
然后在QML文件中,可以通过以下方式导入和使用你的C++类:qmlRegisterType<YourCppClass>("com.example.yourclassname", 1, 0, "YourCppClass");
import com.example.yourclassname 1.0YourCppClass {// ... }
- 编译和运行:现在你的C++ CMake工程已经集成了Qt6和QML,你可以编译和运行它。如果一切正常,你应该可以看到你的QML界面。
方式二 (qt_add_qml_module )
当然,你也可以使用qt_add_qml_module
函数在CMake项目中添加QML模块。这是一个简化了QML资源添加的便捷方法。下面是如何使用qt_add_qml_module
的步骤:
- 安装Qt6:如果你还没有安装Qt6,请从官方网站下载并安装。确保你安装了Qt6的CMake模块。
- 修改CMakeLists.txt:在你的C++ CMake工程中,打开
CMakeLists.txt
文件。首先,确保找到Qt6包,然后链接到需要的Qt6模块。例如,如果你需要使用Qt6 Core、Gui和Quick模块,可以添加以下内容:
然后,将这些模块链接到你的目标(例如,你的可执行文件):find_package(Qt6 COMPONENTS Core Gui Quick REQUIRED)
target_link_libraries(your_target_name PRIVATE Qt6::Core Qt6::Gui Qt6::Quick)
- 添加QML文件:在工程目录下创建一个QML文件夹,将所有QML文件放在该文件夹中。
- 使用qt_add_qml_module:在
CMakeLists.txt
中,使用qt_add_qml_module
函数将QML文件添加到工程中。例如:
其中qt_add_qml_module(your_target_nameURI com.example.yourclassnameVERSION 1.0QML_FILESqml/main.qml )
your_target_name
是你的可执行文件的目标名称,URI
指定了模块的标识符,VERSION
设置了模块的版本,QML_FILES
列出了所有的QML文件。 - 创建主入口:在你的C++工程中创建一个
main.cpp
文件(如果尚未创建),并添加以下代码以设置Qt和QML环境:#include <QGuiApplication> #include <QQmlApplicationEngine>int main(int argc, char *argv[]) {QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);QGuiApplication app(argc, argv);QQmlApplicationEngine engine;const QUrl url(QStringLiteral("qrc:/qml/main.qml"));QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,&app, [url](QObject *obj, const QUrl &objUrl) {if (!obj && url == objUrl)QCoreApplication::exit(-1);}, Qt::QueuedConnection);engine.load(url);return app.exec(); }
- 注册C++类:在
main.cpp
中,使用qmlRegisterType
函数注册你的C++类,使其可以在QML中使用。例如:
然后在QML文件中,可以通过以下方式导入和使用你的C++类:qmlRegisterType<YourCppClass>("com.example.yourclassname", 1, 0, "YourCppClass");
import com.example.yourclassname 1.0YourCppClass {// ...
其他相关知识
为什么会有<target_name>_other_files
?
这个问题是因为 qt_add_qml_module
函数在将 QML 文件添加到项目时,会创建一个名为 <target_name>_other_files
的辅助目标。这个辅助目标是用于在 Qt Creator 中显示 QML 文件和其他相关文件。这个目标对于构建过程没有影响,也不会生成任何二进制文件。它只是为了在 Qt Creator 中提供更好的文件组织和显示。
qt_standard_project_setup()
函数
qt_standard_project_setup()
函数。这个函数会在内部配置 CMake 以便为 Qt 项目生成一个更简洁的目录结构,这意味着它会自动处理 QML 模块和资源的添加,而不会生成额外的辅助目标。
qt_standard_project_setup()
函数在调用 qt_add_qml_module()
之前已经为项目配置了资源管理,所以你没有看到任何 <target_name>_other_files
目标。
如果你想在自己的项目中使用类似的设置,可以尝试在调用 find_package()
和 add_executable()
之后添加 qt_standard_project_setup()
函数。这样,你可以得到一个更简洁的目录结构,同时保留 Qt Creator 的 QML 模块管理功能。
请注意,qt_standard_project_setup()
函数是 Qt 的一个实验性功能,未来版本的 Qt 可能会对其进行更改或移除。在使用这个函数时,请确保你了解其实现细节,并准备好在将来的 Qt 版本中进行必要的调整。
qt_add_qml_module()
和 qt6_add_resources()
的方式差异
qt_add_qml_module()
和 qt6_add_resources()
都可以将 QML 文件和其他资源添加到项目中,但它们的功能和目标有所不同:
qt_add_qml_module()
:- 是为了简化 QML 模块的创建和管理而设计的。
- 自动生成 QRC 文件。
- 可以指定模块的 URI 和版本,这对于在项目中使用 QML 模块很有用。
- 会创建一个名为
<target_name>_other_files
的辅助目标,用于在 Qt Creator 中显示 QML 文件和其他相关文件,以便于查看和管理。 - 更适合用于包含 QML 模块的项目,可以自动处理 QML 模块的注册和资源管理。
qt6_add_resources()
:- 是一个更通用的函数,用于将资源(如图像、文本文件等)添加到项目中。
- 需要手动创建 QRC 文件。
- 不会创建
<target_name>_other_files
辅助目标,因此在 Qt Creator 中不会有额外的文件显示。 - 适用于不需要 QML 模块特性的项目,或者需要更细粒度控制资源管理的项目。
总的来说,如果你的项目需要使用 QML 模块并希望简化模块的创建和管理,建议使用 qt_add_qml_module()
。如果你的项目只需要将 QML 文件和其他资源添加到项目中,而不需要使用 QML 模块特性,或者希望有更多的控制权,那么 qt6_add_resources()
是一个更好的选择。
const QUrl url(u"qrc:///Main.qml"_qs);和const QUrl url(QStringLiteral(“qrc:///Main.qml”));的区别
两者之间的主要区别在于字符串字面值的表示方法和编码:
-
const QUrl url(u"qrc:///Main.qml"_qs);
这里,
u
前缀表示该字符串字面值为一个 UTF-16 编码的 Unicode 字符串。字符串后面的_qs
用户自定义字面量(User-defined Literal,UDL),它是 Qt 提供的用于将字符串字面值转换为QString
类型的便捷方法。在这种情况下,字符串字面值是一个 UTF-16 编码的 Unicode 字符串,最终转换为QString
类型。 -
const QUrl url(QStringLiteral("qrc:///Main.qml"));
在这里,
QStringLiteral
是一个 Qt 宏,用于在编译时将字符串字面值转换为一个QString
类型的对象。该宏的优势在于避免了在运行时创建QString
对象,从而提高了性能。在这种情况下,字符串字面值是一个普通的字符串,QStringLiteral
将其转换为QString
类型。
在实际使用中,这两种方法都可以实现相同的功能,即创建一个 QUrl
对象来表示资源文件的 URL。只是它们在编译时处理字符串字面值的方式略有不同。考虑到性能和简洁性,推荐使用 QStringLiteral
方法。
qt种qrc查找原理
当您使用 qrc:
前缀引用资源文件时,Qt 会自动查找所有已注册的资源文件。在构建过程中,qt_add_resources()
或 qt6_add_resources()
函数会将资源文件(如 resources.qrc
)编译成二进制文件,并将它们嵌入到最终的可执行文件中。当您在运行时使用 qrc:
前缀引用资源文件时,Qt 会在所有已注册的资源文件中查找匹配的条目。
因此,您不需要在引用资源文件时指定 resources.qrc
,因为 Qt 会自动在所有已注册的资源文件中查找正确的文件。如果您有多个 .qrc
文件,只要确保它们都通过 qt_add_resources()
或 qt6_add_resources()
函数正确注册,Qt 就会在所有已注册的资源文件中查找。
需要注意的是,在使用多个 .qrc
文件时,请确保文件名和路径不会发生冲突,以避免混淆和潜在的错误。
使用无前缀的 URL 引用资源文件
根据 Qt 官方文档,从 Qt 6.2 开始,可以在 QML 代码中省略前缀,但在 C++ 代码中,仍然需要使用 qrc:
前缀来引用资源文件。这是因为 QML 和 C++ 是两种不同的语言,它们有不同的命名规则和语法结构。
在 QML 中,可以使用 import
语句来引用 QML 文件,而不需要使用前缀。但是,在 C++ 中,必须使用 qrc:
前缀来引用资源文件,以便在 QML 中使用。
因此,如果您想在 QML 中使用 C++ 代码,必须在 QML 代码中使用 qrc:
前缀来引用资源文件。如果您只想在 QML 中使用 C++ 代码,则可以省略前缀。
相关文章:
C++ cmake工程引入qt6和Quick 教程
目录标题 前言QML简介锻炼C水平 cmake修改方法方式一(qt6_add_resources)方式二 (qt_add_qml_module ) 其他相关知识为什么会有_other_files?qt_standard_project_setup() 函数qt_add_qml_module() 和 qt6_add_resources()的方式差异const QU…...

JavaEE - 网络编程
一、网络编程基础 为什么需要网络编程? 用户在浏览器中,打开在线视频网站,如优酷看视频,实质是通过网络,获取到网络上的一个视频资源。 与本地打开视频文件类似,只是视频文件这个资源的来源是网络。 相比本…...

【Android车载系列】第11章 系统服务-SystemServer自定义服务
1 编写自定义系统服务 1.1 AIDL接口定义 系统源码目录/frameworks/base/core/java/android/app/下新建AIDL接口IYvanManager.aidl package android.app;/** * 目录:/frameworks/base/core/java/android/app/IYvanManager.aidl */ interface IYvanManager{String …...
Lerna
Lerna Lerna是一个优化基于gitnpm的多pagkage项目的管理工具 解决的痛点 痛点一:重复操作 多Package本地link多Package依赖安装多Package单元测试多Package代码提交多Package代码发布 痛点二:版本一致性 发布时版本一 致性发布后相互依赖版本升级 package越多,管…...
迁移学习 pytorch
迁移学习(Transfer Learning)是通过使用一个预训练模型来快速训练一个新的网络模型,通常应用于数据集较小或计算资源较少的情况下。在 PyTorch 中,由于 torchvision 库中已经内置了一些经典的预训练模型,因此我们可以通过简单的调用函数来实现迁移学习。 下面是一个基于 …...

【python】keras包:深度学习( RNN循环神经网络 Recurrent Neural Networks)
RNN循环神经网络 应用: 物体移动位置预测、股价预测、序列文本生成、语言翻译、从语句中自动识别人名、 问题总结 这类问题,都需要通过历史数据,对未来数据进行预判 序列模型 两大特点 输入(输出)元素具有顺序关系…...

vue框架快速入门
vue 1、第一个Vue程序1.1、什么是Vue程序1.2、为什么要使用MVVM1.3、Vue1.4、第一个vue程序 2、基础语法2.1、v-bind2.2、v-if, v-else2.3、v-for2.4、v-on 3、Vue表单双绑、组件3.1、什么是双向数据绑定3.2、在表单中使用双向数据绑定3.3、什么是组件 4、Axios异步…...

Java连接顺丰开放平台
今天使用Java去访问顺丰的开放平台时,JSON转换一直不成功,最终发现是 可以看到这里是 "apiResultData": "{\"success\": .........它是以 " 开头的!!!如果是对象的话,那么…...

前端三剑客 - HTML
前言 前面都是一些基础的铺垫,现在就正式进入到web开发环节了。 我们的目标就是通过学习 JavaEE初阶,搭建出一个网站出来。 一个网站分成两个部分: 前端(客户端) 后端(服务器) 通常这里的客户端…...

【计算机视觉 | 自然语言处理】BLIP:统一视觉—语言理解和生成任务(论文讲解)
文章目录 一、前言二、试玩效果三、研究背景四、模型结构五、Pre-training objectives六、CapFilt架构七、Experiment八、结论 一、前言 今天我们要介绍的论文是 BLIP,论文全名为 Bootstrapping Language-Image Pre-training for Unified Vision-Language Understa…...

c++基础-运算符
目录 1关系运算符 2运算符优先级 3关系表达式的书写 代码实例: 下面是面试中可能遇到的问题: 1关系运算符 C中有6个关系运算符,用于比较两个值的大小关系,它们分别是: 运算符描述等于!不等于<小于>大于<…...
美术馆c++
题目: 杜老师非常喜欢玩一种叫做“美术馆”的数字游戏,蜗蜗看了之后决定也来试一试,他改编了这个游戏,规则如下: 有一个 n� 行 m� 列的方格,每一个格子中有一个数,数字…...

浅谈MySQL索引以及执行计划
MySQL索引及执行计划 🐪索引的作用🐫索引的分类(算法)🦙BTREE索引算法演变🦒Btree索引功能上的分类4.1 辅助索引4.2 聚集索引4.3 辅助索引和聚集索引的区别 🐘辅助索引分类🦏索引树高…...

在c++项目中使用rapidjson(有具体的步骤,十分详细) windows10系统
具体的步骤: 先下载rapidjson的依赖包 方式1:直接使用git去下载 地址:git clone https://github.com/miloyip/rapidjson.git 方式2:下载我上传的依赖包 将依赖包引入到项目中 1 将解压后的文件放在你c项目中 2 将rapidjson文…...
编译方式汇总:Makefile\configure\autogen.sh\configure.ac、Makefile.am文件
一、前言 文章目的:针对各种开源项目,由于部分项目文档写的不够详细,(或者是我太菜了),没有进行详细的介绍怎么编译该项目,导致花费过多时间在查找如何编译该项目上。因此该篇文章针对目前遇到的…...
explicit关键字
explicit关键字只能用来修饰构造函数。使用explicit可以禁止编译器自动调用拷贝初始化,还可以禁止编译器对拷贝函数的参数进行隐式转换。 那么什么是隐式转换呢? 类 命名 参数; //有参构造类 命名 命名对象; //拷贝构造&#x…...
[优雅的面试] 你了解python的对象吗
前情提要:小编面试,结果面试官着急去吃饭~又约了这次来面,不晓得又会问什么问题呢? 面试官大佬:小伙子来的挺准时的(赞赏的表情~),今天咱们接着聊哈,小伙子,你有对象了没?…...

【hello Linux】线程概念
目录 1. 线程概念的铺设 2. Linux线程概念 2.1 什么是线程 2.2 线程的优点 2.3 线程的缺点 2.4 线程异常 2.5 线程用途 3. Linux进程VS线程 4. Linux线程控制 4.1 POSIX线程库 4.2 创建线程 4.3 进程ID和线程ID 4.4 线程终止 4.5 线程等待 4.6 分离线程 Linux🌷 1…...

JavaWeb07(MVC应用01[家居商城]连接数据库)
目录 一.什么是MVC设计模式? 1.2 MVC设计模式有什么优点? 二.MVC运用(家居商城) 2.1 实现登录 2.2 绑定轮播【随机三个商品】 2.2.1 效果预览 index.jsp 2.3 绑定最新上架&热门家居 2.3.1 效果预览 2.3.2 代码实现 数据…...
如何使用电商API接口API接口如何应用
使用API接口 API(应用程序接口)是现代软件开发中必不可少的一部分,它通常允许软件与其他软件或服务进行交互。使用API可以大大提高软件的灵活性和可扩展性,并允许您轻松添加新的功能和服务,因此,API接口的…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...

k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...

企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...

Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...