在Delphi中使用PrintDialog打印對話框的時候,這個控件有三個選項,就是PrintRang那個屬性的三個選項,其中有一個選項三,讓我們自定義選擇頁碼范圍來打印。但是比較蛋疼的是,這個地方選中了之后啥子效果都沒有。無法制定自己的頁碼范圍,很是蛋疼。這里實際上應該要有一個Edit之類的編輯框的,這樣可以讓用戶輸入1,2,3-4之類的頁碼范圍來整就比較人性化了。起初以為是自己沒有指定某屬性神馬的導致,於是在控件的各個屬性中找,找的我蛋都要裂開了,都沒找出來似乎是隱藏了那個Edit的屬性。。。。無果,整開了PrintDialog的源碼看。也未發現相關的代碼。咋辦,咋辦呢。路總是人走出來的,目的就是要在這個彈出的對話框上加一個編輯框就OK了,方式很多,可以在彈出來之后,查找句柄,然后創建一個Edit,然后SetParent就上去了。這是一方面,另外一方面,就是要配合對話框上,用戶點擊上面的選項來相應的聯動這個Edit為可用或非可用狀態。這個自然也是有辦法的,我首先想到的就是Hook了,於是就用Hook整了,WH_CallWndProc消息處理過程函數的Hook,就行了。至於是要攔截神馬消息,嘿嘿,這個是WinSDK的范疇,不熟悉的人,去翻番書,或者百度一番,就可以知道是WM_Command這個消息來處理窗口中的某些控件的消息處理的。首先就是要獲取那個彈出的打印對話框的句柄了,我說過了可以用FindWindow來找。不過我這里要使用消息過程鈎子,那么自然就不要這個了,直接從鈎子中獲取對話框句柄,會更加Happy。看看PrintDialog的代碼,俺們可以知道,神馬PrintDialog,OpenDialog,FontDialog打開都要觸發WM_InitDialog這個消息,就是初始化對話框的消息。所以,第一步,俺們就攔截這個消息就 可以獲取到句柄,然后創建俺們的Edit,然后將Edit設置到對話框中,俺們需要他在的位置。第二步,就是來攔截WM_Command,然后來處理和用戶點擊的聯動處理咯。然后就是在對話框的Destroy消息中注銷Hook,釋放Edit。於是這個過程就OK了
首先在打開對話框之前,注冊我們的過程處理鈎子,必須要之前注冊,因為要攔截WM_InitDialog消息嘛
procedure TForm1.Button1Click(Sender: TObject); begin CEdit := TEdit.CreateParented(Application.Handle); CEdit.Parent := Application.MainForm; Hok := SetWindowsHookEx(WH_CALLWNDPROC,WNDProcHook,HInstance,GetCurrentThreadId); if PrintDialog1.Execute then begin ShowMessage(CEdit.Text); end; UnhookWindowsHookEx(HOK); FreeAndNil(CEdit); end;
然后是鈎子函數過程處理
var DownBtnID: Integer; PrntDlgHandle: THandle; CEdit: TEdit; function WNDProcHook(code: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT stdcall; var msg: PCWPSTRUCT; wNotifyCode,wID: Word; r,WinR: TRect; DwonBtnHandle: THandle; begin if code < 0 then Result := CallNextHookEx(Hok, code, wparam, lparam) else begin msg := PCWPSTRUCT(lparam); case msg.message of WM_INITDIALOG: begin PrntDlgHandle := msg.hwnd; DwonBtnHandle := FindWindowEx(PrntDlgHandle,0,'Button','打印范圍'); Windows.SetParent(CEdit.Handle,DwonBtnHandle); GetWindowRect(DwonBtnHandle,WinR); CEdit.Visible := True; DwonBtnHandle := FindWindowEx(PrntDlgHandle,0,'Button','選定范圍(&S)'); CEdit.Enabled := SendMessage(DwonBtnHandle,BM_GETCHECK,0,0) = 1; GetWindowRect(DwonBtnHandle,r); DownBtnID := GetDlgCtrlID(DwonBtnHandle); CEdit.Left := r.Right - WinR.Left; CEdit.Top := r.Top - WinR.Top; end; WM_COMMAND: begin if msg.hwnd = PrntDlgHandle then begin wNotifyCode := HIWORD(Msg.wparam); wID := LOWORD(Msg.wParam); if wNotifyCode = BN_CLICKED then begin CEdit.Enabled := wID = DownBtnID end; end; end; WM_DESTROY: begin //UnhookWindowsHookEx(HOK); //Hok := 0; //FreeAndNil(CEdit); end; end; Result := 0; end; end;
可見,我這里注銷了WM_Destroy中的處理。目的是因為俺們還需要返回這個Edit中的內容嘛,所以我們直接在使用完了之后注銷鈎子,釋放Edit就行了!
實現之后的效果,就是這樣的咯