OPC Client第5讲(wxwidgets):初始界面的事件处理;按照配置文件初始化界面的内容

发布于:2025-05-24 ⋅ 阅读:(12) ⋅ 点赞:(0)

接上一讲,即实现下述界面的事件处理代码;并且按照配置文件初始化界面的内容(三、)

 事件处理的基础知识,见下述链接五、

OPC Client第3讲(wxwidgets):wxFormBuilder;基础框架;事件处理_wxwidgets 界面设计工具有哪些-CSDN博客

一、总体逻辑

1、涉及到事件处理的 控件

上图的每个序号都涉及到一个控件的事件处理,具体见二、

2、没有涉及到事件处理的 控件

上图中剩下的文本控件wxTextCtrl框,包括“选择机型和PLC”的勾选部分。即界面的初始化内容都是通过OnInitConf函数填的,没有涉及到事件处理。

二、按照一、中逻辑 实现 涉及到事件处理的控件

1、“选择机型和PLC”:OnCheckListBox函数

即下图的1 2 3

1>逻辑思考

先看“选择机型和PLC”这部分的实现代码(见上一讲三、2、2>和三、3、)

具体实现此界面的代码,在InitElement函数中,如下图

其中checkListBox、checkListBoxHCPlc 和 checkListBoxBHPlc三个变量都定义在.h中,在构造函数中实现初始化(为了简化代码)

所以,事件处理 涉及 checkListBox、checkListBoxHCPlc 和 checkListBoxBHPlc三个变量。

2>代码实现

1》三个变量分别绑定其事件函数,都是OnCheckListBox函数

  • EVT_LISTBOX:用于wxListBox控件。
    • 触发条件:当用户在wxListBox中选择一个不同的项时,该事件会被触发。
  • EVT_CHECKLISTBOX:用于wxCheckListBox控件。
    • 触发条件:当用户勾选或取消勾选wxCheckListBox中的任何一个选项时,该事件会被触发

注意下述链接五、

OPC Client第3讲(wxwidgets):wxFormBuilder;基础框架;事件处理_wxwidgets库-CSDN博客

综上,写出此部分的代码:

如下图,由于三个变量的Id都是wxID_ANY,所以在OnCheckListBox函数中需要先获取当前点击的选项的id【即传入参数wxCommandEvent& event的id】。

再根据判断条件 确认 当前勾选的选项是 哪个变量。

2》选中checkListBox

要求:

  • 勾选了checkListBox里的选项后,默认勾选checkListBoxHCPlc里对应的禾川PLC
  • 如果取消当前这个checkListBox,那么checkListBoxBHPlc和checkListBoxHCPlc对应的勾选都要取消
  • 需要设置,checkListBoxHCPlc 和 checkListBoxBHPlc 两个选项只能勾选其一【在3》4》中实现】

区别:

“选中”指的是通过键盘方向键高亮的项(类似于焦点);而“勾选”才是用户点击复选框打钩的状态。

event.GetSelection()

  • 这个方法是从 wxCommandEvent 对象中调用的。
  • 它返回的是触发事件的那个特定项的索引(即用户最近一次点击或选择了哪个项)。
  • 适用于在事件处理函数中获取用户最近一次操作的具体目标项。

checkListBox->GetSelection()

  • 这是从 wxCheckListBox 控件对象本身调用的方法。
  • 在 wxWidgets 中,对于 wxListBox 或类似的单选控件,GetSelection() 返回的是当前被选中的单个项的索引。如果没有任何项被选中,则返回值可能是 -1。
  • 对于允许多选的控件(如 wxCheckListBox),这个方法通常并不适用于获取所有选中的项,而是用于获取最后一个被选中的项(如果有这样的实现)。

checkListBox->GetSelections(wxArrayInt&)

  • 这是一个从 wxListBox 继承来的函数。
  • 它返回的是 当前“选中”(高亮)的项索引列表

checkListBox->GetCheckedItems(wxArrayInt&)

  • 获取所有被选中(勾选)项的索引列表。
  • 这些方法直接从控件本身调用,可以用来查询当前控件的状态,而不仅仅是最近一次用户交互的结果。

3》选中checkListBoxHCPlc

相关基础知识见2》

要求:

  • 需要设置,checkListBoxHCPlc 和 checkListBoxBHPlc 两个选项只能勾选其一
  • 【新增】点击checkListBoxHCPlc时,如果checkListBox没有勾选,则自动勾选上

4》选中checkListBoxBHPlc

和3》完全相同,代码只是需要把3》中的HC与BH互换

2、“选择文件(右键)”:直接写在InitElement函数中了,在实现控件后直接用Bind的Lambda匿名方法

 即下图的4 5

先看“选择文件(右键)”这部分的实现代码(见上一讲四、)

1>“标准对照(必需)”处的事件处理

 用到的是下述链接六、2、的文件和目录对话框:wxFileDialog

OPC Client第4讲(wxwidgets):窗口布局基础知识;界面练习-CSDN博客

1》实现代码:创建wxFileDialog的参数

2》源代码累赘:不用再次调用event.Skip!

《1》对于事件处理机制:加上event.Skip()没用

先理解第3讲的事件处理运行过程五、1、3>

OPC Client第3讲(wxwidgets):wxFormBuilder;基础框架;事件处理-CSDN博客

上图代码中的理解:

  • Lambda 表达式 没有父类,但是有父窗口[this],即InitFrame。【为什么?见上述链接五、1、3>的举例】
  • 当加上event.Skip()后,wxMouseEvent&事件不属于wxCommand事件,所以这个事件不会向上传递到父窗口InitFrame里面。加上event.Skip()没用。

《2》wxTextCtrl还有一个wxMouseEvent类型的wxEVT_RIGHT_DOWN的默认行为:一旦你绑定了自己的事件处理函数,框架就不再自动执行默认行为

如何知道哪些事件有默认行为?——查阅官方文档

  • 例如,wxTextCtrl 对右键点击事件默认会显示一个上下文菜单,提供复制、粘贴等功能。

2>“批量连接”的事件处理

完全同1>

3、“确认”:OnConfirm函数【先看三、此处创建了MainFrame.h/.cpp】

 即下图的6

1>为“确认”按钮绑定事件

2>事件处理函数OnConfirm的总体逻辑

1》更新三、中的config(额外创建变量config1,不改变config的值)

config1的Key值 等于 三、的Configuration.json文件里的Key值

2》把新的配置信息config1写入配置文件Configuration.json

《1》在my_lnit.h中 创建“写入配置文件WriteConfigurations”函数

《2》在InitFrame.cpp的OnConfirm函数中进行使用

3》关闭 InitFrame 对应的界面,打开 MainFrame界面,把1》的config1传给 MainFrame

《1》创建MainFrame.h和MainFrame.cpp

《2》在InitFrame.cpp的OnConfirm函数中进行使用

《3》在进入MainFrame后,即实现下图界面,具体内容见下一讲

4、“取消”:OnCancel函数

 即下图的7

三、按照一、中逻辑 实现 没有涉及到事件处理的控件

上图中剩下的文本控件wxTextCtrl框,包括“选择机型和PLC”的勾选部分。即界面的初始化内容都是通过OnInitConf函数填的,没有涉及到事件处理。

1、OnInitConf函数作用:读取配置文件,初始化各个wxTextCtrl控件的默认值。

2、如何读取1、的配置文件?——新建my_lnit.h 和 my_lnit.cpp

仿照源代码,另一种更简便的写法如下

如上图,创建了读取配置文件的GetConfigurations函数。

在这个函数中,需要打开Configuration.json文件(下述2>),获取里面的数据,到InitFrame.cpp的config变量中。

1>给各个.h代码加上命名空间 + 把.h和.cpp文件放在对应文件夹中

1》新建include文件夹, 所有的命名空间都放在include文件夹下了

打开上图的include文件夹,再创建下图的五个文件夹。

下图的一个文件夹就是一个命名空间(主要用的是UaApp和uasdk),分别代表:缓冲区,json库,主项目相关,sdk相关

2》往1》的命名空间中移入.h文件,确保.cpp代码中#include <uasdk/my_Init.h>可以找到

在代码的“项目”->“属性”中,添加“附加包含目录的路径”

这里只是导入.h文件的路径,在下述链接四、3、

OPC Client第2讲:Visual Studio的C/C++使用教程;C++程序运行过程的各个文件;如何导入库?{静/动态库;更便捷的方法添加第三方库:使用属性表【配置使用wxwidgets】}_visual studio 运行c++-CSDN博客

如此,在.cpp中能引用uasdk文件夹下的.h文件了

3》在2》后出现问题:代码中头文件下的.h文件打不开了

即把.h和.cpp放在文件夹,怎么找到其的文件路径,并打开其代码

解决办法:

使用“添加现有项”并选择适当的过滤器

  1. 右键点击项目中的文件夹(”头文件“),然后选择“添加 -> 现有项...”。

  2. 导航到 D:\VisualStudio\OPC_Data\test\include 目录。

  3. 选择需要添加的 .h 文件。

同理,新建src文件夹,里面放入所有的.cpp文件。按照上述解决办法重新导入各个.cpp文件

4》【非必需】在每个.h代码中加上其属于哪个命名空间

这样不用每次在include文件夹里找

5》同理,修改InitFrame.h和InitFrame.cpp的文件位置和命名空间

main.cpp也要修改。

6》最后,所有的.h和.cpp文件都被放在了对应文件夹中。代码中也加入了每个.h应该放的命名空间

2>实现my_Init.h里的GetConfigurations函数

1》在文件夹中创建 Configuration.json 格式的文件,里面存放着初始的配置信息

注意,师傅发的源代码文件压缩包,这个Configuration.json文件是已经有了的,不用自己再创建

//所有的文件路径都是Debug目录下开始的,即exe文件所在的文件夹

 再添加两个表格.xlsx在路径里面,因为在 Configuration.json文件 中需要这两个表格

Configuration.json文件里面存放着初始的配置信息

《1》注意:【自己写的Configuration.json文件 相比 师傅的做了修改】

1)师傅的——没必要用.json格式的文件

师傅的这个.json文件里存放的数据不是json格式,获取里面的数据也没有用到json包里的简便函数!

师傅用2》的.json库只是为了:在my_lnit.h的GetConfigurations函数中,声明的config变量 和 返回的数据是json格式。

需要读取两个.xlsx文件里的值

2)自己修改后的

就是改成json格式,利用2》的nlohmann json库里的函数 获取/修改数据

2》导入json库(GetConfigurations函数中,声明的config变量 和 返回的数据是json格式)

在源代码中选择了法2:

c++中nlohmann json的基本使用教程 - LiuYanYGZ - 博客园

不知道为什么,上述命令行报错说找不到json.hpp文件。那么换种方法,见下述链接

windows下使用#include <nlohmann/json.hpp>_nlohmann windows-CSDN博客

为了清楚知道nlohmann json有哪些函数可以用,把.hpp文件添加到项目目录中

《1》什么是hpp文件?

.hpp 更加明确地表示这是一个C++头文件,而 .h 则可能是C或C++的头文件。

然而,这并不是一个严格的规定,更多是一个社区内的约定俗成。在实际开发中,你可能会看到两者都被广泛使用。

《2》在代码中要用到此库的地方#include

3》实现GetConfigurations函数【见1》,自己写的对比师傅的优化了】

在这个函数中,需要打开Configuration.json文件(上述1》,文件操作见下述链接),利用nlohmann json(上述2》,使用见下述链接)里的函数获取里面的数据,到InitFrame.cpp的config变量中。

C++核心编程 | welcome to here

GitHub - nlohmann/json: JSON for Modern C++

4》上图中省略了 记录错误 的部分,见下一讲:创建logger.h和helper_t.h(3、中创建)里的gettime函数

3、实现InitFrame.h的OnInitConf函数

剩下的文本控件wxTextCtrl框,包括“选择机型和PLC”的勾选部分。即界面的初始化内容都是通过OnInitConf函数填的,没有涉及到事件处理。

在InitFrame构造函数中加入OnInitConf函数,如下图

实现OnInitConf函数。下图中省略了最外面的第二、三块的变量,其完全类似第一块

1>为什么不能直接odbcNameText->SetValue(config["clientname"]);

因为config["clientname"] 返回的是 json 类型的对象,不能直接传给wxTextctrl的SetValue。

  • wxTextctrl的SetValue接受的是wxString 或者 std::string,但不接受 json 类型
  • 为什么可以接受std::string?——存在隐式转换

2>上图红框:“选择机型和PLC”的勾选部分【创建helper_t.h】 

split函数得自己实现!

  • 在C++的标准库中确实没有直接名为split的函数,不过可以通过其他标准库功能来实现字符串分割的功能。常用的方法包括使用std::stringstream(位于<sstream>头文件中)

1》注意:getline函数的作用,以及分隔符开头/结尾、连续的分隔符:都会变成空字符串

下面开始在InitFrame.cpp的OnInitConf函数中进行调用


网站公告

今日签到

点亮在社区的每一天
去签到