• 【温故Delphi】之窗口ShowModal


    问题描述

      昨天同事修改一个bug,请我审查代码时我发现这个bug很有意思,值得深入研究一下。

      问题是这样的,弹出一个模态窗口后,在窗口内切换树节点,发现主窗口也可以接受鼠标和键盘消息了——模态窗口不模态了

      跟踪发现,在窗口内切换树节点会间接调用到进度条窗口(我们自己写的一个窗口),ShowProgress时会调用Application.MainForm.Enabled := False,HideProgress是会调用Application.MainForm.Enabled := True,问题就出现在这个地方。

    ShowModal实现

    TCustomForm.ShowModal
    begin
      //... 
      WindowList := DisableTaskWindows(0); 
      Show;
      SendMessage(Handle, CM_ACTIVATE, 0, 0);
      repeat
        Application.HandleMessage;
        if Application.Terminated then ModalResult := mrCancel else
        if ModalResult <> 0 then CloseModal;
      until ModalResult <> 0;
      //...
    end;
    DisableTaskWindows
    begin
      //... 
      EnumThreadWindows(GetCurrentThreadID, @DoDisableWindow, 0); 
      //...
    end
    DoDisableWindow
    begin
      //...
      EnableWindow(Window, False);  
      //...
    end

      ShowModal的实际上只让模态接收键盘和鼠标信息,而禁止其他的窗口接收键盘和鼠标消息,这是通过调用EnableWindow这个Windows API实现的。

    SetEnabled实现

    TControl.SetEnabled 
    begin
      //...
      Perform(CM_ENABLEDCHANGED, 0, 0)
      //...
    end
    TWinControl.CMEnabledChanged
    begin 
      //...
      EnableWindow(FHandle, Enabled) 
      //...
    end

      当调用Application.MainForm.Enabled := True时就会使得MainForm的可以接收消息了,之前的模态窗口就不再模态了。

      修改bug的方法:判断Application.ModalLevel > 0是否为真,为真的时候就不在做上述调用。

    Windows API

    1、EnableWindow:该函数允许/禁止指定的窗口或控件接受鼠标和键盘的输入,当输入被禁止时,窗口不响应鼠标和按键的输入,输入允许时,窗口接受所有的输入。

    2、IsWindowEnabled:用于判断指定的窗口是否允许接受键盘或鼠标输入。

    3、EnumThreadWindows枚举所有与一个线程相关联的非子窗口,办法是先将句柄传送给每一个窗口,随后传送给应用程序定义的回调函数。EnumThreadWindows函数继续直到所有窗口枚举完为止或回调函数返回FALSE为止。

    VCL:DisableTaskWindows:{ EnumThreadWindows(GetCurrentThreadID, @DoDisableWindow, 0); } //DoDisableWindow为回调函数

    反思

    1、遇到问题后要深入了解其内在过程,知其所以然;

    2、不断总结,博客化;

  • 相关阅读:
    Ubuntu下systemd服务的配置
    编译压缩代码 MFCompress-src-1.01 :对‘***’未定义的引用
    德尔福 基础
    德尔福 XE5 安卓权限设置
    德尔福 XE5 安卓调试
    复制任意文件或文件夹到剪贴板
    无法完成安装:'Cannot access storage file '/
    Centos7.4安装kvm虚拟机(使用virt-manager管理)
    MSYS2 使用
    线程
  • 原文地址:https://www.cnblogs.com/liustdelphi/p/2848605.html
Copyright © 2020-2023  润新知