下面为Delphi中,方法TCustomForm.ShowModal的代码,通过分析以下代码,可以了解ShowModal到底是怎么一回事!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
function TCustomForm.ShowModal: Integer;
var
WindowList: TTaskWindowList;
LSaveFocusState: TFocusState;
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;
Application.ModalStarted;
try
{ RecreateWnd could change the active window }
ActiveWindow := GetActiveWindow;
Include(FFormState, fsModal);
if (PopupMode = pmNone) and (Application.ModalPopupMode <> pmNone) then
begin
RecreateWnd;
HandleNeeded;
{ The active window might have become invalid, refresh it }
if (ActiveWindow = 0) or not IsWindow(ActiveWindow) then
ActiveWindow := GetActiveWindow;
end;
LSaveFocusState := SaveFocusState;
Screen.SaveFocusedList.Insert(0, Screen.FocusedForm);
Screen.FocusedForm := Self;
SaveCursor := Screen.Cursor;
Screen.Cursor := crDefault;
SaveCount := Screen.CursorCount;
WindowList := DisableTaskWindows(0);
try
Show;
try
SendMessage(Handle, CM_ACTIVATE, 0, 0);
ModalResult := 0;
repeat
Application.HandleMessage;
if Application.Terminated 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.CursorCount = SaveCount then
Screen.Cursor := SaveCursor
else Screen.Cursor := crDefault;
EnableTaskWindows(WindowList);
if Screen.SaveFocusedList.Count > 0 then
begin
Screen.FocusedForm := TCustomForm(Screen.SaveFocusedList.First);
Screen.SaveFocusedList.Remove(Screen.FocusedForm);
end else Screen.FocusedForm := nil;
{ ActiveWindow might have been destroyed and using it as active window will
force Windows to activate another application }
if (ActiveWindow <> 0) and not IsWindow(ActiveWindow) then
ActiveWindow := FindTopMostWindow(0);
if ActiveWindow <> 0 then
SetActiveWindow(ActiveWindow);
RestoreFocusState(LSaveFocusState);
Exclude(FFormState, fsModal);
end;
finally
Application.ModalFinished;
end;
|
集中精力看这代码:
1
2
3
4
5
|
repeat
Application.HandleMessage;
if Application.Terminated then ModalResult := mrCancel else
if ModalResult <> 0 then CloseModal;
until ModalResult <> 0;
|
众所周知,Windows是一个消息驱动的系统,一个窗口总是不断地在获取消息,处理消息这样的一个大循环中,以实时响应我们的操作。而上面这段代码,就是模拟了这样的一种过程,不断地去处理消息,判断程序是否退出,ModalResult是否为特定的值,如果是,则退出这个简单的消息。这段循环代码就保证了只有这代码代码执行完毕,才会在上一层代码中继续往下执行。
代码中通过
1
|
WindowList := DisableTaskWindows(
0
);
|
来禁止当前应用程序的其他窗口鼠标与键盘输入,通过
1
|
EnableTaskWindows(WindowList);
|
来激活其他窗口允许鼠标与键盘输入
Following listed the code of TCustomForm.ShowModal of Delphi, by analysis the source code, we can know how it works.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
function TCustomForm.ShowModal: Integer;
var
WindowList: TTaskWindowList;
LSaveFocusState: TFocusState;
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;
Application.ModalStarted;
try
{ RecreateWnd could change the active window }
ActiveWindow := GetActiveWindow;
Include(FFormState, fsModal);
if (PopupMode = pmNone) and (Application.ModalPopupMode <> pmNone) then
begin
RecreateWnd;
HandleNeeded;
{ The active window might have become invalid, refresh it }
if (ActiveWindow = 0) or not IsWindow(ActiveWindow) then
ActiveWindow := GetActiveWindow;
end;
LSaveFocusState := SaveFocusState;
Screen.SaveFocusedList.Insert(0, Screen.FocusedForm);
Screen.FocusedForm := Self;
SaveCursor := Screen.Cursor;
Screen.Cursor := crDefault;
SaveCount := Screen.CursorCount;
WindowList := DisableTaskWindows(0);
try
Show;
try
SendMessage(Handle, CM_ACTIVATE, 0, 0);
ModalResult := 0;
repeat
Application.HandleMessage;
if Application.Terminated 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.CursorCount = SaveCount then
Screen.Cursor := SaveCursor
else Screen.Cursor := crDefault;
EnableTaskWindows(WindowList);
if Screen.SaveFocusedList.Count > 0 then
begin
Screen.FocusedForm := TCustomForm(Screen.SaveFocusedList.First);
Screen.SaveFocusedList.Remove(Screen.FocusedForm);
end else Screen.FocusedForm := nil;
{ ActiveWindow might have been destroyed and using it as active window will
force Windows to activate another application }
if (ActiveWindow <> 0) and not IsWindow(ActiveWindow) then
ActiveWindow := FindTopMostWindow(0);
if ActiveWindow <> 0 then
SetActiveWindow(ActiveWindow);
RestoreFocusState(LSaveFocusState);
Exclude(FFormState, fsModal);
end;
finally
Application.ModalFinished;
end;
|
Focus on the following code:
1
2
3
4
5
|
repeat
Application.HandleMessage;
if Application.Terminated then ModalResult := mrCancel else
if ModalResult <> 0 then CloseModal;
until ModalResult <> 0;
|
As we all know that, windows is a message based operation system. A window is always in the circle of get message, handle message, in order to response to our actions, but the up code had simulate this situation: the code by using repeat to circle handle messages by calling the Application.HandleMessage method, and then check whether the application is terminated or ModalResult property of the TCustomForm have reached the indicated condition. This block of code have made it possible that the higher layer code could not be executed until showModal have finished.
In the code of TCustomForm.ShowModal, it disable all windows from mouse and keyboard input in the process by calling the DisableTaskWindows function which returns a pointer called TTaskWindowList.
1
|
WindowList := DisableTaskWindows(
0
);
|
and enable it by calling the following code
1
|
EnableTaskWindows(WindowList);
|
下面为Delphi中,方法TCustomForm.ShowModal的代码,通过分析以下代码,可以了解ShowModal到底是怎么一回事!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
function TCustomForm.ShowModal: Integer;
var
WindowList: TTaskWindowList;
LSaveFocusState: TFocusState;
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;
Application.ModalStarted;
try
{ RecreateWnd could change the active window }
ActiveWindow := GetActiveWindow;
Include(FFormState, fsModal);
if (PopupMode = pmNone) and (Application.ModalPopupMode <> pmNone) then
begin
RecreateWnd;
HandleNeeded;
{ The active window might have become invalid, refresh it }
if (ActiveWindow = 0) or not IsWindow(ActiveWindow) then
ActiveWindow := GetActiveWindow;
end;
LSaveFocusState := SaveFocusState;
Screen.SaveFocusedList.Insert(0, Screen.FocusedForm);
Screen.FocusedForm := Self;
SaveCursor := Screen.Cursor;
Screen.Cursor := crDefault;
SaveCount := Screen.CursorCount;
WindowList := DisableTaskWindows(0);
try
Show;
try
SendMessage(Handle, CM_ACTIVATE, 0, 0);
ModalResult := 0;
repeat
Application.HandleMessage;
if Application.Terminated 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.CursorCount = SaveCount then
Screen.Cursor := SaveCursor
else Screen.Cursor := crDefault;
EnableTaskWindows(WindowList);
if Screen.SaveFocusedList.Count > 0 then
begin
Screen.FocusedForm := TCustomForm(Screen.SaveFocusedList.First);
Screen.SaveFocusedList.Remove(Screen.FocusedForm);
end else Screen.FocusedForm := nil;
{ ActiveWindow might have been destroyed and using it as active window will
force Windows to activate another application }
if (ActiveWindow <> 0) and not IsWindow(ActiveWindow) then
ActiveWindow := FindTopMostWindow(0);
if ActiveWindow <> 0 then
SetActiveWindow(ActiveWindow);
RestoreFocusState(LSaveFocusState);
Exclude(FFormState, fsModal);
end;
finally
Application.ModalFinished;
end;
|
集中精力看这代码:
1
2
3
4
5
|
repeat
Application.HandleMessage;
if Application.Terminated then ModalResult := mrCancel else
if ModalResult <> 0 then CloseModal;
until ModalResult <> 0;
|
众所周知,Windows是一个消息驱动的系统,一个窗口总是不断地在获取消息,处理消息这样的一个大循环中,以实时响应我们的操作。而上面这段代码,就是模拟了这样的一种过程,不断地去处理消息,判断程序是否退出,ModalResult是否为特定的值,如果是,则退出这个简单的消息。这段循环代码就保证了只有这代码代码执行完毕,才会在上一层代码中继续往下执行。
代码中通过
1
|
WindowList := DisableTaskWindows(
0
);
|
来禁止当前应用程序的其他窗口鼠标与键盘输入,通过
1
|
EnableTaskWindows(WindowList);
|
来激活其他窗口允许鼠标与键盘输入
- See more at: http://www.neugls.info/delphi-showmodal-%e4%bb%a3%e7%a0%81%e5%88%86%e6%9e%90/#sthash.e9PphVDW.dpuf
参考:
http://www.neugls.info/delphi-showmodal-%E4%BB%A3%E7%A0%81%E5%88%86%E6%9E%90/