GUI07-学工具栏,懂MVC
MVC模式,是天底下编写GUI程序最为经典、实效的一种软件架构模式。当一个人学完菜单栏、开始学习工具栏时,就是他的一生中,最适合开始认识 MVC 模式的好时机之一。这节将安排您学习:
- Model-View-Controller 模式
- 如何创建工具栏以及如何于其上创建普通、多选、单选工具按钮
- 控件之间如何通过“空闲”事件实现状态统一
0. 课堂视频
建议先看视频,再看文本教程。最后到 d2school 课堂做本课的学习强化练习。
GUI07-学工具栏,懂 MVC
1. 才不是题外话:MVC
MVC模式,是天底下编写GUI程序最为经典、实效的一种软件架构模式。当一个人学完菜单栏、开始学习工具栏时,就是他的一生中,最适合开始认识 MVC 模式的好时机之一。
MVC 是 “Model-View-Controller” 的简写:
- Model / 模型:可认为就是我们在代码中定义的各种业务数据;
- View / 视图:业务数据的展现形式,一种模型(数据)往往有多种展现形式;
- Controller / 控制器: 用户通过控制器,以可定制的方式,获取数据模式,及指定形式展现(视图)。
程序员开发软件时,将代码按照 Model-View-Controller 加以分离,能让软件代码:
- 逻辑,意图更清晰
- 耦合更低
- 更可维护
MVC 比较适用于中大型软件代码的组织,我们前几节课所写的程序,看似简单,但其实, GUI软件没有小项目,是底层的库(比如 wxWidgets)默默地做出大量支持,包括 MVC 架构。
以前面课堂写的小例程为例:我们在窗体上鼠标位置下显示鼠标所在的坐标值,并且允许用户做如下控制:
- 是否显示坐标值,或仅显示一行提示文字;
- 文字以蓝或红哪种颜色显示。
则,至少有两个数据模型:
编号 | Model |
---|---|
M1 | 表达坐标的两个整数:x, y |
M2 | 表达用户选中颜色的菜单项ID |
以及,这两个数据,至少四种组合态的展现形式:
编号 | View (数据视图) |
---|---|
V1 | 蓝色 + 显示坐标 |
V2 | 红色 + 显示坐标 |
V3 | 蓝色 + 不显示坐标(仅显示提示) |
V4 | 红色 + 不显示坐标(仅显示提示) |
以下是实际运行时,显示的 V2 状态界面截图:
正如本课视频所讲到,View 并不仅仅包含业务数据的展现,用于实现和用户交互的 GUI 界面控制,比如我们已学的菜单、工具栏、状态栏等界面控件,也是 View 的组成。它们也会有和业务数据紧密关联的状态,比如菜单或工具图标的多选或单选状态。
以上归纳了 Model 和 View,那 Controller是什么呢?是控制流程。在我们所写的程序中,程序接收用户的输入(鼠标点击等),然后调用相应的事件函数,在事件函数中修改 Model 数据,最后引发视图刷新,包括业务视图刷新和人机交互界面中控件状态的改变,这整个过程即为 Controller。
初接触时,对 MVC 的三个最常见的误解为:
-
误解一:以为 View的展现内容只能给人看。正解:一个程序的输出可以是另一个程序的输入,此时可视为后者是前者的“用户”,同理,同一个程序的控制,也可能是来自另一个程序的输入。正因为 Views 不一定真实的人,所以在服务端程序中,特别是多层网络架构的软件系统中,MVC 的应用也广泛可见;
-
误解二:以为人机交互过程中界面控件,就是 Controller 。正解:Controller 是接受用户(不一定是人,见上)的输入,然后引发(即动作的发起者)Model 被修改,并最终体现到 View 变化的每一个完整过程。
-
误解三:以为只有业务数据的展现是 Views。正解:凡是需要展现给用户看的内容,基本都是 View,包括控件的状态。
2. 创建图标
在 Windows 系统下,应用程序工具栏按钮所需要的图标,需要使用 ICON 类型的图标,在 wxWidgets中,对应到 wxIcon 类。
2.1 从文件直接创建
可在程序运行时,通过读取指定路径(相对或绝对)读取指定的图标文件,以构造出一个wxIcon对象,示例代码:
wxIcon myIcon = wxIcon(wxT("路径/图标文件.ico"), wxBITMAP_TYPE_ICO, 16, 16);
注意,创建所得是普通的栈对象,非堆对象。
- 入参1:图标的磁盘位置(包括路径和文件名,可使用绝对或相对路径);
- 入参2:图标文件的类型(注意是 wxBITMAP_TYPE_ICO,而非 wxBITMAP_TYPE_ICON);
- 入参3,4:两个整数,图标的长、宽(像素)。
在程序运行时读取外部文件以创建图标(或其它资源)——
- 好处:可随时更换图标——不少应用程序支持 “换肤”,对于工具栏按钮来说,这是一种简便可行的方法;
- 坏处:程序无法单独运行。比如你想把程序发给你的朋友,就得同时附上这些图标文件,并需确保路径正确。
2.2 从程序嵌入资源中创建
Windows 支持将一些资源,嵌入到可执行文件(.exe)“体内”,从而实现可执行文件可独立运行。
Code::Blocks 向导生成的 wxWidgets 项目中,已经自带 resource.rc 的文件,打开它,默认内容为:
aaaa ICON "wx/msw/std.ico"
#include "wx/msw/wx.rc"
默认包含的 wxWidgets 程序图标。其中,aaaa 为资源的名字,ICON 为资源类型,此处为图标,最后一列 “wx/msw/std.ico” 为图标在磁盘上的路径和名字(仅编译时需用到,运行时不再需要此路径)。
假设我们已经在当前项目下创建名为 icons 的子目录,并于其下准备好 about.ico、show_info.ico、blue_txt.ico、red_txt.ico、quit.ico 等图标,则可将 resouce.rc 内容修改成:
aaaa ICON "wx/msw/std.ico"about ICON "icons/about.ico"
blue_txt ICON "icons/blue_txt.ico"
red_txt ICON "icons/red_txt.ico"
quit ICON "icons/quit.ico"
show_info ICON "icons/show_info.ico"#include "wx/msw/wx.rc"
这样,在编译后,相关图标资源就会内嵌在编译生成的可执行文件中,并可通过 wxIcon 的另一个构造函数读出并且成图标对象:
wxIcon icon = wxIcon(wxT("资源名"), wxBITMAP_TYPE_ICO_RESOURCE, 16, 16);
比如,创建 quit 图标:
wxIcon iconQuit = wxIcon(wxT("quit"), wxBITMAP_TYPE_ICO_RESOURCE, 16, 16);
本文后续代码均从内嵌资源创建图标。
3. 工具栏与工具栏按钮
3.1 创建工具栏
wxFrame::CreateToolBar() 用于创建一个空白的工具栏,该方法返回一个 wxToolBar * (指针)。
示例代码:
wxToolBar* tb = this->CreateToolBar(); // 创建工具栏
以上代码中的 this 工具栏所属的框架窗口,它也将负责该工具栏的生命周期(在框架窗口关闭前,将自释放上面创建工具栏堆对象)。
以下各种工具栏按钮,都需要由工具栏(wxToolBar)对象来创建。
3.2 普通工具按钮
使用工具栏对象,创建一个普通工具栏按钮,方法名为 “AddTool()”示例代码:
// 准备图标 (从内嵌资源中读取)
wxIcon iconQuit = wxIcon(wxT("quit"), wxBITMAP_TYPE_ICO_RESOURCE, 16, 16);// 创建带图标的普通工具按钮
tb->AddTool(idMenuQuit, _("Quit"), iconQuit, _("Quit the Application"));
- 入参1:工具按钮要执行的命令对应的ID,通常来自已经创建的菜单项所绑定的事件ID。比如本例的 idMenuQuit 为 “Quit” 菜单项的ID,该命令用于退出整个应用程序;
- 入参2:工具按钮的标签,默认状态下并不显示,复杂情况下,可设置为在图标底部或右侧显示按钮的名字;
- 入参3:前面创建的图标对象(并非指针);
- 入参4:鼠标在该工具按钮上浮动时出现的提示。
也可将构造图标对象和创建工具按钮合成一步:
tb->AddTool(idMenuQuit, _("Quit"), wxIcon(wxT("quit"), wxBITMAP_TYPE_ICO_RESOURCE, 16, 16), _("Quit the Application"));
实际还需要第三步,但当连续为同一个工具栏创建多个工具按钮时,仅需在最后调用一次:
tb->Realize(); // 真实展现,最后调用,只需一次
仅在调用该方法后,工具栏才真正地将新创建的各工具按钮展现出来。
3.3 复选工具按钮
使用方法为:AddCheckTool(),示例代码:
//复选工具按钮(是否显示鼠标坐标)
tb->AddCheckTool(idMenuShowMotionInfo, _("Show Info"),wxIcon(wxT("show_info"), wxBITMAP_TYPE_ICO_RESOURCE, 16, 16),wxNullBitmap, // 按钮变灰时显示的图标,由程序自动生成_("Show motion info or no")); // 提示
第四个入参用于指定,该复选按钮在不可用(disabled)状态下如何展现,除非你确实想为之提供一种特别的样子,否则,可如代码所示,指定使用代表空图片的对象 wxNullBitmap,系统将自动以 “灰度” 方式生成该状态的展现样式。
因为方法名已经是 “AddCheckTool ()”,故无需像普通的 “AddTool ()” 那样,再由入参指定按钮的类型,下面用于创建单选工具按钮的方法,也是如此。
3.4 单选工具按钮
使用方法为:AddRadioTool(),示例代码:
//单选工具按钮(两个:选择使用蓝色文本或使用红色文本)
tb->AddRadioTool(idMenuBlueText, _("Blue Text"),wxIcon(wxT("blue_txt"), wxBITMAP_TYPE_ICO_RESOURCE, 16, 16),wxNullBitmap, // 按钮变灰时显示的图标,由程序自动生成_("Set text blue")); // 提示tb->AddRadioTool(idMenuRedText, _("Red Text"),wxIcon(wxT("red_txt"), wxBITMAP_TYPE_ICO_RESOURCE, 16, 16),wxNullBitmap,_("Set text red"));
和复选按钮不同,单独一个单选按钮没有意义,通常需要接连创建一组,让用户从多个中选择一个(即为单选之意)。
同一工具栏上如有多组单选按钮,除了可考虑使用分隔(见下面小节)在视觉上加以分组之外,并不需要再额外在逻辑上分组,因为工具按钮通常对应到菜单项,而对菜单项,我们已经作了逻辑分组,详见 《第5节 玩转主菜单》。
3.5 分隔线
tb->AddSeparator(); // 分隔线
3.6 连续代码
以下是在示例项目中, wxToolBarFrame 构造函数尾部,创建工具栏及相应按钮、分隔线的代码片段:
// 工具栏wxToolBar* tb = this->CreateToolBar(); // 创建工具栏wxIcon iconQuit = wxIcon(wxT("quit"), wxBITMAP_TYPE_ICO_RESOURCE, 16, 16);tb->AddTool(idMenuQuit, _("Quit"), iconQuit, _("Quit the Application"));tb->AddSeparator(); // 分隔线//复选工具按钮(是否显示鼠标坐标)tb->AddCheckTool(idMenuShowMotionInfo, _("Show Info"),wxIcon(wxT("show_info"), wxBITMAP_TYPE_ICO_RESOURCE, 16, 16),wxNullBitmap, // 按钮变灰时显示的图标,由程序自动生成_("Show motion info or no")); // 提示tb->AddSeparator(); // 分隔线// 单选工具按钮(两个)tb->AddRadioTool(idMenuBlueText, _("Blue Text"),wxIcon(wxT("blue_txt"), wxBITMAP_TYPE_ICO_RESOURCE, 16, 16),wxNullBitmap,_("Set text blue"));tb->AddRadioTool(idMenuRedText, _("Red Text"),wxIcon(wxT("red_txt"), wxBITMAP_TYPE_ICO_RESOURCE, 16, 16),wxNullBitmap,_("Set text red"));tb->Realize(); // 真实展现,最后调用,只需一次
4. 控件状态同步
为了使用方便,GUI 程序往往允许用户从不同控件入口发起操作,在本例,用户通过菜单栏或工具栏,都可以修改文字的颜色。窗体上输出的文字归属 View,但是菜单项或工具按钮的显示状态,也归于 View 范畴,它们的选中状态,必须保持同步。
举例:用户选中 “变帅” 菜单项,则 工具栏上 “变帅” 按钮也需要在操作后,变成“被按下”的状态;反过来也一样:用户按下 “变帅” 按钮,则同名的菜单项之前,必须打上勾。这还是复选控件,如果是单选控件,则需要的维护一组控件的状态,会更加啰嗦,容易出错。
因此,无论是大家比较熟悉的 Windows 或 苹果的 GUI 系统,还是 Linux 下的各种 GUI 桌面系统,或者是新兴的智能手机 Android 系统,或者是为浏览器前端开发提供支持各种前端库,基本都会提供一套机制,来辅助程序员实现界面组件的状态同步。
GUI 程序有一个共同点:它不可能很忙。有人说,我打开 Word,然后以平均每分钟 120 个汉字,接近 500 次按键的速度打字,这 Word 肯定忙坏了呀? 不是的,这点输入对现在的计算机和程序来说真是一点压力没有,程序仍然能在你的指法间隙间,“挤出”一大把无所事事的时间(不信你可以打开 Windows 任务管理器,看看你要能以怎样的打字速度,让 CPU 占用率提高 0.1%?)。
程序这么闲,自然就可以利用起来,闲着也是闲着,不如打打孩子——不是,不如去检查一下,有哪个控件状态不对,我们好把它纠正过来。
这种空闲事件,在很多 GUI 系统(比如 Windows 或 Android)中称为 “Idle-Event” (对应的事件处理器称为 “Idle-Handler”)。我们正在学习的 wxWidgets 又将它细分出一个 “wxUpdateUIEvent”,即专门用来处理用户界面(UI)的控件状态更新(Update)的事件。对应的,绑定事件函数的宏为:“EVT_UPDATE_UI”。
以用户可以切换坐标是否显示这一功能为例,按照 MVC 的划分原则,我们首先需要有的 Model 数据是:
- a) 坐标数据 x,y (之前课堂已经添加了);
- b) 是否显示,之前课堂没有添加,因此本课需为框架窗口类加上该成员数据,取名 showMotionInfo,一个 bool 值。
接着,当用户依赖某个操作路径(菜单或工具按钮),发起切换操作时,作为一个GUI开发框架,wxWidget将配合作为一个 GUI 操作系统的 Windows,共同帮我们完成复杂的 Controller 过程(视频里说的那些“线”),最终调用到我们写的事件响应函数,该函数修改作为 Model 数据之一的 showMotionInfo。如何知道将它修改成 true 或 false 呢?也就是说,如何知道用户当前操作是选中或是取消选中呢?仍然得感谢 wxWidgets 和其下的操作系统,它已经将该信息,放在事件数据中的 “IsCheck()” 方法里了。
接受用户输入,修改 Model 数据(showMotionInfo)的示例代码:
// 1 绑定到菜单上:
EVT_MENU(idMenuShowMotionInfo, HelloToolBarFrame::OnShowMotionInfo)...// 2 在事件响应函数中,修改 Model,状态信息在事件中:
void HelloToolBarFrame::OnShowMotionInfo(wxCommandEvent& event)
{this->showMotionInfo = event.IsChecked(); // 修改 model
}
接下来,程序在某个时刻发现自己很闲,于是它去开始检查并纠正哪个“孩子”(控件)状态不对——但是,它自己并不知道,也不记录具体哪个控件所应该处于正确状态是什么——谁知道,当然只有作为程序员的我们知道,所以程序会自动触发 UpdateUIEvent 事件,让我们在这个事件里去告诉它,某个“孩子”现在的正确状态应该是:在睡觉……如果有十个不同ID的控件需要更新状态,程序会触发十次这样的事件。
以 “idMenuShowMotionInfo” 为例,空闲的程序想知道绑定该ID的菜单项和工具图标当前应该处于什么状态时,它会触发以下的事件函数被调用:
// 3 绑定控件ID
EVT_UPDATE_UI(idMenuShowMotionInfo, HelloToolBarFrame::OnUpdateShowMotionInfo)...// 4 在事件中,由程序员告诉程序,当前控件的正确状态(是否选中)
void HelloToolBarFrame::OnUpdateShowMotionInfo(wxUpdateUIEvent& event)
{event.Check(this->showMotionInfo); // 有没有选中
}
请对比代码中的 3 和 4,从 “SET/写” 和 “GET/读” 的角度,加以理解。
以上讲的是控件的复选状态,它的状态就是 “选中” 或 “没选中”;对比之下,单选状态稍显复杂。因为单选状态的控件通常成组出现(至少两个),对应的详细状态应该是:“选中哪一个了?”。再次感谢所有 GUI 库,当它们在触发控件的 “UpdateEvent” 时,会带上这个控件的 ID,因此,我们只需检查它是不是我们记录的,用户选中的那个控件ID即可。
比如颜色选择有两项:蓝或红,当用户做出选择,我们就用 Model 数据(selectedColorId) 记录下来:
// 5 绑定控件ID,同一组单选控件需要全部绑定到同一个事件函数:
EVT_UPDATE_UI(idMenuBlueText, HelloToolBarFrame::OnUpdateTextColor)
EVT_UPDATE_UI(idMenuRedText, HelloToolBarFrame::OnUpdateTextColor)...// 6 记录用户选的是哪个ID
void HelloToolBarFrame::OnTextColorSelected(wxCommandEvent& event)
{selectedColorId = event.GetId();
}
对应的,当程序因为闲着也是闲着,又要 “打孩子” 时,我们是这样告诉它哪个 “孩子” 需要被选中,哪个 “孩子” 不需要:
// 7 同样需要绑定一组单选控件(的ID)
EVT_UPDATE_UI(idMenuBlueText, HelloToolBarFrame::OnUpdateTextColor)
EVT_UPDATE_UI(idMenuRedText, HelloToolBarFrame::OnUpdateTextColor)...// 8 在事件中,由程序员告诉程序,它来“问”的控件,是不是被选中的那个
void HelloToolBarFrame::OnUpdateTextColor(wxUpdateUIEvent& event)
{event.Check(event.GetId() == this->selectedColorId);
}
5 Model 数据
最后,汇总一下本例程用到的 Model 数据:
int xPos, yPos;int selectedColorId = idMenuBlueText;bool showMotionInfo = false;
其中,前两项是在之前的课堂定义的。
相关文章:

GUI07-学工具栏,懂MVC
MVC模式,是天底下编写GUI程序最为经典、实效的一种软件架构模式。当一个人学完菜单栏、开始学习工具栏时,就是他的一生中,最适合开始认识 MVC 模式的好时机之一。这节将安排您学习: Model-View-Controller 模式如何创建工具栏以及…...

【进程篇】04.进程的状态与优先级
一、进程的状态 1.1 进程的状态 1.1.1 并行与并发 • 并行: 多个进程在多个CPU下分别,同时进行运行 • 并发: 多个进程在一个CPU下采用进程切换的方式,在一个时间片内,让多个进程都得以推进 1.1.2 时间片的概念 LInux/windows这些民用级别…...

ElasticSearch 数据聚合与运算
1、数据聚合 聚合(aggregations)可以让我们极其方便的实现数据的统计、分析和运算。实现这些统计功能的比数据库的 SQL 要方便的多,而且查询速度非常快,可以实现近实时搜索效果。 注意: 参加聚合的字段必须是 keywor…...

科研学习|论文解读——智能体最新研究进展
从2024-12-13到2024-12-18的45篇文章中精选出5篇优秀的工作分享 Can Modern LLMs Act as Agent Cores in Radiology~Environments? Achieving Collective Welfare in Multi-Agent Reinforcement Learning via Suggestion Sharing A systematic review of norm emergence in …...
面试小札:Java后端闪电五连鞭_8
1. Kafka消息模型及其组成部分 - 消息(Message):是Kafka中最基本的数据单元。消息包含一个键(key)、一个值(value)和一个时间戳(timestamp)。键可以用于对消息进行分区等…...
java error(2)保存时间带时分秒,回显时分秒变成00:00:00
超简单,顺带记录一下 1.入参实体类上使用注释:JsonFormat(pattern “yyyy-MM-dd”) 导致舍弃了 时分秒的部分。 2.数据库字段对应的类型是 date。date就是日期,日期就不带时分秒。 3.返参实体类使用了JsonFormat(pattern “yyyy-MM-dd”) 导…...

计算机毕业设计python+spark+hive动漫推荐系统 漫画推荐系统 漫画分析可视化大屏 漫画爬虫 漫画推荐系统 漫画爬虫 知识图谱 大数据毕设
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...

数字IC后端设计实现篇之TSMC 12nm TCD cell(Dummy TCD Cell)应该怎么加?
TSMC 12nm A72项目我们需要按照foundary的要求提前在floorplan阶段加好TCD Cell。这个cell是用来做工艺校准的。这个dummy TCD Cell也可以等后续Calibre 插dummy自动插。但咱们项目要求提前在floorplan阶段就先预先规划好位置。 TSCM12nm 1P9M的metal stack结构图如下图所示。…...

(8)YOLOv6算法基本原理
一、YOLOv6 模型原理 发布日期:2022年6月 作者:美团技术团队 骨干网络:参考了 RepVGG 的设计,将重参数化能力进行补强,增强了模型结构的重参数化能力。使用了深度可分离卷积和跨阶段连接等技术,旨在提升…...

LNMP+discuz论坛
0.准备 文章目录 0.准备1.nginx2.mysql2.1 mysql82.2 mysql5.7 3.php4.测试php访问mysql5.部署 Discuz6.其他 yum源: # 没有wget,用这个 # curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo[rootlocalhost ~]#…...

在linux系统的docker中安装GitLab
一、安装GitLab: 在安装了docker之后就是下载安装GitLab了,在linux系统中输入命令:docker search gitlab就可以看到很多项目,一般安装第一个,它是英文版的,如果英文不好可以安装twang2218/gitlab-ce-zh。 …...
Python面试常见问题及答案12
问题: 请解释Python中的GIL(全局解释器锁)是什么? ○ 答案: GIL是Python解释器中的一种机制,用于确保任何时候只有一个线程在执行Python字节码。这在多线程场景下可能影响性能优化,但对于单线程…...

从0-1开发一个Vue3前端系统页面-9.博客页面布局
本节主要实现了博客首页界面的基本布局并完善了响应式布局,因为完善了响应式布局故对前面的页面布局有所改动,这里会将改动后的源码同步上传。 1.对页面头部的用户信息进行设计和美化 布局设计参考 :通常初级前端的布局会通过多个div划分区域…...

[手机Linux] 六,ubuntu18.04私有网盘(NextCloud)安装
一,LNMP介绍 LNMP一键安装包是一个用Linux Shell编写的可以为CentOS/RHEL/Fedora/Debian/Ubuntu/Raspbian/Deepin/Alibaba/Amazon/Mint/Oracle/Rocky/Alma/Kali/UOS/银河麒麟/openEuler/Anolis OS Linux VPS或独立主机安装LNMP(Nginx/MySQL/PHP)、LNMPA(Nginx/MySQ…...
白话java设计模式
创建模式 单例模式(Singleton Pattern): 就是一次创建多次使用,它的对象不会重复创建,可以全局来共享状态。 工厂模式(Factory Method Pattern): 可以通过接口来进行实例化创建&a…...

助力 Tuanjie OpenHarmony 开发:如何使用工具包 Hilog 和 SDK Kits Package?
随着团结引擎从 1.0.0 迭代至 1.3.0,越来越多的开发者开始使用团结引擎开发 OpenHarmony 应用。 在开发的过程中,我们也收到了大量反馈,尤其是在日志、堆栈和性能数据方面,这些信息对开发和调试过程至关重要。同时,我…...

NSDT 3DConvert:高效实现大模型文件在线预览与转换
NSDT 3DConvert 作为一个 WebGL 展示平台,能够实现多种模型格式免费在线预览,并支持大于1GB的OBJ、STL、GLTF、点云等模型进行在线查看与交互,这在3D模型展示领域是一个相当强大的功能。 平台特点 多格式支持 NSDT 3DConvert兼容多种3D模型…...

电商数据采集电商,行业数据分析,平台数据获取|稳定的API接口数据
电商数据采集可以通过多种方式完成,其中包括人工采集、使用电商平台提供的API接口、以及利用爬虫技术等自动化工具。以下是一些常用的电商数据采集方法: 人工采集:人工采集主要是通过基本的“复制粘贴”的方式在电商平台上进行数据的收集&am…...
VUE+Node.js+mysq实现响应式个人博客|项目初始化+路由配置+基础组件搭建
Day 1 开发文档:项目初始化与基础架构搭建 一、项目初始化 1. 创建项目 首先,我们使用 Vite 创建一个基于 Vue 3 的项目: # 创建项目 npm create vitelatest my-blog -- --template vue # 这条命令会创建一个名为 my-blog 的新项目&#…...

Python如何正确解决reCaptcha验证码(9)
前言 本文是该专栏的第73篇,后面会持续分享python爬虫干货知识,记得关注。 我们在处理某些国内外平台项目的时候,相信很多同学或多或少都见过,如下图所示的reCaptcha验证码。 而本文,笔者将重点来介绍在实战项目中,遇到上述中的“reCaptcha验证码”,如何正确去处理并解…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...

什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...