如何启用/禁用控件
使用标准 NSIS EnableWindow 命令。
NSDialogs 允许您弹出通过 ${NSD_Create*} 创建的控件的 hwnd (句柄)。EnableWindow 将 hwnd 作为其参数之一。通过它,您可以轻松启用/禁用控件。
!include "nsDialogs.nsh"
!include "winmessages.nsh"
!include "logiclib.nsh"
OutFile "test.exe"Page Custom prevar dialog
var hwnd
var buttonFunction prensDialogs::Create 1018Pop $dialog${NSD_CreateCheckbox} 0 0 50% 6% "Enable button below"Pop $hwnd${NSD_OnClick} $hwnd EnDisableButton${NSD_CreateButton} 25% 25% 50% 50% "Hello World"Pop $buttonEnableWindow $button 0 # start out disablednsDialogs::Show
FunctionEndFunction EnDisableButtonPop $hwnd${NSD_GetState} $hwnd $0${If} $0 == 1EnableWindow $button 1${Else}EnableWindow $button 0${EndIf}
FunctionEndSection ""
SectionEnd
如何显示/隐藏控件
使用标准 NSIS ShowWindow 命令。
NSDialogs 允许您弹出通过 ${NSD_Create*} 创建的控件的 hwnd (句柄)。ShowWindow将 hwnd 作为其参数之一。通过它,您可以轻松显示/隐藏控件。
!include "nsDialogs.nsh"
!include "winmessages.nsh"
!include "logiclib.nsh"
OutFile "test.exe"Page Custom prevar dialog
var hwnd
var buttonFunction prensDialogs::Create 1018Pop $dialog${NSD_CreateCheckbox} 0 0 50% 6% "Show button below"Pop $hwnd${NSD_OnClick} $hwnd EnDisableButton${NSD_CreateButton} 25% 25% 50% 50% "Hello World"Pop $buttonShowWindow $button ${SW_HIDE} # start out hiddennsDialogs::Show
FunctionEndFunction EnDisableButtonPop $hwnd${NSD_GetState} $hwnd $0${If} $0 == 1ShowWindow $button ${SW_SHOW}${Else}ShowWindow $button ${SW_HIDE}${EndIf}
FunctionEndSection ""
SectionEnd
如何创建一个文本居中的标签
文本居中 - 无论控件的大小如何,文本始终居中显示,这通常对于展示目的非常有用。使标签的文本居中对齐很简单,使用 ${NSD_AddStyle} 命令添加 ${SS_CENTER} 样式即可。
!include "nsDialogs.nsh"OutFile "$%temp%\temp.exe"var dialog
var hwnd
var nullPage custom TestFunction TestnsDialogs::Create 1018Pop $dialog${NSD_CreateLabel} 0 0 100% 20% "This line will be centered.$\nAnd so will this line."Pop $hwnd${NSD_AddStyle} $hwnd ${SS_CENTER}nsDialogs::Show
FunctionEndSection
SectionEnd
如何创建多行编辑(文本)控件
虽然多行是控件的一个样式,但对于编辑(文本)控件来说,它是少数几种样式之一,无法在控件创建后设置,因此无法使用 ${NSD_AddStyle}。
相反,您需要手动创建控件:
!include "nsDialogs.nsh"
!include "winmessages.nsh"
!include "logiclib.nsh"
OutFile "test.exe"Page Custom prevar dialog
var hwndFunction prensDialogs::Create 1018Pop $dialog${NSD_CreateText} 0 0 100% 40% "This is NOT a$\r$\nmulti-line$\r$\nedit control"Pop $hwndnsDialogs::CreateControl EDIT \"${__NSD_Text_STYLE}|${WS_VSCROLL}|${ES_MULTILINE}|${ES_WANTRETURN}" \"${__NSD_Text_EXSTYLE}" \0 50% 100% 40% \"This IS a$\r$\nmulti-line$\r$\nedit control"Pop $hwndnsDialogs::Show
FunctionEndSection ""
SectionEnd
或者,更简洁的方法是使用 NsDialogs_CreateTextMultiline 头文件:
!include "nsDialogs.nsh"
!include "nsDialogs_createTextMultiline.nsh"
!include "winmessages.nsh"
!include "logiclib.nsh"
OutFile "test.exe"Page Custom prevar dialog
var hwndFunction prensDialogs::Create 1018Pop $dialog${NSD_CreateText} 0 0 100% 40% "This is NOT a$\r$\nmulti-line$\r$\nedit control"Pop $hwnd${NSD_CreateTextMultiline} 0 50% 100% 40% "This IS a$\r$\nmulti-line$\r$\nedit control"Pop $hwndnsDialogs::Show
FunctionEndSection ""
SectionEnd
如何创建文本密码控件
请参阅 nsDialogs 文档 - 密码控件是默认支持的控件之一;${NSD_CreatePassword}
如何设置文本密码控件使用的字符
默认情况下,文本密码控件将使用星号(****)作为密码字符来掩盖文本(当'XPStyle off'时),或者使用圆点(••••)(当'XPStyle on'时)。您可以使用带有 EM_SETPASSWORDCHAR 标志的 SendMessage 来更改此字符。
密码字符由其 ASCII 或 UNICODE 码索引标识;请注意,您在安装程序中使用的字体可能不支持您希望使用的字符。
注意:如果将密码字符设置为 0(零),文本将不会被掩盖!您可以利用这一点在文本密码控件中切换文本的可见和掩盖状态。另请参阅如何在文本密码控制中隐藏/显示密码的条目。
!include "nsDialogs.nsh"
!include "winmessages.nsh"
!include "logiclib.nsh"
OutFile "test.exe"Page Custom prevar dialog
var hwndFunction prensDialogs::Create 1018Pop $dialog${NSD_CreatePassword} 0 0 50% 8% "This is a password field"Pop $hwndSendMessage $hwnd ${EM_SETPASSWORDCHAR} 149 0 # 在 ASCII 或 Unicode 编码中,149 指的是中等大小的圆点nsDialogs::Show
FunctionEndSection ""
SectionEnd
如何在文本密码控件中隐藏/显示密码
通过使用带有 EM_SETPASSWORDCHAR 标志的 SendMessage 设置,通过将字符指定为 0(零),您可以让密码可见,而通过指定非零字符使密码再次不可见。
注意:更改掩码字符后,必须强制重绘密码控件。通常是通过隐藏然后使用 ShowWindow 显示控件来完成。
!include "nsDialogs.nsh"
!include "winmessages.nsh"
!include "logiclib.nsh"
OutFile "test.exe"Page Custom prevar dialog
var hwnd
var passwordControlFunction prensDialogs::Create 1018Pop $dialog${NSD_CreateCheckbox} 0 0 25% 8% "Show password"Pop $hwnd${NSD_OnClick} $hwnd ShowPassword${NSD_CreatePassword} 0 10% 50% 8% "This is a password field"Pop $passwordControlnsDialogs::Show
FunctionEndFunction ShowPasswordPop $hwnd${NSD_GetState} $hwnd $0ShowWindow $passwordControl ${SW_HIDE}${If} $0 == 1SendMessage $passwordControl ${EM_SETPASSWORDCHAR} 0 0${Else}SendMessage $passwordControl ${EM_SETPASSWORDCHAR} 42 0${EndIf}ShowWindow $passwordControl ${SW_SHOW}
FunctionEndSection ""
SectionEnd
注意:在启用 'XPStyle on' 的情况下,如果要重置ANSI构建中看到的“粗点”字符,不能使用标准的SendMessage(底层使用 SendMessageA),因为它是一个 Unicode 字符。可以使用 System 插件调用 SendMessageW 函数:
/* 9679是粗点字符 */
System::Call "user32::SendMessageW(i $hwnd, i ${EM_SETPASSWORDCHAR}, i 9679, i 0)"
如何创建仅数字的文本控件
请参阅 nsDialogs 文档 - 仅限数字的控件是默认支持的控件之一;${NSD_CreateNumber}
如何创建只读文本控件
文本控件的只读状态可以使用带有 EM_SETREADONLY 标志的 SendMessage 来设置。
请注意,只读的编辑(文本)控件与禁用的文本控件不同。禁用的文本控件将其文本显示为灰色,而只读的文本控件则保持黑色,并显示在浅灰色背景上。此外,禁用的多行文本控件无法滚动。而只读的多行文本控件则可以滚动。
!include "nsDialogs.nsh"
!include "winmessages.nsh"
!include "logiclib.nsh"
OutFile "test.exe"Page Custom prevar dialog
var hwnd
var textControlFunction prensDialogs::Create 1018Pop $dialog${NSD_CreateCheckBox} 0 0 50% 6% "Set text field below read-only"Pop $hwnd${NSD_OnClick} $hwnd SetReadonly${NSD_CreateText} 0 12% 100% 8% "Hello World"Pop $textControlnsDialogs::Show
FunctionEndFunction SetReadonlyPop $hwnd${NSD_GetState} $hwnd $0SendMessage $textControl ${EM_SETREADONLY} $0 0
FunctionEndSection ""
SectionEnd
单选按钮 (Radio buttons)
单选按钮基本用法
!include nsDialogs.nsh
Page Custom MyPageCreate MyPageLeaveVar StationChoiceFunction MyPageCreate
nsDialogs::Create 1018
Pop $0
${NSD_CreateFirstRadioButton} 0 0 40% 6% "NPR"
Pop $1
SendMessage $1 ${BM_CLICK} "" "" ; Must select a default
${NSD_CreateAdditionalRadioButton} 0 12% 40% 6% "BBC"
Pop $2
${IfThen} $StationChoice == "BBC" ${|} SendMessage $2 ${BM_CLICK} "" "" ${|}
nsDialogs::Show
FunctionEndFunction MyPageLeave
${NSD_GetChecked} $1 $3
${If} $3 <> ${BST_UNCHECKED}StrCpy $StationChoice "NPR"
${Else}StrCpy $StationChoice "BBC"
${EndIf}
FunctionEndSection
DetailPrint "Turning the dial to $StationChoice"
SectionEnd
根据单选按钮的变化更新页面
!include nsDialogs.nsh
Page Custom MyPageCreateFunction MyPageCreate
nsDialogs::Create 1018
Pop $0; 组1
${NSD_CreateFirstRadioButton} 0 0 50% 12u "NPR"
Pop $1
${NSD_OnClick} $1 onStationChanged
${NSD_CreateAdditionalRadioButton} 0 14u 50% 12u "BBC"
Pop $2
${NSD_OnClick} $2 onStationChanged
${NSD_CreateLabel} 0 30u 80% 12u ""
Pop $3
SendMessage $1 ${BM_CLICK} "" "" ; 必须选择一个默认选项; 组2
${NSD_CreateFirstRadioButton} 0 50u 50% 12u "FM"
Pop $0 ; 仅用于演示,稍后不需要句柄
${NSD_CreateAdditionalRadioButton} 0 64u 50% 12u "AM"
Pop $0 ; 仅用于演示,稍后不需要句柄
SendMessage $0 ${BM_CLICK} "" "" ; 必须选择一个默认选项nsDialogs::Show
FunctionEndFunction onStationChanged
Pop $0
${NSD_GetChecked} $1 $0
${If} $0 <> ${BST_UNCHECKED}${NSD_SetText} $3 "America, f*(# yeah!" ;
${Else}${NSD_SetText} $3 "保持冷静,继续前行" ; Keep Calm and Carry On
${EndIf}
FunctionEnd
如何创建两组 RadioButton
使用 ${NSD_AddStyle} 向每组的第一个单选按钮添加 WS_GROUP 样式。在 Windows 的 UI 处理中,如果没有定义组启动器,所有单选按钮都被视为同一组的一部分。
因此,要创建两个各有两个单选按钮的组,必须为每组指定一个组启动器,否则第三和第四个单选按钮将被视为第一组的一部分。
使用 ${NSD_AddStyle} 设置组启动器很简单,使用以下代码:
${NSD_AddStyle} $hwnd ${WS_GROUP} # WS_GROUP 定义在 winmessages.nsh 中
示例:
!include "nsDialogs.nsh"
!include "winmessages.nsh"
!include "logiclib.nsh"
OutFile "test.exe"Page Custom prevar dialog
var hwndFunction prensDialogs::Create 1018Pop $dialog${NSD_CreateRadioButton} 0 0 40% 6% "组 1,单选按钮 1"Pop $hwnd${NSD_AddStyle} $hwnd ${WS_GROUP}${NSD_CreateRadioButton} 0 12% 40% 6% "组 1,单选按钮 2"Pop $hwnd${NSD_CreateRadioButton} 50% 0 40% 6% "组 2,单选按钮 1"Pop $hwnd${NSD_AddStyle} $hwnd ${WS_GROUP}${NSD_CreateRadioButton} 50% 12% 40% 6% "组 2,单选按钮 2"Pop $hwndnsDialogs::Show
FunctionEndSection ""
SectionEnd
如何轻松处理单选按钮的选择
通常,你不希望为每个单选按钮指定单独的 OnClick 函数...
!include "nsDialogs.nsh"
!include "winmessages.nsh"
!include "logiclib.nsh"
OutFile "test.exe"Page Custom prevar dialog
var hwndFunction prensDialogs::Create 1018Pop $dialog${NSD_CreateRadioButton} 0 0 40% 6% "Group 1, Radio 1"Pop $hwnd${NSD_AddStyle} $hwnd ${WS_GROUP}${NSD_OnClick} $hwnd Group1Radio1Click${NSD_CreateRadioButton} 0 12% 40% 6% "Group 1, Radio 2"Pop $hwnd${NSD_OnClick} $hwnd Group1Radio2ClicknsDialogs::Show
FunctionEndFunction Group1Radio1ClickPop $hwndMessageBox MB_OK "onClick:Group1Radio1"
FunctionEnd
Function Group1Radio2ClickPop $hwndMessageBox MB_OK "onClick:Group1Radio2"
FunctionEndSection ""
SectionEnd
但是唯一明显的替代方法似乎是将每个单选按钮放在不同的变量中,并在回调函数调用时将堆栈上的 hwnd 与该变量进行比较。
!include "nsDialogs.nsh"
!include "winmessages.nsh"
!include "logiclib.nsh"
OutFile "test.exe"Page Custom prevar dialog
var hwndvar Group1Radio1
var Group1Radio2Function prensDialogs::Create 1018Pop $dialog${NSD_CreateRadioButton} 0 0 40% 6% "组 1, 单选 1"Pop $Group1Radio1${NSD_AddStyle} $Group1Radio1 ${WS_GROUP}${NSD_OnClick} $Group1Radio1 RadioClick${NSD_CreateRadioButton} 0 12% 40% 6% "组 1, 单选 2"Pop $Group1Radio2${NSD_OnClick} $Group1Radio2 RadioClicknsDialogs::Show
FunctionEndFunction RadioClickPop $hwnd${If} $hwnd == $Group1Radio1MessageBox MB_OK "点击:组 1 单选 1"${ElseIf} $hwnd == $Group1Radio2MessageBox MB_OK "点击:组 1 单选 2"${EndIf}
FunctionEndSection ""
SectionEnd
然而,你可以通过使用 nsDialogs 的 getUserData 和 setUserData 命令来消除这种情况。使用这些 *UserData 命令,你可以将数据存储在控件中,并在以后轻松检索这些数据。
为了简化这些命令的使用,我们将使用 NsDialogs UserData 的头文件。
!include "nsDialogs.nsh"
!include "winmessages.nsh"
!include "logiclib.nsh"
OutFile "test.exe"Page Custom prevar dialog
var hwndFunction prensDialogs::Create 1018Pop $dialog${NSD_CreateRadioButton} 0 0 40% 6% "组 1, 单选 1"Pop $hwnd${NSD_AddStyle} $hwnd ${WS_GROUP}${NSD_SetUserData} $hwnd "Group1Radio1"${NSD_OnClick} $hwnd RadioClick${NSD_CreateRadioButton} 0 12% 40% 6% "组 1, 单选 2"Pop $hwnd${NSD_SetUserData} $hwnd "Group1Radio2"${NSD_OnClick} $hwnd RadioClicknsDialogs::Show
FunctionEndFunction RadioClickPop $hwnd${NSD_GetUserData} $hwnd $0${If} $0 == "Group1Radio1"MessageBox MB_OK "点击:组 1 单选 1"${ElseIf} $0 == "Group1Radio2"MessageBox MB_OK "点击:组 1 单选 2"${EndIf}
FunctionEndSection ""
SectionEnd
使用这种方法,你可以轻松地将变量设置为存储在单选按钮控件上的内部字符串,而不需要在 OnClick 事件函数中使用任何 If-ElseIf-EndIf 或 Case 选择。
!include "nsDialogs.nsh"
!include "winmessages.nsh"
!include "logiclib.nsh"
OutFile "test.exe"Page Custom pre postvar dialog
var hwnd
var minorFunction prensDialogs::Create 1018Pop $dialog${NSD_CreateRadioButton} 0 0 40% 6% "我已年满 14 岁"Pop $hwnd${NSD_AddStyle} $hwnd ${WS_GROUP}${NSD_SetUserData} $hwnd "false"${NSD_OnClick} $hwnd RadioClick${NSD_CreateRadioButton} 0 12% 40% 6% "我未满 14 岁"Pop $hwnd${NSD_SetUserData} $hwnd "true"${NSD_OnClick} $hwnd RadioClicknsDialogs::Show
FunctionEndFunction RadioClickPop $hwnd${NSD_GetUserData} $hwnd $minor
FunctionEndFunction post${If} $minor == ""MessageBox MB_OK "请选择你的年龄组"Abort${ElseIf} $minor == trueMessageBox MB_OK "安装将继续进行,内容适合你的年龄"${Else}MessageBox MB_OK "安装将正常进行"${EndIf}
FunctionEndSection ""
SectionEnd
进度条
如何控制进度条控件(使用绝对值) 您可以使用 sendMessage 和进度条控件的消息来控制进度条。这些消息几乎都在 NSIS 附带的 WinMessages.nsh 头文件中定义,因此请务必包含此头文件。
至少有一个例外,它非常有用,因为它可以减少代码量并使您的源代码更容易阅读,那就是 PBM_SETRANGE32。PBM_SETRANGE32 允许您只用两个数字设置起始和结束范围,而不必像 PBM_SETRANGE 那样使用 WinDef.nsh 中的 ${MakeLong}。
为了更新进度条的值,您需要使用 nsDialogs 计时器来调用处理实际处理的函数。此计时器仅调用一次。
下面是一个简单的示例,该示例创建了一个范围从 0(零)到 100 的进度条,用于典型的百分比增加,并将进度设置为 25%、50%、75% 和 100%,使用 Sleep 命令来模拟处理发生的情况——通常这可能是其他 NSIS 调用或在主安装之前调用外部应用程序/安装程序等。
!include "WinMessages.nsh"
!include "MUI2.nsh"
!include "nsDialogs.nsh"OutFile "test.exe"Section
SectionEndVar dialog
Var hwnd
Var nullPage Custom page.custom
Function page.customnsDialogs::Create 1018Pop $dialog${NSD_CreateProgressBar} 0 0 100% 10% "Test"Pop $hwnd${NSD_CreateTimer} NSD_Timer.Callback 10nsDialogs::Show
FunctionEndFunction NSD_Timer.Callback${NSD_KillTimer} NSD_Timer.CallbackSendMessage $hwnd ${PBM_SETRANGE32} 0 100SendMessage $hwnd ${PBM_SETPOS} 25 0Sleep 2000SendMessage $hwnd ${PBM_SETPOS} 50 0Sleep 2000SendMessage $hwnd ${PBM_SETPOS} 75 0Sleep 2000SendMessage $hwnd ${PBM_SETPOS} 100 0
FunctionEnd!insertmacro MUI_LANGUAGE "English"
如何控制进度条控件(使用步进值)
上一个示例的一个缺点是,您必须始终跟踪百分比,而这些百分比可能并不重要,只要用户知道有进度即可。一个例子是,在复制/粘贴代码块时,跟踪百分比可能会变得棘手。您可能会突然发现自己的进度条从 0% 到 50%,然后回到 25%,再上升到 75%。
解决这个问题的一个相当简单的方法是使用步进进度条。这种方法允许您定义一个步进增量值,并简单地调用步进函数来逐步增加进度条的值。以下是使用这种方法的示例,其功能与前面的示例相同。请注意,我们将范围设置为函数中预期的步数。
!include "WinMessages.nsh"
!include "MUI2.nsh"
!include "nsDialogs.nsh"OutFile "test.exe"Section
SectionEndVar dialog
Var hwnd
Var nullPage Custom page.custom
Function page.customnsDialogs::Create 1018Pop $dialog${NSD_CreateProgressBar} 0 0 100% 10% "测试"Pop $hwnd${NSD_CreateTimer} NSD_Timer.Callback 10nsDialogs::Show
FunctionEndFunction NSD_Timer.Callback${NSD_KillTimer} NSD_Timer.CallbackSendMessage $hwnd ${PBM_SETRANGE32} 0 4SendMessage $hwnd ${PBM_SETSTEP} 1 0SendMessage $hwnd ${PBM_STEPIT} 0 0Sleep 2000SendMessage $hwnd ${PBM_STEPIT} 0 0Sleep 2000SendMessage $hwnd ${PBM_STEPIT} 0 0Sleep 2000SendMessage $hwnd ${PBM_STEPIT} 0 0SendMessage $hwnd ${PBM_SETPOS} 4 0
FunctionEnd!insertmacro MUI_LANGUAGE "English"
请注意,在最后,我们仍然将进度设置为 100%。这是因为您的函数中可能有一些条件步骤。如果您忘记步进进度条,那么进度值将不会达到 100%。这是一个经常报告的用户界面问题,用户抱怨即使过程完成了,进度条仍然停留在少于 100% 的位置。
但是,请注意不要使用比在 PBM_SETRANGE32 调用中指定的步数更多的步骤,因为之后的任何步骤都会显示为 100%,而没有任何明显的进展。
如何创建一个跑马灯(无限循环)进度条控件
有时您可能不知道进度 - 例如,您正在执行一个可能需要一些时间的任务,但无法确定任务进行到哪一步。在这种情况下,您可能希望使用一个所谓的跑马灯进度条,它只是从左到右无限循环。
有一个需要注意的事项:除非您使用带有 XP 样式的界面(另见 XPStyle),否则您不能使用跑马灯进度条。
除此之外,通过使用 ${NSD_AddStyle} 向进度条添加 PBS_MARQUEE 样式。
以下是一个这样的示例:
!include "WinMessages.nsh"
!include "MUI2.nsh"
!include "nsDialogs.nsh"OutFile "test.exe"Section
SectionEndVar dialog
Var hwnd
Var null!define PBS_MARQUEE 0x08Page Custom page.custom
Function page.customnsDialogs::Create 1018Pop $dialog${NSD_CreateProgressBar} 0 0 100% 10% "测试"Pop $hwnd${NSD_AddStyle} $hwnd ${PBS_MARQUEE}${NSD_CreateTimer} NSD_Timer.Callback 10nsDialogs::Show
FunctionEndFunction NSD_Timer.Callback${NSD_KillTimer} NSD_Timer.Callback ; 关闭定时器SendMessage $hwnd ${PBM_SETMARQUEE} 1 50 ; start=1|stop=0 间隔(ms)=+N_again:MessageBox MB_YESNO "停止跑马灯?" IDNO _againSendMessage $hwnd ${PBM_SETMARQUEE} 0 0FunctionEnd!insertmacro MUI_LANGUAGE "English"
请注意,跑马灯进度条总是从左到右运行 - 您不能将其设置为其他任何位置。
如何让控件接收快捷键(alt+字母)组合
只有带标签的控件可以分配快捷键,只需在其标题中包含一个 & 符号。例如:
${NSD_CreateCheckbox} 3% 3% 20% 8% "The hot&key here is alt+k"
但是,当在 NSIS 中首次导航到页面时,NSIS 对话框是获得焦点的,而不是内部的 nsDialogs 对话框。因此,在告诉 nsDialogs 显示之前,请先将焦点设置到 nsDialogs 对话框:
nsDialogs::Create 1018
Pop $dialog ; 假设您有一个 'dialog' 变量!
; 后续代码在这里
SendMessage $dialog ${WM_SETFOCUS} $HWNDPARENT 0
nsDialogs::Show
NSIS 对话框仍然会处理例如 alt+N 用于下一步按钮,因为如果当前焦点的窗口没有对快捷键事件作出反应,这些事件会简单地“冒泡”到父窗口。(提示:这意味着您不应该为 B(ack) 或 N(ext) 字母设置任何快捷键!)
使用这些方法,您可以轻松创建一个可以完全通过键盘操作的安装程序。