• 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/

  • 相关阅读:
    18.06.30 POJ 2488:A Knight's Journey
    18.06.27 POJ 3414:Pots
    18.06.27 15年期末Stupid cat & Doge
    18.06.27 水题整理(3)--1st 上机
    18.6.27 水题整理(2)--2nd 上机
    18.6.27 一些没放上来的水题整理(1)--3rd 上机
    18.06.27 POJ NOI 7217猴子吃桃
    18.06.27 POJ NOI 4977怪盗基德的滑翔翼
    18.06.27 POJ百练 4124海贼王之伟大航路
    18.06.27 POJ1054 The Troublesome Frog
  • 原文地址:https://www.cnblogs.com/findumars/p/3493650.html
Copyright © 2020-2023  润新知