You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 05:48:25