Delphi中实现可以更改大小的对话框

原创 2005年04月11日 13:33:00

关键字:Dialog、对话框、resizable

1、问题的提出
问题来自Stanley_Xu,希望得到只有关闭按钮(还可以有帮助),左上也没有程序的图标并且能够更改窗口大小的对话框。
VCL中为TForm设置了BorderStyle和BorderIcons属性,用以简化窗口样式的设置(否则就要调用SetWindowLong和GetWindowLong等API函数)。TFormBorderStyle和TBorderIcon的定义和说明如下:

Value          Meaning
bsDialog       Not resizable; standard dialog box border//不能改大小
bsSingle       Not resizable; single-line border
bsNone Not     resizable; no visible border line
bsSizeable     Standard resizable border
bsToolWindow   like bsSingle but with a smaller caption
bsSizeToolWin  like bsSizeable with a smaller caption

type TBorderIcon = (biSystemMenu, biMinimize, biMaximize, biHelp);
TBorderIcons = set of TBorderIcon;

Value          Meaning
biSystemMenu   The form has a Control menu (also known as a System menu).
biMinimize     The form has a Minimize button
biMaximize     The form has a Maximize button
biHelp         If BorderStyle is bsDialog or biMinimize and biMaximize are excluded, a question mark appears in the form's title bar and when clicked, the cursor changes to crHelp; otherwise,no question mark appears.

显然,通过BorderStyle和BorderIcons只能够满足一般的需要,要实现能够修改大小的对话框就有所力不能及了。
一般情况下,我要得到不能最大最小化但又可以更改大小的窗口,就把BorderStyle设置为bsSizeable,把BorderIcons的biMinimize和biMaximize去掉,结果象这样:窗口可以修改大小,但左上角有图标,:

VcLSizableDlg
图 1 带图标的对话框


注意左上角有图标。

而我们的目标则是下面的两种效果,左上角都没有图标,但窗口都可以修改大小。

OpenSaveDlg
图 2 打开文件对话框

Browse4Folder

图 3浏览文件夹对话框


2、问题解决一半
搜索了一下MSDN,找到一篇教你如何设计可以可更改大小的属性页的文章(在MFC中CPropertySheet是作为CPropertyPage子页出现的,后者从CDialog继承而来,通常不能修改大小)《
How To Design a Resizable MFC Property Sheet》,文中介绍的方法是在属性页创建之前修改窗口样式,然后手动处理WM_SIZE消息。

int CALLBACK CMyPropertySheet::XmnPropSheetCallback(HWND hWnd, UINT message, LPARAM lParam)
{
    extern int CALLBACK AfxPropSheetCallback(HWND, UINT message, LPARAM lParam);
    // XMN: Call MFC's callback
    int nRes = AfxPropSheetCallback(hWnd, message, lParam);

    switch (message)
    {
    case PSCB_PRECREATE:
       
// Set our own window styles
        ((LPDLGTEMPLATE)lParam)->style |= (DS_3DLOOK | DS_SETFONT
  | WS_THICKFRAME | WS_SYSMENU | WS_POPUP | WS_VISIBLE | WS_CAPTION);
        break;
    }
    return nRes;
}

我试着将同样的方法用到VCL的一个Form中。在设计时把BorderStyle设置为bsDialog,然后重载CreateParams方法。但结果是对话框确实变成了厚边框(因为有WS_THICKFRAME样式),鼠标移动到各个边框后能够自动变化,左上角也没有图标,但窗口就是不能改变大小(添加的WM_SIZE消息处理过程没有触发)。问题出在哪里呢?

HalfZoCDlgResizable

图 4 还不能完全令人满意的对话框

3、问题的解决
查了一翻Forms.pas的源代码,发现了问题所在。TCustomForm的WM_NCCREATE消息处理过程中有一个ModifySystemMenu嵌入过程,用来修改Form的系统菜单。注意下面红色文字说的是“使系统菜单看起来像对话框一样”。接下来的几句代码就把系统菜单项删得只剩下了“移动”和“关闭”。

procedure TCustomForm.WMNCCreate(var Message: TWMNCCreate);

procedure ModifySystemMenu;
var
    SysMenu: HMENU;
begin
    ……
   
{ Modify the system menu to look more like it's s'pose to }
    SysMenu := GetSystemMenu(Handle, False);
    if FBorderStyle = bsDialog then
    begin
        
{ Make the system menu look like a dialog which has only
        Move and Close }

        DeleteMenu(SysMenu, SC_TASKLIST, MF_BYCOMMAND);
        DeleteMenu(SysMenu, 7, MF_BYPOSITION);
        DeleteMenu(SysMenu, 5, MF_BYPOSITION);
        DeleteMenu(SysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
        DeleteMenu(SysMenu, SC_MINIMIZE, MF_BYCOMMAND);
        DeleteMenu(SysMenu, SC_SIZE, MF_BYCOMMAND);
        DeleteMenu(SysMenu, SC_RESTORE, MF_BYCOMMAND);
    end else
    ……
end;

begin
    inherited;
    SetMenu(FMenu);
    if not (csDesigning in ComponentState) then ModifySystemMenu;
end;

所以,问题出在由于“SC_SIZE”被删掉,窗口的样式出现了畸形:有WS_THICKFRAME(可以修改窗口大小),但不响应WM_SIZE消息(SC_SIZE被删掉)。
解决的办法很简单:实现自己的WM_NCCREATE消息处理过程,手动修改系统菜单。


procedure TZoCDlgResizable.WMNCCreate(var Message: TWMNCCreate);

 //The following codes are copied from Form.pas line 4047, Delphi 7 sp1.
 procedure ModifySystemMenu;
 var
     SysMenu   : HMENU;
 begin
     SysMenu := GetSystemMenu(Handle, False);
     
{ Make the system menu look like a dialog which has only
  Move, Size and Close commands}
     DeleteMenu(SysMenu, SC_TASKLIST, MF_BYCOMMAND);
     DeleteMenu(SysMenu, 7, MF_BYPOSITION);
     
//Don't remove the separater before CLOSE command.
//   DeleteMenu(SysMenu, 5, MF_BYPOSITION);

     DeleteMenu(SysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
     DeleteMenu(SysMenu, SC_MINIMIZE, MF_BYCOMMAND);
     
{ Don't remove the SIZE command, otherwise we'll lose the
  capability of resizing the Dialog. }
//   DeleteMenu(SysMenu, SC_SIZE, MF_BYCOMMAND);

     DeleteMenu(SysMenu, SC_RESTORE, MF_BYCOMMAND);
 end;

begin
   
{ Skip TCustomForm's WM_NCCREATE handler, which remove
    the SIZE command from the System Menu.}
    inherited DefaultHandler(Message);
   
//Dealing with the System Menu in our own way.
    ModifySystemMenu;
end;

4、TZoCDlgResizable类
最终的解决方案我封装为一个继承自TForm的类,效果如下,与图1相同(如果想要图2那样的系统菜单则把调用ModifySystemMenu的行删掉),使用的时候从TZoCDlgResizable继承一个即可。
BTW:我还顺手给TZoCDlgResizable加了个SizeGrip属性,具体情况可以看代码。


图 5 没有图标、可以修改大小、带有SizeGrip的对话框

下载(exe和源代码)
http://zocsoft.vicp.net:8080/Article%20Demos/ResizableDialog.rar

5、参考资料:

MSDN: How To Design a Resizable MFC Property Sheet

引用地址:《Delphi中实现可以更改大小的对话框

C++模板的定制二:定制C++类

 C++模板的定制二:定制C++类       类模板的基本语法如下:       template        class classname{       ……};T可以是任何类型,下面我就举一...
  • winmain
  • winmain
  • 2001-11-09 20:33:00
  • 684

Delphi中捕捉窗体的最小化、最大化、还原消息

 procedure TForm1.WMSysCommand; begin if (Msg.CmdType = SC_MINIMIZE) then //最小化消息 begin /...
  • aroc_lo
  • aroc_lo
  • 2009-11-26 09:30:00
  • 1781

实现控件的移动,改变大小(DELPHI实现)

实现控件的移动,改变大小(DELPHI实现)主要使用Perform方法  function Perform(Msg: Cardinal; WParam, LParam: Longint): Longi...
  • jinzhili
  • jinzhili
  • 2007-01-16 13:59:00
  • 2889

Delphi中创建一个可以改变大小的无边框窗口

procedure TForm1.CreateParams(var Params: TCreateParams) ; begin   BorderStyle := bsNone;   inh...
  • fghydx
  • fghydx
  • 2016-08-23 15:52:56
  • 1151

<em>delphi</em>7 <em>弹出</em>式<em>对话框</em>总结

2014-08-27 上传<em>大小</em>:138KB <em>delphi</em>7<em>弹出</em>式<em>对话框</em> <em>Delphi</em> <em>弹出</em>式<em>对话框</em>总结,...点击<em>按钮弹出</em>框选择 立即下载 上传者: 冷紫云 时间: 2015-12-23 综合评分:...
  • 2018年04月09日 00:00

控件自适应对话框大小

总结1:由于目前开发的程序只是在实验室内部使用,其使用的显示器都是实验室自己订购的同一个型号(分辨率为1024*768),因此可以考虑开发程序时将开发环境的分辨率设置与使用环境一样(即1024*768...
  • zhaoxiatengkong_1
  • zhaoxiatengkong_1
  • 2013-08-21 23:30:41
  • 1695

深入了解Delphi 7中的四种消息框

Delphi中平常使用的消息框有四种形式,有ShowMessage、MessageDlg、Application.MessageBox、MessageBox。...
  • akof1314
  • akof1314
  • 2011-03-17 17:30:00
  • 26152

单击按钮弹出对话框窗体

package Dialog; import java.awt.Color; import java.awt.Container; import java.awt.Window; import ja...
  • ThinkPet
  • ThinkPet
  • 2018-03-03 13:47:28
  • 33

怎么弹出一个新的窗口

  • zgqtxwd
  • zgqtxwd
  • 2008-05-01 06:40:00
  • 167

<em>Delphi对话框</em>控件小例子

2010-09-21 上传<em>大小</em>:183KB <em>Delphi</em>控件 学习使用TShape、TButton、TBitBtn、T...<em>Delphi</em>禁止WebBrowser<em>弹出</em>IE的<em>对话框</em> 立即下载 上传者: szwincom 时间: 2013-...
  • 2018年04月08日 00:00
收藏助手
不良信息举报
您举报文章:Delphi中实现可以更改大小的对话框
举报原因:
原因补充:

(最多只允许输入30个字)