在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就行了!
實現之后的效果,就是這樣的咯
