首先定義個界面庫的對象:app
ctWin32Dialog::ctDialog ctd;函數
開始時調用start() , 設置最初的幾個參數(大小/標題/圖標) , 而後調用初始頁面1的佈局, 並開始消息循環(ctd.showMainDialog())工具
void start() { ctd.createMainDialog( 510, 370 ); ctd.setTitle( GETSETUPSTRING( 1 ) ); //調用頁面1的佈局顯示 page1( ctd.hMainDlg, 0 ); //這裏直接使用了固定的資源文件做爲圖標 HICON hIcon = LoadIconA( ctd.appInstance, MAKEINTRESOURCEA( IDI_ICON1 ) ); SendMessageA( ctd.hMainDlg, WM_SETICON, TRUE, (LPARAM)hIcon ); //UI線程這裏阻塞 ctd.showMainDialog(); }
佈局1的代碼:佈局
int CALLBACK page1( HWND hDlg, DWORD windowId ) { //先清空全部以前的控件 ctd.clearDlg(); //劃線/顯示bmp/前景色填充 ctd.drawLine( 0, 290, 510, 290, (COLORREF)0xA0A0A0 ); ctd.drawBmp( TMP_WizardImage, 0, 0, 160, 290 ); ctd.setForecolor( RGB( 255, 255, 255 ), {0,0,ctd.hMainDlgRect.right,290} ); //建立對應文字, 這裏的宏是去讀取字符串來顯示 ctd.createText( GETSETUPSTRING( 8 ), 180, 20, 300, 40, 16 ); ctd.createText( GETSETUPSTRING( 9 ), 180, 65, 300, 25 ); ctd.createText( GETSETUPSTRING( 10 ), 180, 90, 300, 25 ); ctd.createText( GETSETUPSTRING( 11 ), 180, 115, 300, 25 ); //建立按鈕, 對應點擊後顯示page2 ctd.createbutton( GETSETUPSTRING( 3 ), 300, 300, PARTCALLBACK( page2 ) ); //建立按鈕, 對應點擊後顯示cancel ctd.createbutton( GETSETUPSTRING( 4 ), 400, 300, PARTCALLBACK( cancel ) ); return 0; }
GETSETUPSTRING 宏 : 去解壓的臨時文件中獲取''指定行''的字符串.ui
PARTCALLBACK : this
#define PARTCALLBACK (proc) [=](HWND hDlg,DWORD windowId)-> int{return proc(hDlg,windowId);}spa
這個宏直接生成函數: 這個函數傳入一個可調用2個參數的函數,並調用.net
在ctd.showMainDialog();以後就能夠正確的顯示出這個頁面:線程
點擊下一步以後到達page2:code
int CALLBACK page2( HWND hDlg, DWORD windowId ) { ctd.clearDlg(); ctd.setForecolor( RGB( 255, 255, 255 ), {0,0,ctd.hMainDlgRect.right,60} ); ctd.drawLine( 0, 60, 510, 60, (COLORREF)0xA0A0A0 ); ctd.drawLine( 0, 290, 510, 290, (COLORREF)0xA0A0A0 ); ctd.drawBmp( TMP_WizardSmallImage, 435, 0, 55, 55 ); ctd.createText( GETSETUPSTRING( 12 ), 20, 15, 200, 15, 12 ); ctd.createText( GETSETUPSTRING( 13 ), 40, 35, 300, 15 ); ctd.drawBmp( TMP_folders, 40, 75, 36, 36 ); ctd.createText( GETSETUPSTRING( 14 ), 90, 85, 350, 15 ); ctd.createText( GETSETUPSTRING( 15 ), 40, 120, 400, 15 ); //這個edit顯示的默認文本爲當前的安裝路徑 //setuppath默認爲系統program路徑 ctd.createEdit( 40, 145, 300, 20, "path", setuppath.c_str() ); //瀏覽 ctd.createbutton( GETSETUPSTRING( 16 ), 350, 144, PARTCALLBACK( choosefile ) ); //上一步 直接回到page1 ctd.createbutton( GETSETUPSTRING( 2 ), 200, 300, PARTCALLBACK( page1 ) ); //下一步 直接跳到page3 ctd.createbutton( GETSETUPSTRING( 3 ), 300, 300, PARTCALLBACK( page3 ) ); ctd.createbutton( GETSETUPSTRING( 4 ), 400, 300, PARTCALLBACK( cancel ) ); return 0; }
繼續下一步,來到page3:
int CALLBACK page3( HWND hDlg, DWORD windowId ) { setuppath = ctd.getEditText( "path" ); //先讀取以前page2中的path ctd.clearDlg(); //而後清空面板 char tmp[200]; wsprintfA( tmp, "%s\r\n\t%s", GETSETUPSTRING( 30 ), setuppath.c_str() ); ctd.setForecolor( RGB( 255, 255, 255 ), {0,0,ctd.hMainDlgRect.right,60} ); ctd.drawLine( 0, 60, 510, 60, (COLORREF)0xA0A0A0 ); ctd.drawLine( 0, 290, 510, 290, (COLORREF)0xA0A0A0 ); ctd.drawBmp( TMP_WizardSmallImage, 435, 0, 55, 55 ); ctd.createText( GETSETUPSTRING( 17 ), 20, 15, 200, 15, 12 ); ctd.createText( GETSETUPSTRING( 18 ), 40, 35, 200, 15 ); ctd.createText( GETSETUPSTRING( 19 ), 40, 75, 400, 15 ); ctd.createEdit( 40, 100, 400, 170, "lastshow" ); PostMessageW( ctd.getWnd( "lastshow" ), EM_SETREADONLY, 1, 0 ); //設置爲只讀 ctd.setText( "lastshow", tmp ); ctd.createbutton( GETSETUPSTRING( 2 ), 200, 300, PARTCALLBACK( page2 ) ); ctd.createbutton( GETSETUPSTRING( 6 ), 300, 300, PARTCALLBACK( page4 ) ); ctd.createbutton( GETSETUPSTRING( 4 ), 400, 300, PARTCALLBACK( cancel ) ); return 0; }
點擊安裝,來看看page4的安裝頁面:
int CALLBACK page4( HWND hDlg, DWORD windowId ) { ctd.clearDlg(); ctd.setForecolor( RGB( 255, 255, 255 ), {0,0,ctd.hMainDlgRect.right,60} ); ctd.drawLine( 0, 60, 510, 60, (COLORREF)0xA0A0A0 ); ctd.drawLine( 0, 290, 510, 290, (COLORREF)0xA0A0A0 ); ctd.drawBmp( TMP_WizardSmallImage, 435, 0, 55, 55 ); ctd.createText( GETSETUPSTRING( 20 ), 20, 15, 200, 15, 12 ); ctd.createText( GETSETUPSTRING( 21 ), 40, 35, 300, 15 ); ctd.createText( GETSETUPSTRING( 22 ), 40, 75, 400, 15 ); ctd.createbutton( GETSETUPSTRING( 4 ), 400, 300, PARTCALLBACK( cancel ) ); //建立一個text 以供顯示安裝的文件名信息 ctd.createText( "", 40, 95, 450, 15, 0, "showpath" ); //建立一個隱藏按鈕,能夠經過他到page5 ctd.createbutton( GETSETUPSTRING( 5 ), 300, 300, PARTCALLBACK( page5 ), 85, 22, "overbutton" ); ShowWindow( ctd.getWnd( "overbutton" ), 0 ); //這裏能夠設置進度爲文件數量,每次釋放一個文件 +1進度 ctd.createProgress( 40, 120, "extract", filescount ); // //功能線程: 建立一個線程去解壓文件 std::thread t1( &ctWizard::installing, this ); t1.detach(); return 0; }
這個仍是比較複雜的,由於要顯示安裝時的信息,因此放置一個空的text和一個空的progress組件到面板中
最後開啓解壓線程, 線程解壓的同時也要反饋這些信息到UI上:
線程代碼:
void installing() { CreateDirectoryA(setuppath.c_str(),NULL); // from 4 to MAX [tmpfile: 0-3] for(int i = 4; i < filescount; i++) { extractFile( i ); // 設置每次解壓完成一個文件進度組件+1 ctd.setProgressPos( "extract", i ); } // click hidden button // goto page5 SendMessageA( ctd.getWnd( "overbutton" ), BM_CLICK, 0, 0 ); }
最後顯示成功頁面page5:
int CALLBACK page5( HWND hDlg, DWORD windowId ) { ctd.clearDlg(); ctd.drawLine( 0, 290, 510, 290, (COLORREF)0xA0A0A0 ); ctd.drawBmp( TMP_WizardImage, 0, 0, 160, 290 ); ctd.setForecolor( RGB( 255, 255, 255 ), {0,0,ctd.hMainDlgRect.right,290} ); ctd.createText( GETSETUPSTRING( 23 ), 180, 20, 300, 22, 16 ); ctd.createText( GETSETUPSTRING( 24 ), 180, 50, 300, 30 ); ctd.createText( GETSETUPSTRING( 25 ), 180, 85, 300, 30 ); //單選框按鈕 ctd.createCheckbox( GETSETUPSTRING( 26 ), 180, 111 ); //跳轉結束的按鈕, 其中判斷若是選中單選框,則運行指定的exe ctd.createbutton( GETSETUPSTRING( 7 ), 300, 300, PARTCALLBACK( end ) ); return 0; }
點擊完成後的代碼:
int CALLBACK end( HWND hDlg, DWORD windowId ) { //安裝完畢後 //建立桌面快捷方式/自動運行的程序 //TODO... //退出UI PostQuitMessage( 0 ); return 0; }
至此界面結束,參考上面的代碼,徹底能夠作出各類自定義的安裝風格.
下一篇: 手擼一個安裝包製做工具(4) --解壓