在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就行了!
实现之后的效果,就是这样的咯
在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就行了!
实现之后的效果,就是这样的咯