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

ShowModal 代码分析的更多相关文章

  1. Android代码分析工具lint学习

    1 lint简介 1.1 概述 lint是随Android SDK自带的一个静态代码分析工具.它用来对Android工程的源文件进行检查,找出在正确性.安全.性能.可使用性.可访问性及国际化等方面可能 ...

  2. pmd静态代码分析

    在正式进入测试之前,进行一定的静态代码分析及code review对代码质量及系统提高是有帮助的,以上为数据证明 Pmd 它是一个基于静态规则集的Java源码分析器,它可以识别出潜在的如下问题:– 可 ...

  3. [Asp.net 5] DependencyInjection项目代码分析-目录

    微软DI文章系列如下所示: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Autofac [ ...

  4. [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(5)(IEnumerable<>补充)

    Asp.net 5的依赖注入注入系列可以参考链接: [Asp.net 5] DependencyInjection项目代码分析-目录 我们在之前讲微软的实现时,对于OpenIEnumerableSer ...

  5. 完整全面的Java资源库(包括构建、操作、代码分析、编译器、数据库、社区等等)

    构建 这里搜集了用来构建应用程序的工具. Apache Maven:Maven使用声明进行构建并进行依赖管理,偏向于使用约定而不是配置进行构建.Maven优于Apache Ant.后者采用了一种过程化 ...

  6. STM32启动代码分析 IAR 比较好

    stm32启动代码分析 (2012-06-12 09:43:31) 转载▼     最近开始使用ST的stm32w108芯片(也是一款zigbee芯片).开始看他的启动代码看的晕晕呼呼呼的. 还好在c ...

  7. 常用 Java 静态代码分析工具的分析与比较

    常用 Java 静态代码分析工具的分析与比较 简介: 本文首先介绍了静态代码分析的基 本概念及主要技术,随后分别介绍了现有 4 种主流 Java 静态代码分析工具 (Checkstyle,FindBu ...

  8. SonarQube-5.6.3 代码分析平台搭建使用

    python代码分析 官网主页: http://docs.sonarqube.org/display/PLUG/Python+Plugin Windows下安装使用: 快速使用: 1.下载jdk ht ...

  9. angular代码分析之异常日志设计

    angular代码分析之异常日志设计 错误异常是面向对象开发中的记录提示程序执行问题的一种重要机制,在程序执行发生问题的条件下,异常会在中断程序执行,同时会沿着代码的执行路径一步一步的向上抛出异常,最 ...

随机推荐

  1. EffectiveJava(19)导出常量的几种方式 - - 接口只用于定义类型

    package com.classinteface.finalinterface; /** * 常量接口模式 java.io.ObjectStreamConstants * 这种模式会导致实现其的类将 ...

  2. Android官方SwipeRefreshLayout

    App基本都有下拉刷新的功能,以前基本都使用PullToRefresh或者自己写一个下拉刷新,Google提供了一个官方的下拉刷新控件SwipeRefreshLayout,简单高效,满足一般需求足够了 ...

  3. Cygwin-安装和配置ssh服务

    Cygwin介绍: Cygwin是一个在windows平台上执行的类UNIX模拟环境.它对于学习UNIX/Linux操作环境,或者从UNIX到Windows的应用程序移植,或者进行某些特殊的开发工作, ...

  4. Execution failed for task ':app:transformClassesAndResourcesWithProguardForRelease'.

    1.Execution failed for task ':app:transformClassesAndResourcesWithProguardForRelease'. 原因解析: gradle ...

  5. JavaScript 转换小技巧

    1.变量转换 看起来很简单,但据我所看到的,使用构造函数,像Array()或者Number()来进行变量转换是常用的做法.始终使用原始数据类型(有时也称为字面量)来转换变量,这种没有任何额外的影响的做 ...

  6. SQL - 获取多机构最近相同节点

    -- Create Branches Table create table Branches ( BranchCode ) ,BranchName ) ,L0BCode ) ,L1BCode ) ,L ...

  7. 网络爬虫与搜索引擎优化(SEO)

    一.网络爬虫 网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本.另外一些不常使用的名字还有蚂蚁.自动索引. ...

  8. UUID(即GUID)

    UUID(GUID)是Cocoa Touch提供的一种生成唯一标识的机制.类型为CFUUIDRef的对象可以代表UUID,UUID是基于当前时间.计数器和硬件标识(通常是以太网卡的MAC地址)等数据计 ...

  9. hdu 4601 Letter Tree

    不easy啊.. 一个小错误让我wa死了.找了一个晚上,怎么都找不到 最后是对拍代码找到的错误.发现当步数比較小的时候答案就是对的,比較大的时候就不正确了 想到一定是什么地方越界了.. . power ...

  10. 使用jstl标签报错:According to TLD or attribute directive in tag file, attribute value

    原来jstl标签版本不一样,标签支持不一样. jstl1.0标签库不支持表达式,如: <c:if test="${query01 == null}">   <js ...