NSIS自定义页面切换时闪烁现象的解决方法咨询
NSIS自定义页面切换时控件闪烁重绘的解决方法
问题描述
我创建了若干NSIS自定义页面,每个页面的自定义函数中执行nsDialogs::Create~nsDialogs::Show操作,每隔几个页面调用LoadBannerImage函数在固定位置加载横幅图片。已尝试lockWindow开关操作,但点击页面的上一页/下一页按钮时,横幅图片及其他控件均会闪烁重绘,该现象在低配虚拟机环境中更为明显,请问如何更自然地解决此问题?
现有代码片段
主脚本页面定义
Page custom DisplayWelcomePage Page custom DisplayInstallationDirPage LeaveInstDirPage !define MUI_PAGE_CUSTOMFUNCTION_SHOW InstallPage !insertmacro MUI_PAGE_INSTFILES Page custom DisplayInstallationFinishPage
WelcomePage.nsi 代码
;WelcomePage.nsi file Function DisplayWelcomePage nsDialogs::Create 1044 Pop $r0 SetCtlColors $r0 0 0xF5F5F5 Push $r0 Call LoadBannerImage nsDialogs::Show FunctionEnd
InstallationDirPage.nsi 代码
; InstallReadyPage.nsi file Function DisplayInstallationDirPage nsDialogs::Create 1044 Pop $r0 SetCtlColors $r0 0 0xF5F5F5 Push $r0 Call LoadBannerImage nsDialogs::Show FunctionEnd
LoadBannerImage 函数
Function LoadBannerImage ${NSD_CreateBitmap} 0u 0u 100u 434u "" Pop $BannerImage SetCtlColors $BannerImage 0 0xF5F5F5 ${NSD_SetBitmap} $BannerImage ${TempBannerFilePath} $8 FunctionEnd
解决方法
1. 复用全局位图控件,避免重复创建
每次切换页面都新建位图控件是闪烁的核心原因之一,改为全局初始化一次控件,切换页面时仅更新内容或控制显隐:
- 定义全局变量存储控件句柄:
Var g_hBannerBitmap
- 在安装初始化阶段创建全局位图控件:
Function .onInit ; 以NSIS主窗口为父控件创建位图 ${NSD_CreateBitmap} 0u 0u 100u 434u "" Pop $g_hBannerBitmap SetCtlColors $g_hBannerBitmap 0 0xF5F5F5 ; 默认隐藏,需要显示的页面再调用显示 ShowWindow $g_hBannerBitmap ${SW_HIDE} FunctionEnd
- 修改
LoadBannerImage函数,仅更新图片并显示:
Function LoadBannerImage ${NSD_SetBitmap} $g_hBannerBitmap ${TempBannerFilePath} $8 ShowWindow $g_hBannerBitmap ${SW_SHOW} FunctionEnd
- 在不需要横幅的页面中隐藏控件:
Function SomePageWithoutBanner nsDialogs::Create 1044 Pop $r0 ; ...其他页面逻辑 ShowWindow $g_hBannerBitmap ${SW_HIDE} nsDialogs::Show FunctionEnd
2. 开启窗口双缓冲
通过Windows API为页面窗口开启双缓冲,减少重绘闪烁:
在每个自定义页面的nsDialogs::Create之后添加以下代码:
; 开启WS_EX_COMPOSITED扩展样式实现双缓冲 GetWindowLong $r0 ${GWL_EXSTYLE} IntOp $r0 $r0 | 0x02000000 ; 直接使用WS_EX_COMPOSITED的数值 SetWindowLong $r0 ${GWL_EXSTYLE} $r0
3. 延迟图片加载时机
将图片加载延迟到窗口初始化完成后执行,避免与页面控件初始化冲突:
Function DisplayWelcomePage nsDialogs::Create 1044 Pop $r0 SetCtlColors $r0 0 0xF5F5F5 ; 监听WM_INITDIALOG消息,窗口初始化完成后再加载图片 nsDialogs::OnNotify $r0 ${WM_INITDIALOG} OnWelcomePageInit Push $r0 nsDialogs::Show FunctionEnd Function OnWelcomePageInit Call LoadBannerImage FunctionEnd
4. 预加载图片到内存
提前将图片加载到内存,避免每次切换页面都从磁盘读取:
Var g_hBannerMemBitmap Function .onInit ; 预加载图片到内存 System::Call 'user32.dll::LoadImage(i0, t "${TempBannerFilePath}", i0, i0, i0, i0x10)' Pop $g_hBannerMemBitmap FunctionEnd ; 修改LoadBannerImage使用内存位图 Function LoadBannerImage SendMessage $g_hBannerBitmap ${STM_SETIMAGE} ${IMAGE_BITMAP} $g_hBannerMemBitmap ShowWindow $g_hBannerBitmap ${SW_SHOW} FunctionEnd
内容的提问来源于stack exchange,提问作者tux Neoh
相关产品推荐
相关产品推荐

