1. 程式人生 > >NSIS進階教程(三)

NSIS進階教程(三)

自定義MessageBox,自定義頁跳轉,自定義CheckBox樣式

前言

上一節中我們處理了Button的自定義以及Button的事件訊息、協議框的建立等等,這節中我們要更加完美的要求我們的提示框也要漂亮,CheckBox也要自定義樣式。有人說MessageBox在NSIS預設情況下是帶邊框的API視窗,是一個比較醜雛形,但是NSIS的nsDialogs外掛也沒有提供一個可以建立彈出窗的命令列呀,CheckBox系統自帶的只能是那個預設的面板,如果想把CheckBox的背景改成藍色,或者把CheckBox的勾改成愛心,把叉改成骷髏頭如何去做呢?這些問題在任何一個面向物件的程式語言中都可以很容易實現,在NSIS這樣侷限的環境中也可以變通實現,接下來我們處理一下這些問題。

本篇主要講講以下幾點:

  • 如何拋棄系統的MessageBox

  • 如何實現自定義頁面的跳轉

  • 如何用自己的貼圖實現CheckBox功能

所用到的外掛【新增】:

  1. FindProcDLL(查詢當前程序外掛)

  2. KillProcDLL (關閉指定程序外掛)

講義

首先貼出一個今天教程的完整的例子【已測試】【附帶圖片】 猛擊這裡

題外話,本節的重點是如何把系統的MessageBox替換掉自定義的視窗,一開始這個命題挺難的,原本因為nsDialogs可以建立一個彈窗,然後給它披上一層皮就可以了,在查了很多資料後,我瞭解到根本不行,nsDialogs外掛不能完成這麼簡單的工作,而是通過另一個外掛nsWindows來完成。另一個自定義CheckBox功能還是有點討巧的,其實在窗體程式設計中,Button跟CheckBox本質上是一樣的東西,CheckBox就是Button披上一層皮加上一些單擊事件改變面板而存在的,於是就有了CheckBox的自定義的可能性。

還是要講一點不足,此處CheckBox不包含旁邊的說明文字,也就是說,當你促發CheckBox旁邊的文字某些事件的時候CheckBox本事不會有任何反應,這樣就不能構成一個CheckBox的整體,不過對於要求不是非常高的人來說,這點完全可以忽略。

如何拋棄系統的MessageBox

通常在使用警告框的時候,我們會呼叫MessageBox的NSIS命令,然而此視窗無比醜陋,簡直是對我們正在做的窗體的褻瀆。於是我們自己建立警告框,此警告框也要跟我們已有的視窗風格一致,包含幾大問題,“無邊框”、“美觀貼圖”、“移動”、“邏輯判斷功能”,做到以上幾點就可以了。上程式碼:

Function onCancel
    IsWindow $WarningForm Create_End
    !define Style ${WS_VISIBLE}|${WS_OVERLAPPEDWINDOW}
    ${NSW_CreateWindowEx} $WarningForm $hwndparent ${ExStyle} ${Style} "" 1018

    ${NSW_SetWindowSize} $WarningForm 349 184
    EnableWindow $hwndparent 0
    System::Call `user32::SetWindowLong(i$WarningForm,i${GWL_STYLE},0x9480084C)i.R0`
    ${NSW_CreateButton} 148 122 88 25 ''
    Pop $R0
    StrCpy $1 $R0
    Call SkinBtn_Quit
    ${NSW_OnClick} $R0 OnClickQuitOK

    ${NSW_CreateButton} 248 122 88 25 ''
    Pop $R0
    StrCpy $1 $R0
    Call SkinBtn_Cancel
    ${NSW_OnClick} $R0 OnClickQuitCancel

    ${NSW_CreateBitmap} 0 0 100% 100% ""
    Pop $BGImage
  ${NSW_SetImage} $BGImage $PLUGINSDIR\quit.bmp $ImageHandle
    GetFunctionAddress $0 onWarningGUICallback
    WndProc::onCallback $BGImage $0 ;處理無邊框窗體移動
  ${NSW_CenterWindow} $WarningForm $hwndparent
    ${NSW_Show}
    Create_End:
  ShowWindow $WarningForm ${SW_SHOW}
FunctionEnd

這個onCancel方法是在我們在主窗體上點選“取消”或者“關閉”的時候促發的方法,這時會彈出一個命令窗口出來。

建立跟設定樣式:WS_VISIBLE 是顯示的意思,不加會隱藏掉,WS_OVERLAPPEDWINDOW 是建立一個層疊窗體的屬性也需要加上。NSW_CreateWindowEx 是建立窗體的主命令。

建立完窗體後,用NSW_SetWindowSize 更改一下窗體的大小。

EnableWindow $hwndparent 0這段程式碼一定要加上,這是建立一個警告框模式窗體的必要條件,就是讓主窗體不能操作。

接下來就是消除邊框,用nsWindows命令建立按鈕的一套,跟nsDialogs的建立是一致的,包括無邊框移動的一套,在第一節中已經講過,這裡就不囉嗦了。

最後把這個窗體展示出來就可以了。把這個onCancel這個方法賦給“取消”按鈕的單擊事件,這樣一個無邊框模式窗體警告框就好了。

"自定義彈出框"

當我們點選“退出”的時候,就要關掉當前程式,所以要新增一個關閉的方法:

Function onClickClose
    FindProcDLL::FindProc "test.exe"
    Sleep 500
    Pop $R0
    ${If} $R0 != 0
    KillProcDLL::KillProc "test.exe"
    ${EndIf}
FunctionEnd

通過FindProcDLL外掛的FindProc方法找到安裝程序,並且通過KillProcDLL外掛的KillProc殺之。

當我們點選“取消”的時候,這時候需要關閉當前警告框,並且讓主窗體能夠處於Active狀態

Function OnClickQuitCancel
  ${NSW_DestroyWindow} $WarningForm
  EnableWindow $hwndparent 1
  BringToFront
FunctionEnd

NSW_DestroyWindow命令銷燬掉警告框,使主窗體能活動,並且Bring到前端。

如何實現自定義頁面的跳轉

一開始我們就定義了兩個自定義頁面:

Page custom WelcomePage
Page custom InstallationPage

WelcomePage跳轉到InstallationPage,這個就是下一步按鈕的事件。

建立一個RelGotoPage方法:

Function RelGotoPage
  IntCmp $R9 0 0 Move Move
    StrCmp $R9 "X" 0 Move
      StrCpy $R9 "120"
  Move:
  SendMessage $HWNDPARENT "0x408" "$R9" ""
FunctionEnd

If a number > 0: Goes foward that number of pages. Code of that page will be executed, not returning to this point. If it is bigger than the number of pages that are after that page, it simulates a “Cancel” click.

If a number < 0: Goes back that number of pages. Code of that page will be executed, not returning to this point. If it is bigger than the number of pages that are before that page, it simulates a “Cancel” click.

If X: Simulates a “Cancel” click. Code will go to callback functions, not returning to this point.

If 0: Continues on the same page. Code will still be running after the call.

下一步的單擊事件中加入以下程式碼,跳轉就好了,而且以後的調轉RelGotoPage都適用

Function onClickNext
  StrCpy $R9 1
  Call RelGotoPage
  Abort
FunctionEnd

如何用自己的貼圖實現CheckBox功能

CheckBox也有系統自帶的那種健全的,但是效果沒有Button貼面板後好,所以棄用之,在第二個頁面中建立幾個Button跟標籤:

${NSD_CreateButton} 26 150 15 15 ""
    Pop $Ck_ShortCut
    StrCpy $1 $Ck_ShortCut
    Call SkinBtn_Checked
    GetFunctionAddress $3 OnClick_CheckShortCut
    SkinBtn::onClick $1 $3
    StrCpy $Bool_ShortCut 1
    ${NSD_CreateLabel} 45 151 100 15 "新增桌面快捷方式"
    Pop $Lbl_ShortCut
    SetCtlColors $Lbl_ShortCut ""  transparent ;背景設成透明

建立CheckBox的時候要考慮周全,首先要定義該CheckBox的變數,該CheckBox的面板,記錄該CheckBox狀態的變數$Bool_ShortCut,該CheckBox旁邊的提示文字變數$Lbl_ShortCut

"自定義Checkbox"

"自定義Checkbox"

Button的貼圖跟變換方式在第二節中已經介紹,這裡就不囉嗦。

這裡的OnClick_CheckShortCut方法不僅僅是一個變換的實現,也通過$Bool_ShortCut記錄了當前CheckBox的狀態

Function OnClick_CheckShortCut
  ${IF} $Bool_ShortCut == 1
        IntOp $Bool_ShortCut $Bool_ShortCut - 1
        StrCpy $1 $Ck_ShortCut
        Call SkinBtn_UnChecked
    ${ELSE}
        IntOp $Bool_ShortCut $Bool_ShortCut + 1
        StrCpy $1 $Ck_ShortCut
        Call SkinBtn_Checked
    ${EndIf}
FunctionEnd

最後我們在完成安裝的時候,可以通過$Bool_ShortCut該變數來了解使用者的選擇

"整體圖"

結束語

其實不難,邏輯清晰,知道自己朝哪個方向去尋找答案,一切就會雲開霧散。希望大家能學到一些。

***************************************************************************

有任何疑問請留言。

That’s all

下回繼續探討