Qt 窗口

在Qt Creator 中创建项目的时候,我们能够选择创建QMainWindow 还是 QWidget 两种窗口。

二者有什么区别呢?其中 QMainWindow 是一种主窗口,包含菜单栏,工具栏,状态栏,中心窗口和浮动窗口等多个窗口组合,它继承自QWidget类,提供了一个预定义的布局。这就是二者的区别。 

一个成熟的窗口,必然包含菜单栏、工具栏、状态栏等多个窗口组合在一起,因此我们使用 Qt 创建一个窗口时,必然需要考虑这些要素,那么本文我们就来学习如何创建一个成熟的Qt窗口吧。

菜单栏

Qt 中,菜单栏采用 QMenuBar 这个类实现,一个菜单栏中可以包含多个菜单,而一个菜单中又包含多个菜单项或者子菜单。

  • QMenuBar : 菜单栏类
  • QMenu:菜单类
  • QAction : 菜单项类

我们可以通过 Qt Designer 来创建一个菜单栏。(注意,必须是 QMainWindow 才行)

 在 Qt Designer 中的左上角,点击 "在这里输入即可在菜单栏这里添加菜单,添加完菜单后即可点击下面的 "在这里输入" 即可添加菜单项,也可以继续输入来添加子菜单。

不过这里有一个 Bug,即无法输入中文,只能采用复制粘贴的方式来输入中文。

添加菜单栏、菜单和菜单项 

此外,也可以通过代码的形式来添加菜单。

 

能够获取到确实添加了菜单栏、菜单和菜单项。 

添加快捷键

在 Qt 的菜单栏中,我们可以通过快捷键来快速选取,比如下面的菜单可以通过 Alt + F 来选取文件菜单Alt + E 来选取编辑菜单按下对应的快捷键直接选取菜单项,我们也能够自行设置快捷键方便我们使用。

和 label 控件一样,都是通过 & + 快捷键的方式来设置对应的快捷键,这样就能够通过 Alt + 快捷键的方式选中菜单了。不过有一点需要注意,同时出现的快捷键之间不能重名,比如菜单之间的快捷键不能相同,但是不同菜单下的菜单项的快捷键可以相同。

 

三个菜单项被选中就会输出对应的消息。 

可以看到确实被选中了并且输出了消息。

添加子菜单

一般菜单中也会嵌套子菜单,比如 Qt 的文件中,就存在访问最近打开文件的子菜单,我们也能够手动添加子菜单。

先创建一个新的 QMenu 对象,并且添加菜单项,然后将该 QMenu 对象添加到某个菜单下面,就添加了一个子菜单。

 这样就能够看到一个子菜单。

添加图标

有的窗口能够显示出图标,比如浏览器的收藏夹。

这些网站就有它们自己的图标,我们也能给自己的菜单添加图标。

 通过 qrc 机制获取图片,然后设置给对应的菜单项。

可以看到图标已经被设置好了。 

 不过一般菜单是不设置图标的,比如这里可以看到给一个菜单设置了图标。

但是图标将文字覆盖了,因此菜单不设置图标。 

添加分割线

QMenu 类中有一个函数叫 addSeparator() ,它会添加一个分割线。

比如这里在添加菜单项的时候,中间添加一个分割线。

能够看到在保存和打开之间多出了一条很浅的分割线。 

 QMenuBar 的一些问题

在上面的代码中,我们都是先创建一个 QMenuBar,然后再设置即可,但是这是有一点问题的。

在创建项目的时候,没有勾选自动生成ui文件的时候,这里是没问题的,而如果勾选了生成 ui 文件的时候,就会出现内存泄漏,比如我这里是勾选了自动生成 ui 文件了的。

Qt 会自动生成一个 QMenuBar 对象,并且挂在 MainWindow 上,而如果按照我上面的代码写,那么我们手动生成的 QMenuBar 对象就会替换掉自动生成的 QMenuBar 对象,这个自动生成的 QMenuBar 就不存在对象树上了,那么它就无法自动释放,就会造成内存泄漏。

为了针对这个问题,我们可以采用其他方式创建 QMenuBar 对象。

即通过 this->menuBar() 来获取this自带的menuBar,如果自动生成了,那么我们就获取到了这个 menuBar,没有创建新的资源,自动生成的 menuBar 就不会出问题了。

而如果没有自动生成 menuBar,就会自动生成然后返回。

 这样两者方式都没有造成内存泄漏。

工具栏

工具栏一行包含一系列快捷工具,一般都是菜单栏中的常用菜单项,因此工具栏的工具项一般和菜单项都采用 QAction 类,都是通用的。

而一个窗口可以含有0个或者多个工具栏,这些工具栏的位置可以随时拖动修改,也就是所谓的浮动态。

创建工具栏并添加工具

和菜单栏不同,工具栏能够同时存在多个,因此添加工具栏的函数是 addToolBar 而非 setToolBar

而工具项和菜单项都是类似的,因此都是用的 QAction 类。

设置工具栏位置

工具栏和菜单栏不同,工具栏可以自由设置不同的位置,在添加工具栏的时候可以设置位置。 

 一般可以添在四种位置,默认在上方。

  • Qt::LeftToolBarArea  :  左侧
  • Qt::RightToolBarArea : 右侧
  • Qt::TopToolBarArea : 上侧
  • Qt::BottomToolBarArea : 底侧
  • Qt::AllToolBarArea : 四个位置都能停靠

除了在添加工具栏的时候 ,我们也能够设置工具栏允许停靠的位置。

通过 setAllowedAreas 可以设置允许其停靠的位置,比如下面的代码就允许停靠 左右区域。

可以发现,虽然刚开始的时候工具栏在上方,但是一旦拖动之后就无法回到上方了。 

  • addToolBar : 是设定初识工具栏的位置
  • setAllowedAreas : 是设定允许工具栏停靠的位置 

其中,工具栏没有固定在某个位置时,称为浮动态,能不能浮动我们也能设置。 

设定工具项的图标

给工具栏添加工具项的时候,也可以为他设置图标,毕竟大部分工具都是采用图标显示的。

不过图标会覆盖工具项的文字,此外,最初设置的文字会变成工具项的 toolTip,即提示。

我们也能通过 setToolTip 函数设置提示信息。

设置工具栏的浮动属性

工具栏并不唯一,我们可以设置多个工具栏。

可以看到,不同的工具栏的前面都有一根竖着的线。

拖拽该线即可移动工具栏,如果拖动的工具栏没有固定在某个方向,那么该工具栏就会变成浮动态,我们也可以通过手动设置是否允许浮动。

比如这里设置 toolbar1 不可浮动。

发现第一个工具栏无法浮动 

 

设置工具栏的移动属性 

这里设置工具栏2 的移动属性为false。 

发现第二个工具栏直接没有移动的选项了。 

 

状态栏 

状态栏是位于窗口底层,用于显示程序的一些简单信息的区域。

它可以显示实时消息、永久消息或者进度条消息等。

状态栏的创建

和菜单栏一样,一个窗口只能有一个状态栏,因此它的创建只能通过 setStatusBar 设置。

设置实时消息

通过 showMessage 函数可以设置信息,其超时时间以ms为单位,如果设置超时时间为0,则默认一直显示。

 设置永久信息

一般永久信息都是通过 label 来显示的,不过有一点需要注意,这种信息会被 showMessage 的显示信息给覆盖掉,因此需要注意。

StatusBar 都能够添加控件,通过 addWidget 函数添加控件,一般所有控件都能够添加。

其次,添加控件的时候,我们能够添加控件的拉伸系数。

 可以看到第一个 label 和第二个 label 不同。

浮动窗口

一般一个窗口中可以有多个小窗口,比如 Qt Creator 就含有多个浮动窗口。 那么我们自然能够通过 Qt 来自行给一个窗口添加子窗口。

QDockWidget 类即是浮动窗口,它一般围绕在中心部件周围。

创建一个浮动窗口

和上面菜单栏工具栏一样,都是直接new 出来一个对象,然后通过 add 函数来添加浮动窗口。

和工具栏一样,浮动窗口可以有多个,因此使用 addDockWidget 来添加浮动窗口。

只不过这里的 addDockWidget 函数必须固定浮动窗口的位置。

以下就是设置浮动窗口位置的宏定义。 

  • Qt::LeftDockWidgetArea : 靠左 
  • Qt::RightDockWidgetArea : 靠右
  • Qt::TopDockWidgetArea : 靠上
  • Qt::BottomDockWidgetArea : 靠下 

 此时的浮动窗口未添加任何控件,因此没有任何功能。

为浮动窗口添加控件

子窗口添加控件有点复杂。

如果只在子窗口中添加一个控件可以直接添加,但是如果想添加多个控件的话,就必须借助 QWidget 了。

这是因为 DockWidget 一次只能包含一个 QWidget,如果想添加多个控件,就必须先添加一个 QWidget 对象,然后往 QWidget 对象中添加一个布局管理器,然后将新的控件添加到布局管理器中,最后连同布局管理器一起放在 QWidget 中。

这样就能够成功设置好想添加到子窗口的控件。

 对话框

在一些窗口的时候,有时候会弹出一些对话框,比如记事本修改文本后退出,会提示是否保存。

这种就是对话框,Qt 也提供了对话框,供我们使用。

在创建项目的时候,base class 选项选则 QDialog 就是一个对话框。

 不过这种方式我们一般不使用,因为对话框一般都是在主窗口弹出的。

比如这样,设置一个按钮,点击按钮即可弹出对话框。

不过这样有个内存泄漏的问题,每一次点击按钮都会创建一个对话框,但是这个对话框却没有delete,虽然我们挂在了对象树上,但问题是,窗口没有关闭,对象树也没有销毁,因此这里需要修改代码。

比如按下对话框的关闭按钮即可释放内存,这样就 Ok 了。

这样的操作 Qt 已经给我们提供了,即通过 setAttribute 函数,给 dialog 设置一个属性,该属性是 

WA_DeleteOnClose, 即关闭的时候自动销毁,这样就不会造成内存泄漏了。

自定义对话框

想要自定义对话框有两种方式:纯代码和图形化界面。

纯代码定义对话框

纯代码方式必须先创建一个 Dialog 类,该类继承自 QDialog 。

首先先新建一个类,该类继承自 QDialog。


 

然后在新建的类的构造函数中添加控件,这里的布局管理器不是必要的,只是为了美观。 

然后在 MainWindow 中给按钮添加槽函数,即点击按钮后显示一个对话框。 

可以看到,对话框中确实新增了按钮和 label。 

 

图形化界面定义对话框

 图形化界面方式定义对话框首先需要新建一个 ui 文件。

由于本次是创建一个 Dialog,因此就选择这三个中的任意一个。 

 这样我们就能在对话框中直接手动添加控件了。

给按钮添加槽函数。

之后在 MainWindo 的ui 文件中添加控件,并且添加槽函数。 

 

可以看到,确实能够显示出一个对话框。 

模态对话框

一般对话框分为两种对话框——模态对话框和非模态对话框。

  • 模态对话框

                出现该对话框时,不能对父窗口进行操作 

  • 非模态对话框

                出现该对话框时,可以对父窗口进行操作

当我们对一个文档进行了修改,退出的时候,一定回弹出一个对话框让我们选则是否保存

 

出现该对话框时,我们无法再对文档进行任何修改,必须做出选择,这就是一种模态对话框。

而如果想要创建一个模态对话框,就需要使用 exec() 函数而非 show() 函数.

这样就制作了一个模态对话框了。 

 

 Qt自带的对话框

有些对话框的使用场景比较经典和常用,针对这些使用场景,Qt 自定义了几种对话框,方便用户使用。

这些对话框都继承自 QDialog ,可以直接使用 QDialog 的 API。

QMessageBox

QMessageBox 自带按钮

QMessageBox 和 QDialog 的创建方式类似,都是通过 new 来开辟控件。

不过不一样的是,QMessageBox 自带图标和按钮,我们可以自行设置,也可以直接采用自带的图标和按钮。

 其中图标有以下图标:无图标、信息图标、警告图标、致命问题图标、操作问题图标等。

 按钮也有以下按钮,有很多种,根据自己需要使用。

 

弹出的对话框如下:

 对于 exec 函数,也就是模态对话框来说,它在执行结束后(对话框关闭)时会返回一个值。

该值是一个 int 类型的数据,该数据即是对话框设置的标准按钮的值。

 可以看到,确实在点击对应按钮后,就会获取到该按钮对应的值。

 通过这种方法我们也能够实现类似 connect 函数的作用,即通过判断返回值来调用函数。

像这种标准的按钮是无法使用信号槽机制的,不过 QMessageBox 也能够自定义按钮。

QMessageBox 自定义按钮

但是在添加自定义按钮的时候,我们能够看到两个参数,一个是按钮的地址,一个是 ButtonRole

 

这个 ButtonRole 指该按钮在对话框中所扮演的角色,我们可以直接查看一下ButtonRole

比如我们设置 ButtonRole 为 AcceptRole 那么点击这个按钮就表示接受的意思,RejectRole 则表示拒绝,HelpRole 表示帮助的角色,自定义的按钮需要设定好所扮演的角色。 

这里我们就随意设置一个接受的角色。 

 快速搭建一个 QMessageBox

QMessageBox 还有一种快速搭建对话框的方式,即通过 QMessageBox::information / warning /critical / question 四种函数来快速搭建。

这四个函数实际上就是 QMessageBox 自带的四种图标的名称,使用对应的函数会自带对应的图标。

四个函数的参数都一样,分别是 父节点、对话框标题、对话框文本、标准按钮,其返回值和exec函数一样,都是按下的按钮的值,可以直接判断使用。 

 这样就能够直接 new 一个图标是 information、带有 ok 和 no 两个按钮的 QMessageBox 对话框

而且通过这种方式创建的对话框都是 模态的。 

 QColorDialog

该对话框实现了一个调色板的功能,类似于画图中的调色板。

这个调色板我们能够做到像 QDialog 和 QMessageBox 一样,通过 new 创建和 delete 删除。

不过 Qt 自己提供了静态函数,类似于 QMessageBox 一样,可以快速创建一个调色板。

QColorDialog::getColor 函数,是 QColorDialog 的一个静态函数。

三个参数分别是 调色板初始颜色、函数的父指针、QColorDialog 的标题。

其中初始颜色是通过 rgb 设置或者直接使用 Qt 自带的宏设置的。

rgb 是三原色的缩写,即红色、绿色和蓝色,通过设置三种颜色的比例来构建其他所有颜色

我们设置通过调色板来设置背景颜色。

 

 这就是 QColorDialog 的作用。

QFileDialog

QFileDialog 是针对于文件的对话框,可以进行保存文件或者打开文件的操作。

它有三种静态函数,分别是 getOpenFileName(获取打开的文件名)、getSaveFileName(获取保存的文件名)、getOpenFileNames(一次打开多个文件)。

 

这三个函数的参数及其类似,分别是父节点的地址、对话框的标题、默认打开的文件路径、以及文件过滤器。

getOpenFileName 和 getOpenFileNames 的作用类似,因此不再赘述,咱们直接试试 getOpenFileName 和 getSaveFileName 两个函数。

设置两个按钮,分别是 getOpenFileName 以及 getSaveFileName 两个函数。

getSabeFileName 右下角是保存 。

 

而getOpenFileName 右下角是打开。 

不过这里的打开和保存按钮并没有效果,因为我们没有给它设定函数,因此没有作用。

QFontDialog

QFontDialog 能够弹出一个修改字体的对话框,和上面的调色板一样,都是通过静态函数进行调整

通过 QFontDialog::getFont 函数能够直接构建一个 QFontDialog 对话框。

该函数有两个参数。

 其中 第一个 ok 函数是一个输入输出型参数,因为设置字体的对话框有两个按钮——ok 和 cancel

如果点击的是 ok,那么该参数的值就会变成 true,cancel 则是 false。

因此这里的参数 ok 初始值应该是 false。

其次,该函数的返回值是一个 QFont,也就是返回在对话框中选择的字体进行返回,用来设置字体

这里的槽函数是获取到字体对话框中的字体,并且将按钮的字体修改为对应的字体。 

可以看到,确实能够设置按钮的字体。 

 

QInputDialog

 这是一个输入对话框,它有三种输入对话框:Int、Double、Item。

分别通过 getInt、getDouble、getItem 三种静态函数创建。

这三个函数的参数都很相似。

getItem/getInt/getDouble : 父节点的指针、对话框的标题、对话框的内容、初始值、最小值、最大值、每次微调的大小、ok值(QFontDialog::getFont的参数含义一样),flags 值。

由于初始值后面的内容后有默认值,因此我们可以不管。 

接着我们来使用一下三个对话框。

可以看到,条目输入框我们需要另外添加一个 QStringList 的参数,该参数类似于C++的 List<String> 类型。

 

 可以看到,三种函数的返回值都是对话框输入的值。

而条目输入框的条目们只是用作一个选择,并不一定需要是条目内容。

总结

本文总结了一个成熟的窗口应该具有的窗口,菜单栏、工具栏、状态栏、浮动窗口、对话框等。

也分别总结了Qt是如何实现它们的,以及各个函数的使用,相信会对大家的Qt学习之旅有所帮助

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

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

相关文章

位置参数

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 位置参数也称必备参数&#xff0c;是必须按照正确的顺序传到函数中&#xff0c;即调用时的数量和位置必须和定义时是一样的。 &#xff08;1&#x…

stack和queue(1)

一、stack的简单介绍和使用 1.1 stack的介绍 1.stack是一种容器适配器&#xff0c;专门用在具有先进后出&#xff0c;后进先出操作的上下文环境中&#xff0c;其删除只能从容器的一端进行元素的插入和弹出操作。 2.stack是作为容器适配器被实现的&#xff0c;容器适配器即是…

信号与槽函数的魔法:QT 5编程中的核心机制

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、信号与槽函数的基本概念 二、信号与槽函数的实现原理 三、信号与槽函数的代码实例 四…

搭载算能 BM1684 芯片,面向AI推理计算加速卡

搭载算能 BM1684 芯片&#xff0c;是面向AI推理的算力卡。可集成于服务器、工控机中&#xff0c;高效适配市场上所有AI算法&#xff0c;实现视频结构化、人脸识别、行为分析、状态监测等应用&#xff0c;为智慧城市、智慧交通、智慧能源、智慧金融、智慧电信、智慧工业等领域进…

实用软件分享---- i茅台 在windows上自动预约和自动获取小茅运的软件

专栏介绍:本专栏主要分享一些实用的软件(Po Jie版); 声明1:软件不保证时效性;只能保证在写本文时,该软件是可用的;不保证后续时间该软件能一直正常运行;不保证没有bug;如果软件不可用了,我知道后会第一时间在题目上注明(已失效)。介意者请勿订阅。 声明2:本专栏的…

计算机基础学习路线

计算机基础学习路线 整理自学计算机基础的过程&#xff0c;虽学习内容众多&#xff0c;然始终相信世上无难事&#xff0c;只怕有心人&#xff0c;期间也遇到许多志同道合的同学&#xff0c;现在也分享自己的学习过程来帮助有需要的。 一、数据结构与算法 视频方面我看的是青…

C++_list简单源码剖析:list模拟实现

文章目录 &#x1f680;1. ListNode模板&#x1f680;2. List_iterator模板(重要)&#x1f331;2.1 List_iterator的构造函数&#x1f331;2.2 List_iterator的关于ListNode的行为 &#x1f680;3. Reverse_list_iterator模板(拓展)&#x1f680;4. List模板(核心)&#x1f331…

【计算机毕设】基于SpringBoot的房产销售系统设计与实现 - 源码免费(私信领取)

免费领取源码 &#xff5c; 项目完整可运行 &#xff5c; v&#xff1a;chengn7890 诚招源码校园代理&#xff01; 1. 研究目的 随着房地产市场的发展和互联网技术的进步&#xff0c;传统的房产销售模式逐渐向线上转移。设计并实现一个基于Spring Boot的房产销售系统&#xff0…

SpringCloud学习笔记(一)

SpringCloud、SpringCloud Alibaba 前置知识&#xff1a; 核心新组件&#xff1a; 所用版本&#xff1a; 学习方法&#xff1a; 1.看理论&#xff1a;官网 2.看源码&#xff1a;github 一、微服务理论知识 二、关于SpringCloud各种组件的停更/升级/替换 主业务逻辑是&#x…

尝试用智谱机器人+知识库,制作pytorch测试用例生成器

尝试用智谱机器人知识库,制作pytorch测试用例生成器 1 保存pytorch算子文档到txt2 创建知识库3 创建聊天机器人4 测试效果5 分享 背景:是否能将API的接口文档和sample放到RAG知识库,让LLM编写API相关的程序呢 小结:当前的实验效果并不理想,可以生成代码,但几乎都存在BUG 1 保存…

星闪在智能汽车端的应用

随着智能汽车、智能终端、智能家居和智能制造等多产业的快速发展&#xff0c;多应用领域对无线短距通信技术在低延时、高可靠、低功耗等方面提出共性要求&#xff0c;现有主流无线短距通信技术的先天局限和技术潜力无法满足新应用的技术要求&#xff0c;针对解决行业技术痛点的…

StrApi基本使用

1.创建项目(这里只使用默认的sqllite) 点击链接进入官网查看先决条件,看看自己的node,python等是否符合版本要求 运行以下命令进行创建项目(网慢导致下载失败的话可以尝试使用手机热点给电脑使用,我就是这样解决的,也可以看我csdn的资源这里进行下载) yarn create strapi-ap…

5.25.1 用于组织病理学图像分类的深度注意力特征学习

提出了一种基于深度学习的组织病理学图像分类新方法。我们的方法建立在标准卷积神经网络 (CNN) 的基础上,并结合了两个独立的注意力模块,以实现更有效的特征学习。 具体而言,注意力模块沿不同维度推断注意力图,这有助于将 CNN 聚焦于关键图像区域,并突出显示判别性特征通…

基于Python的校园预约打印网站的实现

基于Python的校园预约打印网站的实现 开发语言:Python 数据库&#xff1a;MySQL所用到的知识&#xff1a;Django框架工具&#xff1a;pycharm、Navicat、Maven 系统功能实现 注册 新用户首先要进行注册信息填写&#xff0c;填写完成以后进行登录即可使用此网站 打印社 分别有…

同元软控受邀出席2024工业软件创新发展学术会议

5月24日至26日&#xff0c;以“工业软件与新质生产力”为主题的2024工业软件创新发展学术会议在武汉顺利召开。会议由《软件导刊》编辑部主办&#xff0c;复杂关键软件环境全国重点实验室、武汉人工智能研究院、武汉轻工大学电气与电子工程学院承办&#xff0c;百度公司等单位协…

RandLA-Net 训练自定义数据集

https://arxiv.org/abs/1911.11236 搭建训练环境 git clone https://github.com/QingyongHu/RandLA-Net.git搭建 python 环境 , 这里我用的 3.9conda create -n randlanet python3.9 source activate randlanet pip install tensorflow2.15.0 -i https://pypi.tuna.tsinghua.e…

数据结构与算法 :数据结构绪论,时间和空间复杂度 推导大O阶

各位少年 大家好 我是博主那一脸阳光&#xff0c;今天开始给大家分享数据结构&#xff0c;由于我个人当初学的时候是自学&#xff0c;并没有看培训机构的视频 所以接下来我分享的数据结构的内容&#xff0c;源头来自一本书叫做大话数据结构。顺便一提为了方面大家理解&#xff…

unicloud 云对象

背景和优势 20年前&#xff0c;restful接口开发开始流行&#xff0c;服务器编写接口&#xff0c;客户端调用接口&#xff0c;传输json。 现在&#xff0c;替代restful的新模式来了。 云对象&#xff0c;服务器编写API&#xff0c;客户端调用API&#xff0c;不再开发传输json…

二叉树—堆(C语言实现)

一、树的概念及结构 1.树的概念 树是一种非线性的数据结构&#xff0c;它是有n&#xff08;n > 0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一颗倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下。 ● 有一个特殊的结点…

结构设计模式 - 代理设计模式 - JAVA

代理设计模式 一. 介绍二. 代码示例2.1 定义 CommandExecutor 类2.2 定义 CommandExecutorProxy代理类2.3 模拟客户端2.4 测试结果 三. 结论 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子…