在 Delphi 下自定义通用对话框------自定义打开文件对话框[1]

[入库:2005年8月18日] [更新:2007年3月24日]

本文简介:选择自 happyjoe 的 blog

在 delphi 下自定义通用对话框
--------------自定义打开文件对话框

    几次碰到有人在论坛里问如何在 delphi 下自定义通用对话框,本人对此问题也比较感兴趣,所以抽点时间搞了下,现在把“成果”与大家分享。本文的题目大了点,通用对话框有好多,但这里只以打开文件对话框为例。其实自定义所有通用对话框的原理是一样的。

第一步:建立对话框模版

    先来说个概念:对话框模版。对话框模版是一种资源,在 .rc 文件中定义,编译后生成 .res 文件,最终一般存在于资源动态链接库(dll)中或可执行程序中。在专业的共享软件中一般都大量使用模版来创建对话框。通过模版生成的对话框一般用来采集用户输入,上面可以放标准的 windows 控件,比如 button, label, textbox, listbox, listview, treeview 等。

    通用对话框也是由对话框模版生成的窗体,只不过这些对话框模版由操作系统定义,自定义通用对话框就是通过更改这些模版来实现的(打开和保存文件对话框例外,它们是通过添加新的模版来自定义的)。所以第一步要知道怎样定义对话框模版,可以在 notpad 里直接敲 .rc 文件(这种方法这里就不使用了),还可以使用现有的工具,我机器上最好的工具是 visual studio .net ide,只需要点几下鼠标即可。(用它也可以查看、修改可执行文件中的资源,直接点打开->文件,打开可执行文件即可)。现在就先在 vs.net 中定义一个对话框模版(过程略),该模版就是我们在打开文件对话框上自定义的部分,需要注意的是该模版必须具有 ds_3dlook 、ds_control 、ws_child 、ws_clipsiblings 风格且不能有 border,因为通用对话框是将我们的整个模版当作子窗体subclass 到原有对话框的(类似 button 等标准控件与其拥有者的关系)。我将对话框模版的外观和 .rc 文件的内容贴出来:

 // .rc 文件内容
131 dialogex 0, 0, 282, 36
style ds_setfont | ds_3dlook | ds_fixedsys | ds_control | ws_child | 
    ws_clipsiblings
font 8, "ms shell dlg", 400, 0, 0x1
begin
    ltext           "文件名称:",-1,7,8,40,8
    ltext           "此静态控件用来显示文件名称",1004,51,8,224,8,
                    ss_pathellipsis
    control         "如果选中文件是图片文件则进行预览",1005,"button",
                    bs_autocheckbox | ws_tabstop,7,18,268,10
end

    上面对话框模版中的 checkbox 没有任何实际意义,只用来说明功能。将此 .rc 文件编译成 .res 文件(可以用 vs.net 直接编译,也可以用 delphi 带的 brcc32 工具)以备后面例子使用。

第二步:继承 topendialog 类

    调用打开文件对话框只需一个 api:getopenfilename,这个 api 需要一个 openfilename 结构的参数,自定义对话框时将该结构的 lptemplatename 成员指定为对话框模版的标识(identifier)并在 flags 成员中包含 ofn_enabletemplate 常数即可。

    对话框模版及其包含的每个控件都应该有自己唯一的标识,而且这些标识不能与通用对话框上原有控件的标识重复。标识有2种:字符串标识和数字标识,在本例中使用数字标识:对话框模版的标识为 131,第一个静态控件的标识为 -1,第二个静态控件的标识为 1004,checkbox 的标识为 1005。(标识为 -1 的控件一般为内容固定不变的静态控件。) openfilename 结构的 lptemplatename 成员的类型是 null-terminated 字符串指针,如果对话框模版的标识为字符串,则可直接赋值,比如某模版的标识为 idd_mydialog,那么赋值语句为:lptemplatename := pchar('idd_mydialog'),如果为数字,比如本例中的模版的标识为 131,赋值语句则为:lptemplatename := windows.makeintresource(131)。

    delphi 中所有通用对话框类都继承自 tcommondialg 抽象类,在这个抽象类中定义了个受保护的(protected)属性:template,类型为 pchar。这个属性就是用来存放模版标识的,但遗憾的是我们不能在除它的继承类以外的地方访问到它(因为受保护)。所以我们需要在它的孙子类中重新定义一公有(public)属性来间接访问它。

    在 delphi 里新建一个 vcl 类 tmyopendialog 继承自 topendialog 类,定义一公有属性 templateres ,通过其写入方法为受保护的 template 属性赋值,下面列出代码:

//********************************************
// myopendialog.pas
// tmyopendialog 类实现自定义打开文件对话框
// by: joe huang    date: 2004-01-05
//********************************************
unit myopendialog;

interface

uses
  sysutils, classes, dialogs, windows, messages, commdlg;

type
  tcommandevent = procedure (controlid: word) of object;

  tmyopendialog = class(topendialog)
  private
    { private declarations }
    ftemplateres: pchar;
    foncommand: tcommandevent;
    procedure settemplateres(const value: pchar);
  protected
    { protected declarations }
    procedure wndproc(var message: tmessage); override;
  public
    { public declarations }
    //该属性用来指定自定义模版的标识
    property templateres: pchar read ftemplateres write settemplateres;
  published
    { published declarations }
    property oncommand: tcommandevent read foncommand write foncommand;
  end;

procedure register;

implementation

procedure register;
begin
  registercomponents('samples', [tmyopendialog]);
end;

{ tmyopendialog }
procedure tmyopendialog.settemplateres(const value: pchar);
begin
  ftemplateres := value;
  self.template := value;
end;
procedure tmyopendialog.wndproc(var message: tmessage);
begin
  message.result := 0;
  if (message.msg = wm_command) then
  begin
    if assigned(foncommand) then
      foncommand(message.wparamlo);
  end;
  inherited wndproc(message);
end;
end.

    tmyopendialog 类还定义了一个事件用来捕获对话框模版上控件状态发生的改变(后面说明此事件的用法)。将该类注册到组件面板的 samples 页中。

第三步:建立工程实现自定义对话框

    新建一工程保存至目录,将第一步中的 .res 文件放至该目录中并加入到工程文件中。从 samples 页中把我们的新控件拖入 form1 中,名字为 myopendialog1,再在 form1 上放入 button1,button1 的 on_click 事件代码如下:

procedure tform1.button1click(sender: tobject);
begin
  myopendialog1.templateres := windows.makeintresource(131);
  myopendialog1.execute;
end;

myopendialog1 的 on_show 事件代码如下:

procedure tform1.myopendialog1show(sender: tobject);
begin
  //标识为 1004 的控件为第二个静态控件,用来显示选择的文件全名
  //此事件一般用来初始化模版上的控件内容和状态
  setdlgitemtext(myopendialog1.handle, 1004, '初始化...');
end;

myopendialog1 的 on_selectionchange 事件代码如下:

本文关键:Customize Common Dialog Box, Common Dialog Box Customization, 自定义通用对话框, Dialog Box, 对话框, Dialog Template, 对话框模版, TOpenDialog, TCommonDialog, Open File Dialog, 打开对话框, 打开文件对话框
  相关方案
Google
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top