NSIS中能否为Next按钮添加鼠标事件切换按钮图片?
NSIS Next按钮悬停/点击切换图片解决方案
一、原生API实现(无需插件)
由于你已修改modern.exe无法使用graphics-installer,通过原生user32 API结合窗口消息监听可实现需求:
1. 提前加载按钮状态图
先定义正常、悬停、点击三种状态的图片路径,在初始化阶段加载并缓存句柄:
!include "WinMessages.nsh" !include "LogicLib.nsh" ; 定义三种状态的图片路径 !define BTN_NORMAL "btn_normal.bmp" !define BTN_HOVER "btn_hover.bmp" !define BTN_PRESSED "btn_pressed.bmp" ; 全局变量存储图片句柄 Var hBtnNormal Var hBtnHover Var hBtnPressed Function .onInit ; 加载正常状态按钮图 System::Call 'user32::LoadImage(i 0, t "${BTN_NORMAL}", i ${IMAGE_BITMAP}, i 0, i 0, i ${LR_CREATEDIBSECTION}|${LR_LOADFROMFILE}) i.s' Pop $hBtnNormal ; 加载悬停状态按钮图 System::Call 'user32::LoadImage(i 0, t "${BTN_HOVER}", i ${IMAGE_BITMAP}, i 0, i 0, i ${LR_CREATEDIBSECTION}|${LR_LOADFROMFILE}) i.s' Pop $hBtnHover ; 加载点击状态按钮图 System::Call 'user32::LoadImage(i 0, t "${BTN_PRESSED}", i ${IMAGE_BITMAP}, i 0, i 0, i ${LR_CREATEDIBSECTION}|${LR_LOADFROMFILE}) i.s' Pop $hBtnPressed FunctionEnd
2. 子类化按钮监听鼠标消息
给Next按钮子类化,监听鼠标相关消息实现实时切换图片:
; 定义TrackMouseEvent所需结构和常量 !define sizeof.TRACKMOUSEEVENT 16 !define STRUCT.TRACKMOUSEEVENT "i 0, i 0, i 0, i 0" !define TME_LEAVE 0x00000002 ; 按钮子类化处理函数 Function NextBtnSubclassProc Exch $2 Exch Exch $1 Push $3 Push $4 ; 处理鼠标移动(悬停) StrCmp $1 ${WM_MOUSEMOVE} 0 +5 SendMessage $NextButton ${BM_SETIMAGE} ${IMAGE_BITMAP} $hBtnHover ; 注册鼠标离开消息监听 Push $0 System::Alloc ${sizeof.TRACKMOUSEEVENT} Pop $0 System::Call '*$0(i ${sizeof.TRACKMOUSEEVENT}, i ${TME_LEAVE}, i $NextButton, i 0)' System::Call 'user32::TrackMouseEvent(ptr $0)' System::Free $0 Goto SubclassEnd ; 处理鼠标左键按下 StrCmp $1 ${WM_LBUTTONDOWN} 0 +2 SendMessage $NextButton ${BM_SETIMAGE} ${IMAGE_BITMAP} $hBtnPressed ; 处理鼠标左键松开 StrCmp $1 ${WM_LBUTTONUP} 0 +2 SendMessage $NextButton ${BM_SETIMAGE} ${IMAGE_BITMAP} $hBtnHover ; 处理鼠标离开 StrCmp $1 ${WM_MOUSELEAVE} 0 +2 SendMessage $NextButton ${BM_SETIMAGE} ${IMAGE_BITMAP} $hBtnNormal SubclassEnd: ; 调用原窗口过程 System::Call 'user32::CallWindowProc(ptr $2, ptr $NextButton, i $1, i $3, i $4) i.s' Pop $0 Exch $0 Pop $4 Pop $3 Pop $1 Pop $2 FunctionEnd ; 在首个页面显示时完成按钮子类化 Function Page1Show ; 保存原窗口过程(可选,卸载时可恢复) System::Call 'user32::SetWindowLongPtr(ptr $NextButton, i ${GWL_WNDPROC}, ptr NextBtnSubclassProc) i.s' Pop $R0 FunctionEnd
二、SkinnedButton插件快速实现
你试用的SkinnedButton插件原生支持三帧状态切换,只需用垂直拼接的三帧图片(从上到下:正常、悬停、点击)即可:
; 加载插件(确保插件文件在指定目录) !addplugindir "." Function Page1Show ; 绑定Next按钮到三帧图片 SkinnedButton::SetButton $NextButton "btn_frames.bmp" FunctionEnd
插件会自动监听鼠标事件并切换对应帧,无需手动处理消息。
三、不推荐用leavepage函数
leavepage是页面切换时触发的回调,无法响应实时鼠标动作,用来切换按钮图片会出现延迟或逻辑混乱,完全没必要采用这种方式。
内容的提问来源于stack exchange,提问作者tux Neoh
相关产品推荐
相关产品推荐

