2024年3月26日发(作者:)
信息框函数MsgBox
信息框是Windows应用程序中使用得较多的一种对话机制,它被广泛地用于
提示、选择程序走向,是一个重要的程序控制手段。Delphi 提供的信息框函数
MessageDlg功能比较强,其最大优点是可以任意设定信息框的按钮(使用了集合
类型),但其缺点也是很明显的,主要表现在标题字符串不能由用户自己设置;窗
口弹出时寂静无声;按钮不能随着Windows的不同语言的版本显示不同的文字
(例如无论在哪种语言版本下都只能显示"OK"、"Yes"等英文字符)。这些优点和
缺点都是由于它是Delphi自己实现的,而不是通过调用系统API函数实现的,故
不能使用系统的语言环境、多媒体等资源。这样,所开发的程序在中文版中显示
信息框时与周围的窗口显得极不协调。而VB在这方面却做得较好,所以我们按
照VB的格式自定义一个信息框函数MsgBox。下面的函数都假定是在TForml中
定义的。为了使用方便,我们首先在 Interfaces段中定义一些符号常量:
const
{第一组:按钮内容选择}
OKOnly=0;{仅显示"确定"按钮}
OKCancel=1;{显示"确定"和"取消"按钮}
AbortRetryIgnore=2;{"中止""重试""放弃"}
YesNoCancel=3;{"是""否""取消"}
YesNo=4;{"是"和"否"}
RetryCancel=5;{"重试""取消"}
{第二组:显示图标选择}
Critical=16;{"STOP"图标}
Question=32;{"?"图标}
Excalamation=48;{"!"图标}
Information=64;{"i"图标}
{第三组:缺省指针位置(激活状态)}
DefaultButton1=0;{第一按钮}
DefaultButton2=256{第二按钮}
DefaultButton3=512{第三按钮}
{第四组:信息框方式}
ApplicationModal=0;{应用方式}
SystemModal=4096;{系统方式}
然后,建立函数MsgBox,由于API函数中使用的字符串必须以mull结尾,所
以使用了另一个自定义的函数StrToPch来将Pascal类型字符串转换成为以
mull结尾的字符串。参数说明
msg为信息框标题变量;
mbType为规定信息框类型的变量,使用方式是"mbType=按钮内容+图标+缺
省指针+信息框方式"?闳缒氲玫揭桓龊?确定"和"取消"两个按钮、带"?"图
标、缺省指针指向第二个按钮(即"取消")的信息框,那么就该这样设
置:mbType:=OKCancel+Question+DefaultButton2;
title为信息框中显示文本的变量。
MsgBox的返回值与MessageDlg函数的返回值完全一样,例如返回mrYes表
示"Yes"或"是" 按钮被按下,mrNo表示"No"或"否"按钮被按下等等。可参考
MessageDlg函数的说明。下面即是在Delphi中通过调用Windows API的
GetActive Windows函数和MessageBox函数来实现Msg
Box函数的代码:
{信息框函数}
function (msg:string;mbType:Word;title:stri
ng):Word;
var hWnd:HWND;
1pText,!pCaption:Pchar;
begin
1pText:=StrToPch(title);
1pCaption=StrToPch(msg);
hWnd:=GetActiveWindow();
MsgBox:=MessageBox(hWnd,1pText,1pCaption,mbType);
end;
{将Pascal字符串转换成null结尾字符串函数}
function ch(Str:string):PChar;
var
a:PChar;
begin
a:=StrAlloc(Length(Str)+1);
StrPCopy(a,Str);
StrToPch:=a;
end;
二、文件拷贝函数CopyFDelphi提供了一组比较完整的文件操作函数,用它
们可以完成几乎全部的文件操作,但恰恰缺少拷贝文件的函数。而文件拷贝的使
用应该说是比较常用的,因此,笔者利用几个API函数定义了一个功能很强的文
件拷贝函数CopyF。该函数代码如下(请注意:该函数中调用了上述的MsgBox函
数):
{文件拷贝函数}
function (var ExistingFileName:string;const
NewFileName:string; var Mode:Integer):Boolean;
var
EFile,NFile:PChar;
CpFlag,FailIfExists:Boolean;
msg:string;
ErrID,mbType:integer;
begin
EFile:=StrToPch(ExistingFileName);
NFile:=StrToPch(NewFileName);
if (Mode=1) or (Mode=3) then FailIfExists:=True
else FailIfExists:=False;
CpFlag:=CopyFile(EFile,NFile,FailIfExists);
if not CpFlag then
begin
ErrID:=GetLastError();
ExistingFileName:=SysErrorMessage(ErrID);
if Mode<2 then
begin
msg:='CopyFile Error!';
mbType:=OKOnly+Excalamation;
MsgBox(msg,mbType,ExistingFileName);
end;
Mode:=ErrID;
end;
CopyF:=CpFlag;
end;
CopyF函数参数说明如下:
若拷贝操作成功,函数CopyF返回True,失败函数CopyF返回False。
ExistingFileName是字符变量,输入时代表源文件名。若操作失败,则返回
错误信息字符串(由于调用了API函数,在中文Windows下该信息当然就是中
文)。
NewFileName是字符常量,代表目标文件名。
Mode是整数变量,输入时代表拷贝的方式:
0表示如果目标文件存在,将覆盖它,操作失败,将显示具有出错信息的信息
框;
1表示如果目标文件存在,不覆盖它,操作失败,显示具有出错信息的信息
框;
2表示如果目标文件存在,将覆盖它,操作失败,不显示信息框;
3表示如果目标文件存在,不覆盖它,操作失败,不显示信息框;
当拷贝操作失败时,Mode将返回出错代码。
总之,灵活应用API函数可以使您的应用程序的界面与您使用的Windows的
语言环境相当和谐地融为一体,摆脱掉Delphi的痕迹,使您的程序给人以相当"
专业"的感觉。最后说明一点,如果要使这些自定义的函数成为"全局"的,在其它
单元中也能够使用,需将函数标题复制到Unitl单元interfaces的type段中
(应删除"TForml."几个字符);然后在调用函数的其他单元implementation中的
user段中加入Unitl;在函数名前要加上"Form1."几个字符,如在Unit2单元中
调用MsgBox就应写成。
(以上所有函数均在Windows 95中文版使用Delphi Desktop V2.0调试通
过)
2 如何检视 Delphi 所产生的汇编码?
Glen Boyd 的回答:
开启登录编辑程序(),接着到
『HKEY_CURRENT_USERSoftwareBorlandDelphi2.0Debugging』下新增一个
字符串机码『EnableCPU』,将它的字符串值设『1』。此後Delphi整合环境的
View选单下就会多一个『CPU』选项,它会开启一个窗口来检视目前程序指令的
内存及汇编。你可以在侦错时利用单步追踪或其它方法来观察它。
1 如何建立不定数目的对象数组?
最简单的方法是使用 TList 类。我发现从 TList 衍生一个新类很有用处。接
下来的程序码示范如何为一个特定型态撰写一个特别的 TList 类,并且加进基
本的错误检查。
TListOfMyObject = class (TList)
private
function GetItems(Index: Ordinal): TMyObject;
public
property Items[Index: Ordinal]: TMyObject read GetItems;
procedure Add(AObject: TMyObject);
end;
function ms (Index: Ordinal): TMyObject;
begin
if Index >= Count then
raise Fmt('Index(%d) outside range 1..%d', [Index, Co
unt-1]);
Result := inherited Items[Index];
end;
procedure (AObject: TmyObject);
begin
inherited Add(AObject);
end;
当构件重绘时如何防止闪动的情况?
如果构件的 ComponentStyle 属性没有包含 csOpaque 旗帜的话,调
用 Invalidate方法时会导致构件的背景先被擦掉再重绘。如果你在 Paint 方
法中绘制背景,那你应该在构件的建构函式中加上:
ComponentStyle := ComponentStyle + [csOpaque];
Max Nilson的回答:
引起闪动另一个原因可能是 WM_ERASEBKGND 讯息的处理。当 VCL 控制项收到
一个 WM_ERASEBKGND 讯息时,它会将构件的背景擦掉然後配置成预设的颜色。
如果你的元件衍生自 TWinControl,而且构件的颜色与背景颜色不同(例如图形),
每次重画以前都会将构件先清成背景颜色再重绘,这就是造成闪动的原因了!
解决的方法不难,你必须告诉 Windows 你要自行解决『所有的』绘图动作。不
过有一个前提是,你一定要确定你的 Paint 方法将整个构件都画过,如果你漏了
什麽地方忘了画,那个部分的数据会由乱数组成,你能想见这情况吗?使用这个
方法可以加速你的构件绘制动作(稍微快一点点),因为少了一个填满背景颜色的
动作。
type
TMyComponent = class (TWinControl)
...
protected
procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEB
KGND;
...
end;
procedure eBkgnd(var Message: TWMEraseBkgnd);
begin
// 不要重绘背景,这会造成构件闪动
:= 0
end;
想要你的构件能够处理方向键,你必须要拦截 CM_WANTSPECIALKEY 构件讯
息。 CM_WANTSPECIALKEY 构件讯息提供你比拦截 WM_GETDLGCODE 窗口消息更
容易且灵活的判断方法来决定是否需要某些特殊键的讯息。当控制项收到任何
一个特殊键时就会送出CM_WANTSPECIALKEY 构件讯息给控制项。
特殊键包括:VK_TAB、VK_LEFT、VK_RIGHT、VK_UP、VK_DOWN、VK_RETURN、
VK_EXECUTE 、VK_ESCAPE 及 VK_CANCEL。如果讯息传回值是非零值,这个键就
会被送至 KeyPress 方法以供处理,否则这个键的讯息会被送至构件的父控制项,
以预设方式来处理。
一个简单的范例:
type
TMyComponent = class (TWinControl)
...
protected
procedure CMWantSpecialKey(var Message: TCMWantSpecialKey); message C
M_WANTSPECIALKEY;
...
end;
procedure SpecialKey(var Message: TCMWantSpecialKe
y); begin
inherited;
// 我们只想处理向左方向键,其它的特殊键都给 Windows 处理
if de = VK_LEFT then
:= 1;
end;
CM_WANTSPECIALKEY 构件讯息比 WM_GETDLGCODE 讯息更具有弹性的地方在这
儿。我们甚至可以根据是按下的是哪个特殊键才决定是否处理这个键。例如,你
的控制项有三张图像,你可以让使用者利用左右方向键来回检视它们,如果翻到
最後一张图像再按向右键时,焦点就让它离开构件,剩下的全部都让 Delphi 来
处理。
发布评论