CMake+QT+大漠插件的桌面应用开发

文章目录

  • CMake+QT+大漠插件的桌面应用开发
    • 简介
    • 环境
    • 项目结构
    • 配置编译环境
    • 代码

CMake+QT+大漠插件的桌面应用开发

简介

  • 在CMake+大漠插件的应用开发——处理dm.dll,免注册调用大漠插件中已经说明了如何免注册调用大漠插件,以及做了几个简单的功能调用(查找窗口、截图)
  • 下面来利用QT做一个简单的窗口查找、截图的桌面工具应用,功能点如下
    • 点击“注册”选项完成大漠插件的注册。
    • 用户在文本框输入窗口标题后,点击“查询”按钮,可对包含该标题的窗口进行查询。
    • 提供表格展示查询到的窗口信息。
    • 点击“截图”按钮,对选中的窗口进行截图并保存。
  • 界面如下

image.png

  • 目前主窗口的UI操作和大漠的调用是在一个线程里面的,当大漠调用时间过长时会出现UI界面卡顿的现象,下一篇将会给出如何处理这种问题的示例。

环境

版本/规范备注
平台win32操作系统为Windows10
CMake3.27.8CLion自带
C++17
ToolchainVisualStudio 2022只用其工具链,记得先安装好
QT5.12.12安装时选择msvc2017,不要64位的
DM7.2353
CLion2023.3.2你也可以用其他IDE工具
  • 启动IDE时,记得以管理员模式启动

项目结构

  • 新建一个项目 qt_dm_demo_x_01
  • 将下载好的 dm.dll 文件以及处理好的 dm.tlh、dm.tli 文件放置到项目的 external 目录下
    • 注:dm.tlh、dm.tli 文件的生成请参考 CMake+大漠插件的应用开发——处理dm.dll,免注册调用大漠插件
qt_dm_demo_x_01					     # 项目目录
--|cmake-build-debug-visual-studio	 # 工程构建目录,存临时生成的文件
--|--|...
--|external					         # 引入第三方库文件的所在的文件夹
--|--|dm.dll                         # 大漠插件的dll
--|--|dm.tlh
--|--|dm.tli
--CMakeLists.txt		             # CMake脚本文件
--dmutil.cpp                         # 大漠的功能封装工具
--dmutil.h                           # 大漠的功能封装工具
--main.cpp					         # 程序入口
--mymainwindow.cpp                   # 主窗口
--mymainwindow.h                     # 主窗口
--mymainwindow.ui                    # 主窗口的UI文件
--strutils.cpp                       # 字符串工具
--strutils.h                         # 字符串工具

配置编译环境

  • 配置工具链
    • 和CMake+大漠插件的应用开发——处理dm.dll,免注册调用大漠插件中保持一致即可
  • CMakeLists.txt 文件
cmake_minimum_required(VERSION 3.27)
project(qt_dm_demo_x_01)set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8")set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)# QT安装的msvc地址
set(CMAKE_PREFIX_PATH "C:/Qt/Qt5.12.12/5.12.12/msvc2017")
# 查找QT组件包
find_package(Qt5 COMPONENTSCoreGuiWidgetsREQUIRED)
# 生成可执行文件
add_executable(${PROJECT_NAME} main.cppstrutils.cpp strutils.hdmutil.cpp dmutil.hmymainwindow.cpp mymainwindow.h mymainwindow.ui
)
# 链接需要的QT库
target_link_libraries(${PROJECT_NAME}Qt5::CoreQt5::GuiQt5::Widgets
)target_compile_definitions(${PROJECT_NAME} PRIVATE-DWIN32# -D_DEBUG-D_WINDOWS-D_UNICODE-DUNICODE
)message(STATUS "CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}")
# 拷贝库文件到生成的可执行文件旁边
if (WIN32 AND NOT DEFINED CMAKETOOLCHAIN_FILE)set(DEBUG_SUFFIX)if (MSVC AND CMAKE_BUILD_TYPE MATCHES "Debug")set(DEBUG_SUFFIX "d")endif ()set(QT_INSTALL_PATH "${CMAKE_PREFIX_PATH}")if (NOT EXISTS "${QT_INSTALL_PATH}/bin")set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")if (NOT EXISTS "${QT_INSTALL_PATH}/bin")set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")endif ()endif ()if (EXISTS "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll")add_custom_command(TARGET ${PROJECT_NAME} POST_BUILDCOMMAND ${CMAKE_COMMAND} -E make_directory"$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")add_custom_command(TARGET ${PROJECT_NAME} POST_BUILDCOMMAND ${CMAKE_COMMAND} -E copy"${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll""$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")endif ()foreach (QT_LIB Core Gui Widgets)add_custom_command(TARGET ${PROJECT_NAME} POST_BUILDCOMMAND ${CMAKE_COMMAND} -E copy"${QT_INSTALL_PATH}/bin/Qt5${QT_LIB}${DEBUG_SUFFIX}.dll""$<TARGET_FILE_DIR:${PROJECT_NAME}>")endforeach (QT_LIB)
endif ()# 拷贝资源文件 dm.dll
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/external DESTINATION ${CMAKE_CURRENT_BINARY_DIR})

代码

  • dmutil.h
#ifndef DM_DEMO_X_DMUTIL_H
#define DM_DEMO_X_DMUTIL_H#include <string>
#include <vector>// #import "./external/dm.dll" no_namespace
#include "./external/dm.tlh"#define DM_LIB_PATH L"./external/dm.dll"using namespace std;struct MyWindow {long hwnd;wstring title;long processId;
};/*** 注册dm.dll,获取大漠实例* @return 大漠实例*/
Idmsoft *GetDmObject();/*** 初始化大漠插件,并注册用户VIP* @return 大漠实例*/
Idmsoft *initialDMAndRegVIP();/*** 获取匹配的窗口* @param baseVec 保存window的容器* @param pDm 大漠插件* @param title 窗口标题中的字段(模糊匹配)* @param processName 进程名称(精确匹配,不区分大小写),默认不会根据进程名筛选窗口*/
void getMatchedWindows(vector<MyWindow>& baseVec, Idmsoft *pDm, const wstring& title, const wstring& processName = L"");#endif //DM_DEMO_X_DMUTIL_H
  • dmutil.cpp(记得填入自己的 注册码附加码
#include <iostream>
#include <sstream>
#include <string_view>
#include <vector>
#include "dmutil.h"
#include "strutils.h"using namespace std;Idmsoft *GetDmObject() {Idmsoft *m_dm = nullptr;bool m_bInit = false;typedef HRESULT(_stdcall*pfnGCO)(REFCLSID, REFIID, void**);pfnGCO fnGCO = nullptr;HINSTANCE hdllInst = LoadLibrary(DM_LIB_PATH);if (hdllInst == nullptr) {cout << "Load library 'dm.dll' failed ! DM_LIB_PATH = " << DM_LIB_PATH << endl;return nullptr;}fnGCO = (pfnGCO) GetProcAddress(hdllInst, "DllGetClassObject");if (fnGCO != nullptr) {IClassFactory *pcf = nullptr;HRESULT hr = (fnGCO)(__uuidof(dmsoft), IID_IClassFactory, (void **) &pcf);if (SUCCEEDED(hr) && (pcf != nullptr)) {hr = pcf->CreateInstance(nullptr, __uuidof(Idmsoft), (void **) &m_dm);if ((SUCCEEDED(hr) && (m_dm != nullptr)) == FALSE) {cout << "Create instance 'Idmsoft' failed !" << endl;return nullptr;}}pcf->Release();m_bInit = true;}return m_dm;
}Idmsoft *initialDMAndRegVIP() {Idmsoft *pDm = GetDmObject();if (pDm == nullptr) {cout << "===> dm.dll registration failed !" << endl;return nullptr;}// 注册dm.dll成功,打印版本cout << "===> DM version: " << (char *) pDm->Ver() << endl;// 注册用户(同一程序下,只需注册一次,后续不用重复注册)long regResult = pDm->Reg(L"注册码", L"版本附加信息(附加码)");if (regResult != 1) {cout << "===> Account registration failed ! code = " << regResult << endl;return nullptr;}cout << "===> Account registration successful ! " << endl;// long releaseRes = pDm->ReleaseRef();// cout << "===> ReleaseCode = " << releaseRes << endl;return pDm;
}void getMatchedWindows(vector<MyWindow>& baseVec, Idmsoft *pDm, const wstring& title, const wstring& processName) {// 获取匹配的窗口句柄_bstr_t hwnds;if (!processName.empty()) {hwnds = pDm->EnumWindowByProcess(processName.c_str(), title.c_str(), L"", 1 + 8 + 16);} else {hwnds = pDm->EnumWindow(0, title.c_str(), L"", 1 + 4 + 8 + 16);}// 拆分找到的多个窗口句柄string content(hwnds);vector<string_view> hwndStrVec = splitSV(content, ",");// 装入容器vectorbaseVec.reserve(hwndStrVec.size());for (const string_view& element : hwndStrVec) {long curHwnd = viewToInt(element);// 获取窗口titleconst _bstr_t &curTitle = pDm->GetWindowTitle(curHwnd);// const _bstr_t &className = pDm->GetWindowClass(curHwnd);long processId = pDm->GetWindowProcessId(curHwnd);baseVec.push_back({curHwnd, {curTitle}, processId});}}
  • strutils.h
#ifndef DM_DEMO_X_STRUTILS_H
#define DM_DEMO_X_STRUTILS_H#include <string>
#include <string_view>
#include <iostream>
#include <vector>using namespace std;/*** 按分隔符拆分字符串内容为vector,string_view更加高效* @param content 待分隔的字符串* @param delim 分隔符,默认为空格* @return vector容器*/
vector<string_view> splitSV(string_view content, string_view delim = " ");/*** string_view 转 int,失败时抛出异常* @param content 字符串内容view* @return int值*/
int viewToInt(string_view content);#endif //DM_DEMO_X_STRUTILS_H
  • strutils.cpp
#include <sstream>
#include <string>
#include <vector>
#include <charconv>#include "strutils.h"vector<string_view> splitSV(string_view content, string_view delim) {vector<string_view> output;size_t first = 0;while (first < content.size()) {const auto second = content.find_first_of(delim, first);if (first != second)output.emplace_back(content.substr(first, second - first));if (second == string_view::npos)break;first = second + 1;}return output;
}int viewToInt(string_view content) {int num;auto result = std::from_chars(content.data(), content.data() + content.size(), num);if (result.ec == std::errc::invalid_argument) {throw std::runtime_error("Could not convert.");}return num;
}
  • mymainwindow.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>MyMainWindow</class><widget class="QMainWindow" name="MyMainWindow"><property name="geometry"><rect><x>0</x><y>0</y><width>400</width><height>300</height></rect></property><property name="windowTitle"><string>窗口查询程序</string></property><widget class="QWidget" name="centralwidget"><layout class="QVBoxLayout" name="verticalLayout"><item><layout class="QHBoxLayout" name="horizontalLayout"><item><spacer name="horizontalSpacer"><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="sizeHint" stdset="0"><size><width>40</width><height>20</height></size></property></spacer></item><item><widget class="QLabel" name="label"><property name="font"><font><weight>75</weight><bold>true</bold></font></property><property name="text"><string>窗口标题:</string></property></widget></item><item><widget class="QLineEdit" name="edtTitle"><property name="minimumSize"><size><width>200</width><height>0</height></size></property></widget></item><item><widget class="QPushButton" name="btnQuery"><property name="text"><string>模糊查询</string></property></widget></item><item><spacer name="horizontalSpacer_3"><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="sizeHint" stdset="0"><size><width>40</width><height>20</height></size></property></spacer></item><item><widget class="QPushButton" name="btnCapture"><property name="text"><string>截图(选中行)</string></property></widget></item><item><spacer name="horizontalSpacer_2"><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="sizeHint" stdset="0"><size><width>40</width><height>20</height></size></property></spacer></item></layout></item><item><widget class="QTableWidget" name="tableWidget"/></item></layout></widget><widget class="QMenuBar" name="menubar"><property name="geometry"><rect><x>0</x><y>0</y><width>400</width><height>21</height></rect></property><widget class="QMenu" name="menuOperation"><property name="title"><string>菜单</string></property><addaction name="actionReg"/></widget><addaction name="menuOperation"/></widget><widget class="QStatusBar" name="statusbar"/><action name="actionReg"><property name="text"><string>注册DM</string></property></action></widget><resources/><connections/>
</ui>
  • mymainwindow.h
#ifndef QT_DM_DEMO_X_MYMAINWINDOW_H
#define QT_DM_DEMO_X_MYMAINWINDOW_H#include <QMainWindow>#include "dmutil.h"QT_BEGIN_NAMESPACE
namespace Ui { class MyMainWindow; }
QT_END_NAMESPACEclass MyMainWindow : public QMainWindow {
Q_OBJECT
public:explicit MyMainWindow(QWidget *parent = nullptr);~MyMainWindow() override;public:void showInfo(const QString &message, const QString &title = "提示");void showWarn(const QString &message, const QString &title = "告警");/*** 注册大漠* @param pDm 大漠插件,待赋值*/void doRegDM(Idmsoft **pDm);/*** 查询匹配的窗口* @param pDm 大漠插件* @param title 窗口标题(模糊查询)*/void doFindWindow(Idmsoft *pDm, const QString &title);/*** 对窗口截图* @param pDm 大漠插件* @param hwnd 窗口句柄*/void doCaptureWindow(Idmsoft *pDm, long hwnd);public slots:void showMessageBox(bool result, const QString &message);void showTableView(bool result, const QString &msg, const vector<MyWindow> &windowVec);private:Ui::MyMainWindow *ui;Idmsoft *pCommonDm = nullptr;
};#endif //QT_DM_DEMO_X_MYMAINWINDOW_H
  • mymainwindow.cpp

// You may need to build the project (run Qt uic code generator) to get "ui_MyMainWindow.h" resolved#include <QFont>
#include <QHeaderView>
#include <QMessageBox>
#include <QPushButton>
#include <QAction>
#include <QString>
#include <QTableWidgetItem>
#include <QObject>
#include <QVector>
#include <iostream>
#include "mymainwindow.h"
#include "ui_MyMainWindow.h"using namespace std;MyMainWindow::MyMainWindow(QWidget *parent) :QMainWindow(parent), ui(new Ui::MyMainWindow) {ui->setupUi(this);// Init ViewssetFixedSize(1280, 720);ui->tableWidget->setColumnCount(3);ui->tableWidget->setHorizontalHeaderLabels(QStringList() << "进程ID" << "句柄" << "标题");ui->tableWidget->horizontalHeader()->setStretchLastSection(true); // 最后一列自动铺满表格// ui->tableWidget->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);ui->tableWidget->horizontalHeader()->setHighlightSections(false);ui->tableWidget->horizontalHeader()->setStyleSheet("QHeaderView::section{background:gray;}");ui->tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);QFont font = ui->tableWidget->horizontalHeader()->font();font.setBold(true);ui->tableWidget->horizontalHeader()->setFont(font);ui->tableWidget->setStyleSheet("QTableWidget::item:hover { background-color: lightblue; }");ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); // 禁止编辑ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows); // 选中整行// Init Listener// 注册大漠connect(ui->actionReg, &QAction::triggered, [this]() {ui->actionReg->setEnabled(false);this->doRegDM(&this->pCommonDm);ui->actionReg->setEnabled(true);});// 查找窗口connect(ui->btnQuery, &QPushButton::clicked, [this]() {ui->btnQuery->setEnabled(false);this->doFindWindow(this->pCommonDm, ui->edtTitle->text());ui->btnQuery->setEnabled(true);});// 截图connect(ui->btnCapture, &QPushButton::clicked, [this]() {ui->btnCapture->setEnabled(false);// 获取选中行的句柄列的字段const QList<QTableWidgetItem *> &selectedItems = ui->tableWidget->selectedItems();if (selectedItems.size() >= 2) {QTableWidgetItem *item = selectedItems.at(1);const QString &hwnd = item->data(Qt::DisplayRole).toString();bool res = false;long hwndL = hwnd.toLong(&res, 0);cout << res << endl;if (res) {this->doCaptureWindow(this->pCommonDm, hwndL);} else {this->showWarn("选中行的窗口句柄解析异常!");}} else {this->showWarn("请选中列表中的其中一行!");}ui->btnCapture->setEnabled(true);});}MyMainWindow::~MyMainWindow() {delete ui;
}void MyMainWindow::showInfo(const QString &message, const QString &title) {QMessageBox::information(this, title, message);
}void MyMainWindow::showWarn(const QString &message, const QString &title) {QMessageBox::critical(this, title, message);
}void MyMainWindow::showMessageBox(const bool result, const QString& message) {if (result) {this->showInfo(message);} else {this->showWarn(message);}
}void MyMainWindow::showTableView(bool result, const QString &msg, const vector<MyWindow> &windowVec) {if (result) {auto rowNum = windowVec.size();ui->tableWidget->setRowCount(rowNum);for (int i = 0; i < rowNum; ++i) {const MyWindow &item = windowVec[i];ui->tableWidget->setItem(i, 0, new QTableWidgetItem(QString::number(item.processId)));ui->tableWidget->setItem(i, 1, new QTableWidgetItem(QString::number(item.hwnd)));ui->tableWidget->setItem(i, 2, new QTableWidgetItem(QString::fromStdWString(item.title)));}} else {this->showWarn(msg);}
}void MyMainWindow::doRegDM(Idmsoft **pDm) {cout << "========== Initial DM ............ ==========" << endl;*pDm = initialDMAndRegVIP();if (*pDm == nullptr) {cout << "========== Initial DM <Failed>     ==========" << endl;showMessageBox(false, "DM 注册失败!");return;}cout << "========== Initial DM <Successful> ==========" << endl;cout << endl;showMessageBox(true, "DM 注册完成!");
}void MyMainWindow::doFindWindow(Idmsoft *pDm, const QString &title) {vector<MyWindow> windowVec;if (pDm == nullptr) {cout << "this->pCommonDm == nullptr" << endl;this->showTableView(false, "请先在菜单中完成注册!", windowVec);return;}// 找一下title包含findStr的窗口,并打印信息getMatchedWindows(windowVec, pDm, title.toStdWString());if (windowVec.empty()) {cout << "can not find such window" << endl;this->showTableView(false, "没有找到包含该标题的窗口!", windowVec);return;}this->showTableView(true, "成功!", windowVec);
}void MyMainWindow::doCaptureWindow(Idmsoft *pDm, long hwnd) {if (pDm == nullptr) {cout << "this->pCommonDm == nullptr" << endl;this->showMessageBox(false, "请先在菜单中完成注册!");return;}// 绑定窗口句柄long dmBind = pDm->BindWindowEx(hwnd,"normal","normal","normal","",0);if (dmBind == 1) {// 恢复并激活指定窗口,置顶窗口,pDm->SetWindowState(hwnd, 12);pDm->SetWindowState(hwnd, 8);pDm->delay(600);// 延迟一下截图,存到相对路径wstring filename = wstring(L"./capture_window_").append(std::to_wstring(hwnd)).append(L".bmp");long retCap = pDm->Capture(0, 0, 2000, 2000, filename.c_str());if (retCap != 1) {cout << "capture failed" << endl;this->showMessageBox(false, "截图失败!");} else {cout << "capture success" << endl;this->showMessageBox(true, QString::fromStdWString(L"截图成功,保存地址为: " + filename));}// 取消置顶窗口pDm->SetWindowState(hwnd, 9);} else {cout << "DM BindWindow failed" << endl;this->showMessageBox(false, "绑定窗口异常!");}pDm->UnBindWindow();
}
  • main.cpp
#include <QApplication>
#include <iostream>
#include "mymainwindow.h"
using namespace std;int main(int argc, char *argv[]) {setlocale(LC_ALL, "chs");QApplication a(argc, argv);MyMainWindow mainWindow;mainWindow.show();return QApplication::exec();
}

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

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

相关文章

【STM32】STM32学习笔记-USART串口收发HEX和文本数据包(29)

00. 目录 文章目录 00. 目录01. 串口简介02. 串口收发HEX数据包接线图03. 串口收发HEX数据包示例104. 串口收发HEX数据包示例205. 串口收发文本数据包接线图06. 串口收发文本数据包示例07. 程序示例下载08. 附录 01. 串口简介 串口通讯(Serial Communication)是一种设备间非常…

科研绘图(五)玫瑰图

柱状图的高级平替可视化 “玫瑰图”&#xff0c;通常也被称为“科克斯图”。它类似于饼图&#xff0c;但不同之处在于每个部分&#xff08;或“花瓣”&#xff09;的角度相同&#xff0c;半径根据它表示的值而变化。这种可视化工具对于周期性地显示信息非常有用&#xff0c;比…

Spring Boot 中批量执行 SQL 脚本的实践

在Spring Boot应用中&#xff0c;有时候我们需要批量执行存储在数据库中的 SQL 脚本。本文将介绍一个实际的案例&#xff0c;演示如何通过 Spring Boot、MyBatis 和数据库来实现这一目标。 0、数据库层 CREATE TABLE batchUpdate (id INT AUTO_INCREMENT PRIMARY KEY,update_…

TCP连接TIME_WAIT

TCP断开过程: TIME_WAIT的作用: TIME_WAIT状态存在的理由&#xff1a; 1&#xff09;可靠地实现TCP全双工连接的终止 在进行关闭连接四次挥手协议时&#xff0c;最后的ACK是由主动关闭端发出的&#xff0c;如果这个最终的ACK丢失&#xff0c;服务器将重发最终的FIN&#xf…

CSS3中多列布局详解

多列布局 概念&#xff1a;在CSS3之前&#xff0c;想要设计类似报纸那样的多列布局&#xff0c;有两种方式可以实现&#xff1a;一种是"浮动布局"&#xff0c;另一种是“定位布局”。 这两种方式都有缺点&#xff1a;浮动布局比较灵活&#xff0c;但不容易控制&…

用Python“自动连发消息”

自动连发消息&#xff0c;基本上C和Python的思路都是不停的模拟“击键”操作&#xff0c;还有一种VB的脚本写法&#xff0c;反成每种语言都能写&#xff0c;更厉害的可以用java做出个GUI界面&#xff0c;先上代码。 一 代码 import pyautogui # 鼠标 import p…

C++力扣题目101--对称二叉树

101. 对称二叉树 力扣题目链接(opens new window) 给定一个二叉树&#xff0c;检查它是否是镜像对称的。 思路 首先想清楚&#xff0c;判断对称二叉树要比较的是哪两个节点&#xff0c;要比较的可不是左右节点&#xff01; 对于二叉树是否对称&#xff0c;要比较的是根节点…

Linux命令之用户账户管理whoami,useradd,passwd,chage,usermod,userdel的使用

1、查看当前用户账户 2、切换用户为root用户 3、新建用户user1&#xff0c;给用户user1设置密码为password123 4、新建用户user2&#xff0c;UID为510&#xff0c;指定其所属的私有组为group1&#xff08;group1组的标识符为500&#xff09;&#xff0c;用户的主目录为/home/us…

codesys【程序】

FB&#xff1a; 用于实现 PLC【叠】PLC FB功能块&#xff1a; 包含 输入&#xff0c;输出&#xff0c;局部变量&#xff0c;静态变量 用ST语言&#xff0c;方便复制。FUNCTION_BLOCK FB_CAN轴 VAR_INPUT 输入 END_VAR VAR_OUTPUT 输出 END_VAR VAR …

【MATLAB源码-第110期】基于matlab的哈里斯鹰优化算发(HHO)无人机三维路径规划,输出做短路径图和适应度曲线。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 哈里斯鹰优化算法&#xff08;Harris Hawk Optimization, HHO&#xff09;是一种受自然界捕食行为启发的优化算法。它基于哈里斯鹰的捕猎策略和行为模式&#xff0c;主要用于解决各种复杂的优化问题。这个算法的核心特征在于…

vue3-列表渲染

v-for 我们可以使用 v-for 指令基于一个数组来渲染一个列表。 v-for 指令的值需要使用 (item in items) 形式的特殊语法&#xff0c;其中 items 是源数据的数组&#xff0c;而 item 是迭代项的别名&#xff0c; (item, index) in items index 表示当前项的位置索引(可选参数)…

深度学习-标注文件处理(txt批量转换为json文件)

接上篇&#xff0c;根据脚本可将coco128的128张图片&#xff0c;按照比例划分成训练集、测试集、验证集&#xff0c;同时生成相应的标注的labels文件夹&#xff0c;最近再看实例分离比较火的mask rcnn模型&#xff0c;准备进行调试但由于实验室算力不足&#xff0c;网上自己租的…

JVM知识总结(持续更新)

这里写目录标题 java内存区域程序计数器虚拟机栈本地方法栈堆方法区运行时常量池 对象的创建 java内存区域 Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域&#xff1a; 程序计数器虚拟机栈本地方法栈堆方法区 程序计数器 记录下一条需要…

【ArcGIS遇上Python】ArcGIS Python批量筛选多个shp中指定字段值的图斑(以土地利用数据为例)

文章目录 一、案例分析二、提取效果二、代码运行效果三、Python代码四、数据及代码下载一、案例分析 以土地利用数据为例,提取多个shp数据中的旱地。 二、提取效果 原始土地利用数据: 属性表: 提取的旱地:(以图层名称+地类名称命名)

基于python舆情分析可视化系统+情感分析+爬虫+机器学习(源码)✅

大数据毕业设计&#xff1a;Python招聘数据采集分析可视化系统✅ 毕业设计&#xff1a;2023-2024年计算机专业毕业设计选题汇总&#xff08;建议收藏&#xff09; 毕业设计&#xff1a;2023-2024年最新最全计算机专业毕设选题推荐汇总 &#x1f345;感兴趣的可以先收藏起来&…

Python 自学(八) 之模块

目录 1. import语句导入模块 P206 2. from ... import 语句导入模块 P207 3. 模块的搜索目录 sys.path P209 4. 以主程序的形式执行 __name__ P212 5. python中的包 P213 1. import语句导入模块 P206 同一目录下&…

响应式Web开发项目教程(HTML5+CSS3+Bootstrap)第2版 第1章 HTML5+CSS3初体验 项目1-1 三栏布局页面

项目展示 三栏布局是一种常用的网页布局结构。 除了头部区域、底部区域外&#xff0c;中间的区域&#xff08;主体区域&#xff09;划分成了三个栏目&#xff0c;分别是左侧边栏、内容区域和右侧边栏&#xff0c;这三个栏目就构成了三栏布局。当浏览器的宽度发声变化时&#x…

【java八股文】之JVM基础篇

【java八股文】之JVM基础篇-CSDN博客 【java八股文】之MYSQL基础篇-CSDN博客 【java八股文】之Redis基础篇-CSDN博客 【java八股文】之Spring系列篇-CSDN博客 【java八股文】之分布式系列篇-CSDN博客 【java八股文】之多线程篇-CSDN博客 【java八股文】之JVM基础篇-CSDN博…

设计模式-委托模式

设计模式专栏 模式介绍模式特点应用场景委托模式在GUI编程场景的应用代码示例Java实现委托模式Python实现委托模式 委托模式在spring中的应用 模式介绍 委托模式是一种软件设计模式&#xff0c;其中一个对象&#xff08;委托对象&#xff09;将某些操作委托给另一个对象&#…

css深度选择器 /deep/

一、/deep/的含义和使用 /deep/ 是一种 CSS 深度选择器&#xff0c;也被称为深度组合器或者阴影穿透组合器&#xff0c;主要用在 Web 组件样式封装中。 在 Vue.js 或者 Angular 中&#xff0c;使用了样式封装技术使得组件的样式不会影响到全局&#xff0c;也就是说组件内部的…