DELPHI中的自定义通用对话框处理
更新时间:2024-03-29 11:39:01 阅读量: 综合文库 文档下载
- delphi 自定义类推荐度:
- 相关推荐
DELPHI中的自定义通用对话框处理和消息处理
一、自定义通用对话框
在Delphi的VCL的Dialog包中存在多个通用对话框,比如TopenDialog(文件选择对话框)、TsaveDialog(文件保存对话框)、TopenPictureDialog(图片打开对话框)、TfontDialog(字体选择对话框)、TfindDialog(文件查找对话框)、TreplaceDialog(文件替换对话框)等13个常用、通用的标准对话框,这里的标准对话框采用的是Windows系统内置的标准对话框,对话框的风格和样式和操作系统的风格和样式是一致的,之所以能够保持一致,是因为通用对话框是由通过对话框模版生成的窗体,只不过这些对话框模版由操作系统定义。
建立自定义通用对话框有两种方式: 1、 修改通过对话框模版来实现的; 2、 通过代码在运行时添加控件;
这里首先介绍一下通过对话框模板方式的实现步骤:
1、对话框模板方式
Delphi的通用对话框位于Delphi系统库的VCL.Dialogs单元,Delphi 中所有通用对话框类都继承自 TCommonDialg 抽象类,
以TfindDialog为例,可以看到创建查找兑换的结构信息如下: tagFINDREPLACEW = packed record
lStructSize: DWORD; { size of this struct $20 }
hWndOwner: HWND; { handle to owner's window } hInstance: HINST; { instance handle of.EXE that
contains cust. dlg. template } Flags: DWORD; { one or more of the fr_?? } lpstrFindWhat: PWideChar; { ptr. to search UnicodeString } lpstrReplaceWith: PWideChar; { ptr. to replace UnicodeString } wFindWhatLen: Word; { size of find buffer } wReplaceWithLen: Word; { size of replace buffer } lCustData: LPARAM; { data passed to hook fn. }
lpfnHook: function(Wnd: HWND; Message: UINT; wParam: WPARAM; lParam: LPARAM): UINT stdcall;
{ ptr. to hook fn. or nil } lpTemplateName: PWideChar; { custom template name }
在这个抽象类中定义了PWideChar 类型的Template属性,这个属性就是用来存放模版标识的,通过在IDE中对操作系统标准的对话框模板进行修改,因为lpTemplateName是保护属性,所以需要对通用对话框进行继承,继承的类中定义好TemplateRes属性,将修改好的模板赋给TemplatesRes属性,例如:TemplateRes := Windows.MakeIntResource(131);其中131为资源ID。
该方法比较麻烦,需要修改模板文件,并引入资源,同时对于新加入的控件,需要捕捉windows消息进行处理,所以推荐使用下面的方式。
2、代码在运行时添加控件
在电子病历编辑器控件中,在标准打印的基础上增加了几个特殊选项,比如
“仅打印奇数页”、“仅打印偶数页”、“奇偶页边距互换”三个选项,对应于标准打印对话框是没有的,这里需要在标准对话框的基础上,在空白区域加上我们需要的控件,这里只要继承标准的打印对话框,在对话框的空白区域,算好控件需要放置的位置就可以了,过程如下:
1、 首先创建TprintDialogEx类继承于标准对话框TprintDialog,并命名为TprintDialogEx;
TPrintDialogEx = class(TPrintDialog)
2、 创建一个Tpanel,计算好位置到空白区域,这里打印窗口是Fixed窗口,空白区域
属于绝对位置;
FExtendedPanel := TPanel.Create(self); with fExtendedPanel do begin
Name := 'ExtendedPanel'; Caption := '';
SetBounds(0, 0, 169, 200); // (204, 5, 169, 200); BevelOuter := bvNone; BorderWidth := 6; TabOrder := 1; End;
3、将3个CheckBox对应FextendedPanel的位置进行放置,并挂接事件就OK了;FCheckBoxOdd:=TCheckBox.Create(Self); with FCheckBoxOdd do begin
Name:='CheckBoxOdd'; Checked:=False;
caption:='仅打印奇数页'; SetBounds( 2, 7, 90, 28 ); Parent := FExtendedPanel; end; ….
这种方法最大的好处是方便,不需要再修改模板并且再去捕捉系统Windows消息,直接挂接事件,对属性进行赋值就可以;其中最大的问题是对应的位置要比较固定,但是这些对话框基本上都是Fix固定大小的窗体,对应的位置并不需要过多的考虑。
二、通用对话框的消息处理
通用对话框的基类TcommonDialog的基类是Tcomponent,但是它并不能按照普通的TWinControl那样进行控件操作和事件的处理,查看Tdialog单元源代码,会发现每个通用对话框,会创建一个TredirectorWindow类,代码如下:
FRedirector := TRedirectorWindow.Create(nil); with TRedirectorWindow(FRedirector) do begin
FFindReplaceDialog := Self; end;
TRedirectorWindow(FRedirector).FFormHandle := GetActiveWindow; FFindReplace.hWndOwner := FRedirector.Handle;
从以下代码可以看到FfindReplace.hWndOwner,即FfindReplace的宿主是Fredirector,再来看TredirectorWindow的定义,TRedirectorWindow = class(TWinControl),其中注释描述如下:
{ TRedirectorWindow }
{ A redirector window is used to put the find/replace dialog into the ownership chain of a form, but intercept messages that CommDlg.dll sends exclusively to the find/replace dialog's owner. TRedirectorWindow creates its hidden window handle as owned by the target form, and the find/replace dialog handle is created as owned by the redirector. The redirector wndproc forwards all messages to the find/replace component. }
重定向window是用来创建一个隐藏的窗口句柄,redirector的处理的Wndproc消息都被重定向到通用对话框组件上。
所以,通用对话框的处理都来自于windows系统的CommDlg.dll,TredirectorWindow用来转发Delphi程序中的消息给通用对话框,这里也可以看出Delphi中的通用对话框是对windows标准对话框进行封装后的结果,windows标准对话框中的控件并不能当做delphi中的控件进行直接访问。
在开发电子病历编辑器控件的过程中,出现一个问题,对于Delphi的ActiveX控件在非模态窗体状态,接受输入法输入时,输入内容呈现的是乱码,如果是英文和数字输入则没有问题,而且模态窗体状态没有这种情况,在独立EXE程序中也没有。
通过跟踪对话框消息,发现在非模态窗体状态,接受的windows的WM_CHAR消息,接收到的Wparam参数内容和正常的情况不一样,在模态状态下,接受的Wparam是4位长度,而在非模态状态下的Wparam是6位长度,并且与正常情况下的内容没有规律可循,经过分析对比发现,模态和非模态对话框在DELPHI中的处理的不同在于:
? 非模态对话框
响应一个消息,系统处理一个消息,处理完毕后返回控制权给Windows; ? 模态对话框
在对话框创建后,挂起外部的消息,只是响应对话框内部的消息,而外部消息则全部\过滤\掉了,直到系统接收到WM_DESTROY或WM_CLOSE后,系统返回控制权给模态对话框创建前的线程,继续模态对话框创建前的线程将执行的代码; 在Windows中有两个接受字符的消息,WM_CHAR和WM_IME_CHAR; 1、 WM_CHAR
如果窗口是unicode(IsWindowUnicode),WM_CHAR的wParam就是unicode字符。如果窗口式ANSI,WM_CHAR的wParam是一个单字节的值。如果输入中文,则会得到2个WM_CHAR,把这两个单字节值合到一起就是输入的中文; 2、 WM_IME_CHAR
如果是unicode window,则wParam就是unicode字符,此时和WM_CHAR没有任何区别。
如果是ansi window,则wParam是双字节的mbc编码。 其中IME(Input Method Editor)的消息处理流程:
当用输入法输入时,首先发送WM_IME_COMPOSITION消息,在这个消息处理中,可以用ImmGetCompsitionString得到输入的字符串。如果不处理,则DefWndProc会针对每个字符串重新发送WM_IME_CHAR,如果WM_IME_CHAR也未处理,则 DefWndProc会再次发送WM_CHAR。
所以,我判断之所以会造成乱码,很有可能是OCX在非模态状态下,即接受了WM_CHAR又接收了WM_IME_CHAR消息,造成最后的wParam是三个字节的内容,造成最后的输出是三个字节的乱码内容。
经过实验,捕捉输入控件的WM_IME_CHAR事件,并将WM_IME_CHAR作为WM_CHAR事件转发出去,就可以解决这个问题了!处理代码如下:
case Message.Msg of WM_IME_CHAR: begin
KeyMsg:=TWMKey(Message);
SendMessage(Edit1.handle, WM_CHAR, KeyMsg.CharCode, 0); end;
以上实验是针对普通的Tform中的Tedit控件进行的实验,但我要解决的问题是在通用对话框中对WM_IME_CHAR消息的处理。
在通用查找对话框中的Edit输入控件根本不是标准TWinControl控件,不能像Delphi中标准控件那样直接挂接WndProc过程,所以必须通过遍历通用对话框中的输入控件,然后再挂接消息处理过程;
1、 2、 3、
首先遍历通用对话框中的控件,判断控件的ClassName,这里ClassName通过Spy++工具可以查看的到;
找到CalssName = ‘Edit’的控件,将其消息处理转到自定义的消息处理过程中; 捕捉WM_IME_CHAR消息,并作为WM_CHAR进行转发,并忽略掉默认的WM_IME_CHAR处理。
代码如下:
//遍历通用对话框中的控件,并判断ClassName
function EnumChildWndProc(AhWnd: LongInt; AlParam: lParam) : Boolean; stdcall; var
WndClassName: array [0 .. 254] of Char; WndCaption: array [0 .. 254] of Char; className, Caption: string; begin
GetClassName(AhWnd, WndClassName, 254); GetWindowText(AhWnd, WndCaption, 254); className := string(WndClassName); Caption := string(WndCaption); if className ='Edit' then begin
SetProp(AhWnd, GWL_WNDPROC));
//挂接到FindReplaceWndProc消息处理过程
SetWindowLong(AhWnd, GWL_WNDPROC, LongInt(@FindReplaceWndProc)); end; Result := True; end;
//FindReplaceWndProc中对WM_IME_CHAR的处理 WM_IME_CHAR: begin
SendMessage(Wnd, WM_CHAR, WParam, 0); Result:=-1;
MakeIntAtom(WndProcPtrAtom),
GetWindowLong(AhWnd,
Exit; end; 三、总结
在Delphi实际开发中,有些在独立EXE程序中可以正常的处理,而在ActiveX控件中则会出现一些莫名其妙的问题,究其原因都是因为在OCX控件中消息处理机制在和独立EXE程序中差异造成的,通过以上问题的解决为今后对错误的处理和判断都有很好的借鉴意义。
正在阅读:
DELPHI中的自定义通用对话框处理03-29
(苏教牛津版)一年级英语下 期中测试卷01-08
中小学教师研修个人工作计划参考范文模板08-03
catia鼠标曲面详细讲义 法语版04-21
论文 自我陈述11-01
月季花作文500字07-16
还没来得及说我爱你02-13
MATLAB习题精选12-08
山西省2015年下半年监理工程师《合同管理》:合同生效时间的规定考试试题03-11
医学生暑假社会实践报告参考04-18
- 多层物业服务方案
- (审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)
- 人教版新课标六年级下册语文全册教案
- 词语打卡
- photoshop实习报告
- 钢结构设计原理综合测试2
- 2014年期末练习题
- 高中数学中的逆向思维解题方法探讨
- 名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版
- 北航《建筑结构检测鉴定与加固》在线作业三
- XX县卫生监督所工程建设项目可行性研究报告
- 小学四年级观察作文经典评语
- 浅谈110KV变电站电气一次设计-程泉焱(1)
- 安全员考试题库
- 国家电网公司变电运维管理规定(试行)
- 义务教育课程标准稿征求意见提纲
- 教学秘书面试技巧
- 钢结构工程施工组织设计
- 水利工程概论论文
- 09届九年级数学第四次模拟试卷
- 对话框
- 定义
- 通用
- 处理
- DELPHI
- 倍福故障手册 - 图文
- 2019-2025年中国幼儿教育产业深度调研与发展现状分析报告(定制
- 湖北省有机化学原料行业企业名录2018版279家 - 图文
- 2017年中国NTC热敏电阻器行业研究及发展趋势预测(目录) - 图文
- 大学生职业生涯规划与发展讲义
- 第二章课后习题答案
- 教育学综合考研2007-2012历年真题及答案详解 - 图文
- 学校班级文化中队名称班主任寄语班级口号修订稿
- ubuntu
- 基于51的波形发生器设计报告
- 关于开展摄影作品征集活动的通知
- 近年年注税备考 - 财务与会计考试测验模拟试题02
- 心理学打印版
- 快速记单词的秘诀
- 《中国古代文学(B)(1)(专科必修)》2016期末试题及答案
- 供应链管理计算题总结
- 世界现代史名词解释(华师10)
- 热电阻的测温电路
- 2017六一节目串词 定稿
- 001-武汉大学-14-丁俊萍-思想政治理论课多元立体教学模式探索 -