2501wtl,皮肤技术
下载地址
设计目标
最重要的是使用方便,已有程序创建一个COM对象,调一个方法就可把界面外观全部改成Mac风格的.
另外一个目标是要有扩展性.
所以,基本设计是定义一个统一的接口,然后用不同实现.每一个实现单独放在一个COMDLL中,调用者选择一个类标创建对象就行了.
接口的定义:
interface ISkinX : IUnknown{[helpstring("Install Skin hook")] HRESULT InstallSkin([in] long lThreadID);[helpstring("Uninstall Skin hook")] HRESULT UninstallSkin();};
调用InstallSkin安装皮肤,UninstallSkin卸掉皮肤,lThreadID是线程ID.
原理
就是通过消息勾挂改变已有控件的外观.
好处是可不必修改程序已完成的标准界面,只要勾挂上勾挂函数,所有的界面就都变了,使用起来非常方便.
原理就是下面的调用:
SetWindowsHookEx(WH_CALLWNDPROC, HookProc, 0, lThreadID);
WH_CALLWNDPROC勾挂,可拦截所有线程ID为lThreadID的线程内的窗口消息,这样就可处理这些消息.
但是,光拦截消息还不够,还必须知道是谁发出的这些消息.
幸好,从消息的参数里,可得到窗口句柄,而通过窗口句柄,可得到窗口类.这里说的窗口类是窗口系统中的窗口类名.
如,按钮的窗口类是"按钮",组合框的窗口类是"ComboBox"...这些在MSDN里面都可找到的,另外,还有一些文档中没有的窗口类名,比如对话框,有一个叫"#32770"的类名,而菜单,实际上也是一个窗口,其类名是"#32768".
有了这些信息,就可区分不同窗口处理了.
处理消息,显然最重要的是WM_PAINT消息.这样可重载系统默认的绘画方式,把控件窗口画成想要的样子.
但是只处理WM_PAINT消息也是不够的,因为控件的风格不是一成不变的,看看窗口xp的显示效果,以按钮为例,有很多种风格,普通风格,鼠标在按钮上的风格,鼠标按住按钮的风格,鼠标按住按钮又移动到按钮外的风格
为了实现动态的炫目的皮肤效果,还需要截取一些其他消息,如鼠标消息.下载代码里有Mac按钮的一个实现,看一下就知道了.
有了勾挂,就可截取所有消息,有了窗口类,就可识别窗口类型,对不同类型的窗口给予不同处理.
这样,要在勾挂函数里面识别不同窗口和不同消息,有大量的分发工作,更重要的是,光区分窗口类还不够,同类型的不同窗口经常需要不同处理,如两个按钮窗口,大小不同,文字不同,是否有鼠标按下不同.
这些状态有些是可从按钮窗口读到的,如大小和文字,而有些则读不到,比如是否按下鼠标,对这些读不到的状态,必须自己记录,如在收到WM_LBUTTONDOWN消息时记下按下了按钮.
也即,对每个窗口,还需要记录一些与其相应的数据,这样在收到WM_PAINT消息时做不同处理.把所有这些逻辑写在勾挂函数里显然太麻烦了,即使写出来也没法维护,需要一个好的设计.
根据面向对象的思想,需要为每种窗口类型写一个类,并为每个窗口生成一个对应类的实例,由这些实例来处理窗口消息,并记录必要的窗口状态数据.
这样,就由这些对象处理窗口消息,怎么给这些对象传递消息呢,可以转发勾挂函数,不过这里用了另一个:SubclassWindow,SubclassWindow的原理,就不多讲了,可参看MSDN,其实就是替换一个窗口过程函数.
ATL提供了现成的支持,用起来还是很方便的,替代的窗口过程函数不用全部自己写,而可用消息映射宏生成.
现在用SubclassWindow的方式,可直接把对象链接到窗口的消息链中,这好像有点和勾挂函数的功能重复了,因为勾挂函数本来就是用来拦截消息的.
现在SubclassWindow以后,已可拦截了窗口消息,那还要勾挂函数干什么呢?
答案是:用勾挂函数来执行SubclassWindow操作.原因有两个,第一,要做的是一个皮肤插件,想用户调用一个函数就可改变整个界面风格,而不是为每个窗口调用SubclassWindow函数;
第二,创建有些窗口,根本不是在代码里控制的,如菜单窗口,除了使用勾挂函数,甚至不能取得菜单窗口的句柄.
所以,必须使用勾挂函数,但在勾挂函数中,只处理一个消息:WM_CREATE,在创建一个可识别窗口时,生成一个对象实例,并用SubclassWindow勾挂该实例到目标窗口,让该对象实例去完成剩下的事情.
总结一下:
1,为每种可识别的窗口类编写类,实现必要的消息处理及保存状态;
2,用勾挂函数拦截WM_CREATE消息,并创建对应的类实例;
3,通过SubclassWindow操作把生成的类实例勾挂到目标窗口,处理消息及保存状态;
对PushButton绘画的问题,我冒昧对你的代码做了点修改.思路就是在子类化按钮后,将按钮的风格改成自绘画,这样就不会和按钮自身的绘画干扰了,而且我估计只要处理WM_DRAWITEM和WM_MEASUREITEM消息就可以了,不过我没有这么试过.
但是复选框和RadioButton没有BS_OWNERDRAW风格,所以没法这么做.绘画干扰问题还没有解决.下面贴出我对CMacButton修改过的地方:
1,增加long m_iCtrlType;成员变量
2,
void Initialize(){m_iCtrlType=-1;//..m_nState = STATE_NORMAL;m_bTracking = false;if(BASETYPE_BUTTON==GetBaseType())//..{::SetWindowLong(m_hWnd,GWL_STYLE,::GetWindowLong(m_hWnd,GWL_STYLE)|BS_OWNERDRAW);}}
3,long GetBaseType(){if(m_iCtrlType!=-1)return m_iCtrlType;//..long lStyle = GetWindowLong(GWL_STYLE);if ( (lStyle & BS_OWNERDRAW) == BS_OWNERDRAW )//`物主画`return m_iCtrlType=BASETYPE_OWNERDRAW;//..if ((lStyle & BS_GROUPBOX)==BS_GROUPBOX)//组框return m_iCtrlType=BASETYPE_GROUPBOX;else if ((lStyle & BS_CHECKBOX)==BS_CHECKBOX|| (lStyle & BS_AUTOCHECKBOX) == BS_AUTOCHECKBOX )//复选框return m_iCtrlType=BASETYPE_CHECKBOX;else if ((lStyle & BS_AUTORADIOBUTTON)==BS_AUTORADIOBUTTON|| (lStyle & BS_RADIOBUTTON)==BS_RADIOBUTTON)//收音机return m_iCtrlType=BASETYPE_RADIOBUTTON;//普通按钮return m_iCtrlType=BASETYPE_BUTTON;}
这样,要为每种需要改变外观的控件窗口编写一个类,很自然的想到取出它们的公共基类,这就是CWidgetHookBase,所有控件窗口处理类的公共基类,实际上是一个C++接口,因为它只包含一个纯虚函数,下面是它的定义:
组件勾挂的抽象基类
class CWidgetHookBase
{
public:virtual void Install(HWND hWidget) = 0; //在`CWidgetHook`中实现
};
该接口中唯一的安装函数,用来实现把对象链接到窗口的功能,也就是SubclassWindow,这会在继承类实现.
这里要讲的实际上是控件类工厂,也就是CWidgetFactory及其继承类.下面是CWidgetFactory的完整声明和实现:
///用来勾挂`组件`的抽象工厂类.创建`勾挂`实例
class CWidgetFactory
{
protected:static CWidgetFactory* m_pInstance;
public://初化实例CWidgetFactory(){ATLASSERT(m_pInstance==NULL);m_pInstance = this;}//取单例实例static CWidgetFactory* Instance(){return m_pInstance;}virtual CWidgetHookBase* CreateWidget(LPCTSTR szClass) = 0;
};
CWidgetFactory* CWidgetFactory::m_pInstance = NULL;
CWidgetFactory使用了两个设计模式,单件模式和抽象工厂模式,实际上还包括抽象方法模式.
首先看抽象工厂模式,想让控件工厂根据窗口类的名字创建出不同控件的窗口消息处理类.对仿真Mac的系统,这些控件窗口消息处理类包括CMacButton,CMacComboBox,CMacTrackBar等;
而对仿真KDE的系统,则是CKDEButton,CKDEComboBox等.这样,就可定义两个CWidgetFactory的继承类,分别叫CMacFactory和CKDEFactory,分别产生这两个族的对象.
CWidgetFactory::CreateWidget就是用来产生这些对象的方法,它是个必须在继承类中实现的纯虚函数.CreateWidget接受窗口类的名字为参数,返回所有控件类的基类的CWidgetHookBase指针.
这样,每个对象工厂负责产生一族对象,但对一个应用来说,应该只有一个风格,也即,只有一个工厂的实例,单件模式来了.
这里使用简化版的单件模式,需要声明一个继承类的实例,然后通过CWidgetFactory的实例静态函数得到该唯一实例.
这里没有控制不能生成第二个实例,不过问题不大.
现在来看工厂的一个实现,CMacFactory,完整的代码如下:
class CMacFactory : public CWidgetFactory
{
public:virtual CWidgetHookBase* CreateWidget(LPCTSTR szClass){if (lstrcmpi(szClass, "Button") == 0 )return new CMacButton;else if (lstrcmpi(szClass, "#32770") == 0) //对话return new CMacDialog;else if (lstrcmpi(szClass, "ListBox") == 0)return new CMacListBox;else if (lstrcmpi(szClass, WC_TABCONTROL) == 0)return new CMacTabCtrl;else if (lstrcmpi(szClass, "#32768") == 0) //菜单return new CMacMenu;else if (lstrcmpi(szClass, "ComboBox") == 0) //组合框return new CMacCombo;else if (lstrcmpi(szClass, TRACKBAR_CLASS) == 0) //跟踪杆return new CMacTrackBar;return NULL;}
};
再看看消息勾挂的代码:
LRESULT CALLBACK CMacSkin::HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{CWPSTRUCT cwps;if( nCode == HC_ACTION ){CopyMemory(&cwps, (LPVOID)lParam, sizeof(CWPSTRUCT));switch(cwps.message){case WM_CREATE:{CHAR szClass[MAX_PATH];GetClassName(cwps.hwnd, szClass, MAX_PATH);CWidgetHookBase* pWidget=NULL;pWidget = CWidgetFactory::Instance()->CreateWidget(szClass);if (pWidget)pWidget->Install(cwps.hwnd);}break;}}return CallNextHookEx((HHOOK)CMacSkin::m_hHook, nCode, wParam, lParam);
}
不管对CMacFactory还是其他的工厂实现,及不同控件类族,勾挂函数的实现都是一样的.CWidgetFactory继承类的实现也类似,只是替换一些类名而已.
现在,有了控件类的接口:CWidgetHookBase,产生控件对象的工厂也有了,下面就该实现控件类了.在定义控件基类时,只定义了一个抽象的安装函数,而没有其他代码,则,所有实现代码都交给各个控件类去实现吗?
不是,这些控件类还有许多公共代码可在基类实现,但是,选择不在CWidgetHookBase中加入这些代码,而是再加入一个中间类:CWidgetHook.
不可把这两个基类合为一个类呢?其实,最初的设计是只有一个基类的,就是CWidgetHook,而又想在继承类中使用WTL包装窗口控件的类,这样,根据ATL/WTL的架构,CWidgetHook就必须是一个模板类,而模板类是不能作为基类指针的,因为模板是类型不定的,而抽象工厂模式要求一个基类指针,所以又取出CWidgetHookBase此纯虚的接口类.
下面是CWidgetHook模板类的声明:
//`//`所有`组件`勾挂的基类/参数:`/T/`继承类`/TBase/Widget`窗口包装器,为了方便,使用`WTL`包装器template <class T, class TBase = CWindow>
class CWidgetHook : public CWidgetHookBase, public CWindowImpl<T, TBase>
//CRTP
这里用了多继承,它也是ATL里常用的,第一个父类是前面定义的CWidgetHookBase接口,需要该接口来实现抽象工厂设计模式.
第二个父类是CWindowImp,这是ATL定义的,是所有窗口类的(虽然不是顶层)高层父类.
CWindowImp接收两个模板参数,同时也是CWidgetHook的模板参数.第一个模板参数是继承类,这也是ATL中常用的技巧,该技巧使得可在父类中知道继承类的类型,于是,把本指针转换成继承类的类型,就可调用继承类的方法,这样实现了类似虚函数的多态,却不需要付出虚函数的性能代价.
追踪ATL的代码,可见其实TBase参数最终是作为基类的,通过模板参数改变基类,这也是模板与OO不同的地方.
TBase有一个默认CWindow值,可在此传入其他类,但必须是CWindow的继承类,最有价值的参数当然是WTL窗口包装类,这样,在实现控件消息处理类时,就可用WTL包装类提供的功能,而不需要只依赖窗口接口了,确实可带来不少帮助.
讲完CWidgetHook的声明.下面来看CWidgetHook的定义和实现,首先看几个函数声明:
void Initialize() {}; //初化实例void Finalize() {}; //实例`终止器`static void InitializeClass() {}; //初化类static void FinalizeClass() {}; //类的`终止器`
上面四个函数都包含了空的实现,在继承类中可选择重载它们.
在生成每个实例时,调用初化,在析构实例前,调用终止器;在生成类的第一个实例时调用InitializeClass静态函数,在析构类的最后实例时调用FinalizeClass.
为什么要有两个静态函数呢,因为一个类代表同一个窗口,这些窗口会使用同样的资源,如复选框,需要几张不同状态的图片,而这些图片对每个复选框来说都是一样的,如果为每个实例保存这样一份资源,就有点浪费内存了.
对一个皮肤插件来说,效率还是很重要的,所以选择用静态变量保存这些图片,并在第一个生成复选框时,加载这些资源,后续生成的其他复选框可重用这些资源,然后在最后复选框消失时释放这些资源,这样,最小化了内存的使用量.
在构造器和析构器中调用这两个静态函数,另外还有个m_lRef实例计数值,下面还剩下OnFinalMessage和安装函数没讲.
OnFinalMessage比较简单,调用Finalize并删除自己,因为是CWindowImp继承类,OnFinalMessage函数会在析构窗口时自动调用它,这样,就保证了会自动释放实例,不会造成泄漏内存.
最后看安装函数,这是在CWidgetHookBase中定义的纯虚函数,在CWidgetHook模板类中实现它.
安装函数的主要功能是调用SubclassWindow,从而控制窗口消息.另外,还控制反射消息和初化实例.
下面是它的代码:
virtual void Install(HWND hWidget){ATLASSERT(::IsWindow(hWidget));SubclassWindow(hWidget);//如果它是子窗口,请为其父窗口安装一个`反射器`,这样`父窗口`会反射回消息给我if ( (::GetWindowLong(hWidget, GWL_STYLE) & WS_CHILD) == WS_CHILD){HWND hWndParent = ::GetParent(hWidget);ATLASSERT(::IsWindow(hWndParent));// `WM_GETREFLECTOR`取已安装的反射器(如果有)CReflectHook* pReflector =(CReflectHook*)::SendMessage(hWndParent, WM_GETREFLECTOR, 0, 0);if (!pReflector)new CReflectHook(hWndParent);}T* pT = static_cast<T*>(this);pT->Initialize();//继承类要实现.在此针对性的初化.}
安装函数是模板方法,它调用的初化方法则要在继承类中重载.则,初化方法是实例的初化函数,不可放在构造器里呢?
因为每个实例的初化可能不太一样,要根据被勾挂的窗口的状态决定,所以,必须等到调用SubclassWindow后,才调用初化方法,在继承类的初化实现中,可通过m_hWnd直接取得窗口句柄,调用API或WTL包装类方法检查窗口状态,并执行必要的实例初化代码.
MFC和ATL都提供了反射消息的机制,就是让父窗口在收到这类消息时,把它们再返回给控件窗口,这就是反射消息.
要实现皮肤插件,也需要在控件窗口类中收到这些消息,但是,不能依赖ATL或MFC的反射,因为想可让不同主机程序使用皮肤插件,而不是局限于ATL和MFC.
其他程序可能没有反射消息机制,或使用了不同反射消息机制.所以,实现了自己的反射消息机制.
CReflectHook类就是用来完成反射消息的,其构造器按参数接受父窗口的句柄,然后调用SubclassWindow把对象实例链接到窗口上去,这和控件的实现类似.
ProcessWindowMessage是个虚函数,它的定义可追述到ATL窗口类的最底层,CReflectHook::ProcessWindowMessage实现反射功能,把收到的需要反射的消息返回给控件窗口.
但也不是简单的原样返回,而是包装成另一个WM_REFLECT消息,以免和其他消息冲突.当反射消息发回给控件窗口时,控件窗口利用下面三个宏展开WM_REFLECT,并得到原消息:
LF_REFLECTED_NOTIFY_CODE_HANDLER
LF_REFLECTED_COMMAND_CODE_HANDLER
LF_REFLECTED_MESSAGE_HANDLER
另外注意WM_GETREFLECTOR消息,可用该自定义消息来向父窗口查询与其关联的CReflectHook实例,以避免重复安装反射勾挂,因为CReflectHook::ProcessWindowMessage为该消息返回了本指针.
CWidgetHook::Install使用了WM_GETREFLECTOR消息.
最后说一下怎么写CWidgetHook继承类(即控件类),这也是直接影响最终效果的.WTL定义了许多常见控件包装类,把这些类作为CWidgetHook的第二个模板参数,可以大大简化后续工作,当然,如果没有对应的包装类,也可接收默认参数.
因为借助了ATL/WTL的基本架构,编写控件类和写一个ATL窗口类类似,可用ATL/WTL消息映射宏,当然,不象MFC一样提供了向导,需要手动输入这些宏.
另外,控件类还可选择的重载CWidgetHook定义的4个初化和清理函数.附带示例中提供了一个Mac按钮类的实现,可参考,该按钮示例算是比较复杂的,因为窗口窗口类名为"按钮"的窗口,实际上包括普通按钮,单选钮和复选框,其他的许多控件实现起来比按钮容易,当然也有一些比较麻烦的.
相关文章:
2501wtl,皮肤技术
下载地址 设计目标 最重要的是使用方便,已有程序创建一个COM对象,调一个方法就可把界面外观全部改成Mac风格的. 另外一个目标是要有扩展性. 所以,基本设计是定义一个统一的接口,然后用不同实现.每一个实现单独放在一个COMDLL中,调用者选择一个类标创建对象就行了. 接口的定义…...
【面试题】技术场景 6、Java 生产环境 bug 排查
生产环境 bug 排查思路 分析日志:首先通过分析日志查看是否存在错误信息,利用之前讲过的 elk 及查看日志的命令缩小查找错误范围,方便定位问题。远程 debug 适用环境:一般公司正式生产环境不允许远程 debug,多在测试环…...
word论文排版常见问题汇总
word论文排版常见问题汇总 常用快捷键: Alt F9 正常模式与域代码模式切换 Ctrl F9 插入域代码 F9 刷新域代码显示,要注意选定后刷新才会有效果 word中在当前列表的基础上修改列表 在使用word时,我们会定义一个列表,并将其链接…...
传奇3仿韩服单机版安装教程+GM管理面板
今天为大家带来一款怀旧网单《传奇3仿韩服》的游戏架设,适用于单机娱乐, 仅供怀旧,本人已经安装游戏成功,特此带来详细安装教程。 适用环境 单机 视频演示 传奇3仿韩服单机 亲测截图 架设步骤 关闭默认杀毒软件和其它自己下的杀…...
第26章 汇编语言--- 内核态与用户态
汇编语言是低级编程语言的一种,它与特定计算机的硬件架构紧密相关。内核态和用户态是操作系统中进程运行的两种不同模式,它们用来区分操作系统内核代码和其他应用程序代码的执行环境。下面我将简要解释这两种状态,并给出一个简单的示例来展示…...
Spring bean的生命周期和扩展
接AnnotationConfigApplicationContext流程看实例化的beanPostProcessor-CSDN博客,以具体实例看bean生命周期的一些执行阶段 bean生命周期流程 生命周期扩展处理说明实例化:createBeanInstance 构造方法, 如Autowired的构造方法注入依赖bean 如UserSer…...
计算机网络 (33)传输控制协议TCP概述
一、定义与基本概念 TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议。它工作在OSI模型的第四层,即传输层,为用户提供可靠的、有序的和无差错的数据传输服务。TCP协议与UDP协议是传输层的两大主要协议,但两者在设计上有明显的不同&…...
Python3 JSON
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。它基于JavaScript编程语言的一个子集,但JSON是独立于语言的,很多编程语言都支持JSON格式数据的…...
Leetcode 698 Partition to K Equal Sum Subsets
题意 给一个数组,要求把数组里的元素分成k个子集,满足每个子集中数的总和是相等的。问是否能分成k个子集 题目链接 https://leetcode.com/problems/partition-to-k-equal-sum-subsets/description/ 思考 想象你有k个桶,然后你有n个小球&…...
可靠的人形探测,未完待续(III)
一不小心,此去经年啊。问大家新年快乐! 那,最近在研究毫米波雷达模块嘛,期望用在后续的产品中,正好看到瑞萨的活动送板子,手一下没忍住。 拿了板子就得干活咯,我一路火花带闪电,开整…...
Git文件夹提交错了,怎么撤销?
最近提交了一些不应该提交的文件夹到git中,现在需要移除它们,现在简单记录一下操作日志: 情况一 文件夹已经被添加到 Git,但未提交 如果文件夹已经被 git add 添加到暂存区中,但尚未提交,你可以使用以下命令将其从暂存区中移除: git rm -r …...
小程序textarea组件键盘弹起会遮挡住输入框
<textarea value"{{remark}}" input"handleInputRemark" ></textarea> 如下会有遮挡: 一行代码搞定 cursor-spacing160 修改后代码 <textarea value"{{remark}}" input"handleInputRemark" cursor-spacin…...
Android车机DIY开发之学习篇(二)编译Kernel以正点原子为例
Android车机DIY开发之学习篇(二)编译Kernel以正点原子为例 1.代码在/kernel-5.10文件夹下 2.在kernel-5.10目录下执行如下命令编译 : 编译之前,需要将 clang 导出到 PATH 环境变量: 如果是 Android12 执行下面这条命令 export PATH../pr…...
qt 窗口(window/widget)绘制/渲染顺序 QPainter QPaintDevice Qpainter渲染 失效 无效
qt窗体布局 窗体渲染过程 qt中窗体渲染逻辑顺序为 本窗体->子窗体/控件 递归,也就是说先渲染父窗体再渲染子窗体。其中子窗体按加入时的先后顺序进行渲染。通过下方的函数调用堆栈可以看出窗体都是在widget组件源码的widgetprivate::drawwidget中进行渲染的&am…...
Ubuntu下载时不显示无线网图标并显示Cable unplugged
我用的是ubuntu22-04-5.iso一下载出来发现无法连接网络甚至直接显示Wired是Cable unplugged. 下面是解决方法: step1: step2:点击编辑中的虚拟网络编辑器 step3: step4: step5: step6:取消勾选自动检测可用的DNS服务器 step7:在window上按下winR输入c…...
微信小程序实现人脸识别登录
hello hello~ ,这里是 code袁~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹 🦁作者简介:一名喜欢分享和记录学习的在校大学生…...
atoi函数的概念和使用案例
atoi 函数是 C 语言标准库中的一个函数,它用于将字符串转换为整数。atoi 的名称是 “ASCII to integer” 的缩写。该函数定义在 <stdlib.h> 头文件中。 概念 atoi 函数会从字符串的开始位置开始转换,直到遇到第一个非数字字符或遇到字符串结束符…...
Mysql--运维篇--日志管理(连接层,SQL层,存储引擎层,文件存储层)
MySQL提供了多种日志类型,用于记录不同的活动和事件。这些日志对于数据库的管理、故障排除、性能优化和安全审计非常重要。 一、错误日志 (Error Log) 作用: 记录MySQL服务器启动、运行和停止期间遇到的问题和错误信息。 查看: 默认情况下…...
poi处理多选框进行勾选操作下载word以及多word文件压缩
一、场景 将数据导出word后且实现动态勾选复选框操作 eg: word模板 导出后效果(根据数据动态勾选复选框) 二、解决方案及涉及技术 ① 使用poi提供的库进行处理(poi官方文档) ② 涉及依赖 <!-- excel工具 --><depen…...
QT 键值对集合QMap
在QT中,可以使用QMap作为键值对的集合。QMap是Qt的一个模板类,它存储了键值对,并且可以通过键来快速查找值。 导入 #include <QMap> 以下是一些使用QMap的方法: 1.创建并初始化一个 QMap<int, QString> UserDepa…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...
