模式窗体和非模式窗体
区别:模式窗体:你必须关闭该窗体,才能操作其它窗体;比如说,必须按确定或取消,或者按关闭。 非模式窗体:不必关闭该窗体,就可转换到其它窗体上进行操作。
模式窗体:ModalForm.Showmodal;
非模式窗体:ModelessForm.Show;
TCustomForm是Windows窗口(一般窗口与对话框)的基类。它有两个显示窗口的方法:Show()和ShowModal()分别用来显示非模态与模态的窗口。不过,它对于模态窗口的实现并没有利用Windows系统提供的DialogBox()之类的API,而是VCL自己实现的。原因可能是无法将DialogBox()与VCL的Form机制很好地结合。
这一节来研究一下Show()和ShowModal()的具体实现。
先是Show():
begin
Visible : = True;
BringToFront;
end;
Show()的代码非常简单,而且易懂,它的行为与其名称一样的单纯。
而ShowModal()要做的事情则多得多:
var
…… // 省略变量声明
begin
…… // 省略部分代码
try
Show; // 调用Show()方法显示窗口
try
SendMessage(Handle, CM_ACTIVATE, 0 , 0 );
ModalResult : = 0 ;
// 接管线程主消息循环,使窗口“模态”化
repeat
Application.HandleMessage;
if Application.FTerminate then
ModalResult : = mrCancel
else
if ModalResult <> 0 then CloseModal;
until ModalResult <> 0 ;
Result : = ModalResult;
SendMessage(Handle, CM_DEACTIVATE, 0 , 0 );
if Get ActiveWindow <> Handle then
ActiveWindow : = 0 ;
finally
Hide; // 窗口消失
end ;
finally
// 省略部分代码
end ;
end ;
可见,VCL中的模态窗口是通过接管线程主消息循环来实现的,只是它的退出循环条件是ModalResult <> 0(ModalResult初始值为0),那么,ModalResult的值是何时被改变的呢?有两种方式可以改变这个ModalResult的值:
一种是程序员在模态窗口中的某个事件代码中显式地改变ModalResult的值。如:
ModalResult := mrOK;
另一种是设置该窗口上的某个按钮的ModalResult的属性值,当单击该按钮后就改变了窗口的ModalResult。也许有人会奇怪,按钮属性是如何和窗口的属性联系起来的呢?看一下TButton的Click方法就知道了,该方法会在每个按钮被按下后被执行:
procedure TButton.Click;
var
Form: TCustomForm;
begin
// 获取按钮父窗口的TCustomForm对象
Form := GetParentForm(Self);
// 改变Form对象的ModalResult值
if Form <> nil then Form.ModalResult := ModalResult;
// 调用TControl.Click(),即调用OnClick事件的用户代码
inherited Click;
end;
按钮被按下后,这段程序会首先得到执行,最后的那行在对TControl.Click()的调用中,才会执行Delphi程序员为该按钮定义的OnClick事件的代码。
1.模式窗体
type
TFormScroll = class(TForm)
var
//声明一个窗体类型的变量
FormScroll: TFormScroll;
begin
// default value
Result := Col;
try
FormScroll := TFormScroll.Create (Application);//创建窗体
try
// initialize the data
FormScroll.SelectedColor := Col;
// show the form 显示这个窗体
if FormScroll.ShowModal = mrOK then
Result := FormScroll.SelectedColor;
finally
FormScroll.Free;
end;
except
on E: Exception do
MessageDlg ('Error in FormDLL: ' +
E.Message, mtError, [mbOK], 0);
end;
end;
function TCustomForm.ShowModal: Integer;
var
WindowList: Pointer;
SaveFocusCount: Integer;
SaveCursor: TCursor;
SaveCount: Integer;
ActiveWindow: HWnd;
begin
CancelDrag;
if Visible or not Enabled or (fsModal in FFormState) or
(FormStyle = fsMDIChild) then
raise EInvalidOperation.Create(SCannotShowModal);
if GetCapture <> 0 then SendMessage(GetCapture, WM_CANCELMODE, 0, 0);
ReleaseCapture;
Include(FFormState, fsModal);
ActiveWindow := GetActiveWindow;
SaveFocusCount := FocusCount;
Screen.FSaveFocusedList.Insert(0, Screen.FFocusedForm);
Screen.FFocusedForm := Self;
SaveCursor := Screen.Cursor;
Screen.Cursor := crDefault;
SaveCount := Screen.FCursorCount;
WindowList := DisableTaskWindows(0);
try
Show;
try
SendMessage(Handle, CM_ACTIVATE, 0, 0);
ModalResult := 0;
repeat
Application.HandleMessage;
if Application.FTerminate then ModalResult := mrCancel else
if ModalResult <> 0 then CloseModal;
until ModalResult <> 0;
Result := ModalResult;
SendMessage(Handle, CM_DEACTIVATE, 0, 0);
if GetActiveWindow <> Handle then ActiveWindow := 0;
finally
Hide;
end;
finally
if Screen.FCursorCount = SaveCount then
Screen.Cursor := SaveCursor
else Screen.Cursor := crDefault;
EnableTaskWindows(WindowList);
if Screen.FSaveFocusedList.Count > 0 then
begin
Screen.FFocusedForm := Screen.FSaveFocusedList.First;
Screen.FSaveFocusedList.Remove(Screen.FFocusedForm);
end else Screen.FFocusedForm := nil;
if ActiveWindow <> 0 then SetActiveWindow(ActiveWindow);
FocusCount := SaveFocusCount;
Exclude(FFormState, fsModal);
end;
end;
2.非模式窗体
var
FormScroll: TFormScroll;
begin
FormScroll := TFormScroll.Create (Application); //创建窗体
try
// initialize the data
FormScroll.FormHandle := FormHandle;
FormScroll.MsgBack := MsgBack;
FormScroll.SelectedColor := Col;
// show the form 显示非模式窗体
FormScroll.Show;
except
on E: Exception do
begin
MessageDlg ('Error in FormDLL: ' +
E.Message, mtError, [mbOK], 0);
FormScroll.Free;
end;
end;
end;
procedure TCustomForm.Show;
begin
Visible := True;
BringToFront;
end;