ShowModal 代码分析

下面为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/

你可能感兴趣的:(show)