什么是模态窗口?本文带你了解模态窗口的本质
做 Windows 桌面应用开发的小伙伴们对“模态窗口”(Modal Dialog)一定不陌生。如果你希望在模态窗口之上做更多的事情,或者自己实现一套模态窗口类似的机制,那么你可能需要了解模态窗口的本质。
本文不会太深,只是从模态窗口一词出发,抵达大家都熟知的一些知识为止。
本文内容
- 开发中的模态窗口
- 模态窗口的三个特点
- 实现模态窗口
- API 调用
- 禁用主窗口
- 阻塞代码等待操作完成
- 进行 UI 强提醒
开发中的模态窗口
在各种系统、语言和框架中,只要有用户可以看见的界面,都存在模态窗口的概念。从交互层面来说,它的形式是在保留主界面作为环境来显示的情况下,打开一个新的界面,用户只能在新的界面上操作,完成或取消后才能返回主界面。从作用上来说,通常是要求用户必须提供某些信息后才能继续操作,或者单纯只是为了广告。
模态窗口的三个特点
如果你希望自己搞一套模态窗口出来,那么只需要满足这三点即可。你可以随便加戏但那都无关紧要。
- 保留主界面显示的同时,禁用主界面的用户交互;
- 显示子界面,主界面在子界面操作完成后返回;
- 当用户试图跳过子界面的交互的时候进行强提醒。
拿 Windows 系统中的模态对话框为例子,大概就像下面这两张图片这样:
有一个小的子界面盖住了主界面,要求用户必须进行选择。Windows 系统设置因为让背景变暗了,所以用户肯定会看得到需要进行的交互;而任务管理器没有让主界面变暗,所以用户在操作子界面的时候,模态窗口的边框和标题栏闪烁以提醒用户注意。
实现模态窗口
对于 Windows 操作系统来说,模态窗口并不是一个单一的概念,你并不能仅通过一个 API 调用就完成显示模态窗口,你需要在不同的时机调用不同的 API 来完成一个模态窗口。如果要完整实现一个自己的模态窗口,则需要编写实现以上三个特点的代码。
当然,你可能会发现实际上你显示一个模态窗口仅仅一句话调用就够了,那是因为你所用的应用程序框架帮你完成了模态窗口的一系列机制。
关于 WPF 框架是如何实现模态窗口的,可以阅读:直击本质:WPF 框架是如何实现模态窗口的
关于如何自己实现一个跨越线程/进程边界的模态窗口,可以阅读:实现 Windows 系统上跨进程/跨线程的模态窗口
如果你希望定制以上第三个特点中强提醒的动画效果,可以阅读:WPF window 子窗口反馈效果(抖动/阴影渐变) - 唐宋元明清2188 - 博客园。
API 调用
为了在 Windows 上实现模态窗口,需要一些 Win32 API 调用(当然,框架够用的话直接用框架就好)。
禁用主窗口
我们需要使用到 BOOL EnableWindow(HWND hWnd, BOOL bEnable);
来启用与禁用某个窗口。
EnableWindow(hWnd, false);
try
{// 模态显示一个窗口。
}
finally
{EnableWindow(hWnd, true);
}
[DllImport("user32")]
private static extern bool EnableWindow(IntPtr hwnd, bool bEnable);
阻塞代码等待操作完成
因为 async
/await
的出现,阻塞其实可以使用 await
来实现。虽然这不是真正的阻塞,但可以真实反应出“异步”这个过程,也就是虽然这里在等待,但实际上依然能够继续在同一个线程响应用户的操作。
UWP 中的新 API 当然已经都是使用 async
/await
来实现模态等待了,不过 WPF/Windows Forms 比较早,只能使用 Dispatcher 线程模型来实现模态等待。
于是我们可以考虑直接使用现成的 Dispatcher 线程模型来完成等待,方法是调用下面两个当中的任何一个:
Window.ShowDialog
也就是直接使用窗口原生的模态Dispatcher.PushFrame
新开一个消息循环以阻塞当前代码的同时继续响应 UI 交互
上面 Window.ShowDialog
的本质也是在调用 Dispatcher.PushFrame
,详见:
- 直击本质:WPF 框架是如何实现模态窗口的
关于 PushFrame
新开消息循环阻塞的原理可以参考:
- 深入了解 WPF Dispatcher 的工作原理(PushFrame 部分) - walterlv
当然,还有其他可以新开消息循环的方法。
进行 UI 强提醒
由于我们一开始禁用了主窗口,所以如果用户试图操作主窗口是不会有效果的。然而如果用户不知道当前显示了一个模态窗口需要操作,那么给出提醒也是必要的。
简单的在 UI 上的提醒是最简单的了,比如:
- 将主界面变暗(UWP 应用,Web 应用喜欢这么做)
- 将主界面变模糊(iOS 应用喜欢这么做)
- 在模态窗口上增加一个很厚重的阴影(Android 应用喜欢这么做)
然而 Windows 和 Mac OS 这些古老的系统由于兼容性负担不能随便那么改,于是需要有其他的提醒方式。
Windows 采用的方式是让标题栏闪烁,让阴影闪烁。
而这些特效的处理,来自于子窗口需要处理一些特定的消息 WM_SETCURSOR
。
详见:WPF window 子窗口反馈效果(抖动/阴影渐变) - 唐宋元明清2188 - 博客园
通常你不需要手工处理这些消息,但是如果你完全定制了窗口样式,则可能需要自行做一个这样的模态窗口提醒效果。
我的博客会首发于 https://blog.walterlv.com/,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。
如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。
什么是模态窗口?本文带你了解模态窗口的本质相关推荐
- 微信小程序之自定义模态弹窗(带动画)实例
代码地址如下: http://www.demodashi.com/demo/13991.html 一.前期准备工作 软件环境:微信开发者工具 官方下载地址:https://mp.weixin.qq.c ...
- 浮动窗口代码(带关闭按钮+全屏漂浮)
<html> <head> <meta http-equiv="Content-Type" content="text/html; char ...
- 六元均匀直线阵的各元间距为_小间距led显示屏的封装方式有哪些?本文带你了解!...
小间距LED显示屏产品(一般市场定义为点间距不大于2.5mm)因稳定性.可靠性.耐久性及易维护性开启了各类指挥调度中心的新时代,并不断满足其他中高端应用场景精细化.个性化的产品需求.而对于这些LED小 ...
- WPF 让窗口激活作为前台最上层窗口的方法
在 WPF 中,如果想要使用代码控制,让某个窗口作为当前用户的输入的逻辑焦点的窗口,也就是在当前用户活动的窗口的最上层窗口,默认使用 Activate 方法,通过这个方法在大部分设备都可以做到激活窗口 ...
- html弹窗赋值给查询框,bootstrap模态框动态赋值, ajax异步请求数据后给id为queryInfo的模态框赋值并弹出模态框(JS)...
/查询单个 function query(id) { $.ajax({ url : "/small/productServlet", async : true, type : &q ...
- python PyQt5中文教程☞【第二节】PyQt5基本功能(创建窗口、应用程序图标、显示提示语、通过按钮关闭窗口、消息框(关闭窗口确认框)、窗口显示在屏幕中间【居中显示】)
引用文章:http://code.py40.com/pyqt5/ 文章目录 简单的例子:创建一个小窗口 应用程序的图标 显示提示语 通过按钮关闭窗口 消息框(关闭窗口确认框) 窗口显示在屏幕的中间[居 ...
- pyqt 子窗口控制主窗口绘图_实战PyQt5: 005-主窗口QMainWindow
QMainWindow简介 在桌面应用中,一个应用软件通常都会包含一个主窗口,主窗口是承载所有控件的窗体, 在PyQt5中常用的主窗体有两种QMainWindow和QDialog,他们也都继承自QWi ...
- Android窗口管理服务WindowManagerService切换Activity窗口(App Transition)的过程分析
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8596449 在Android系统中,同一时刻只 ...
- 3点 刚体运动 opencv_模态法动力学分析中的刚体模态
01 - 概述 在对汽车结构进行动力学有限元分析时,无论是瞬态问题还是频响问题,都经常使用模态叠加法. 模态叠加法动力学分析是常规模态分析的自然扩展,它利用结构振型来缩减问题求解规模,从而使数值求解更 ...
- qt如何把父窗口的变量传给子窗口_父窗口和iframe子窗口之间相互传递参数和调用函数或方法...
1.父窗口向子窗口传递参数: 可以在url中添加参数:2.html?a=1&b=2&c=3 然后在子页面上可用js解析,提供一个函数: function getQueryStr(sAr ...
最新文章
- prometheus--初见
- 怎么计算一个对象占用的内存
- intellij IDEA怎样打war包
- 切换不了摄像头 高拍仪_手机摄像头模组支架保护膜的变革之路
- UA OPTI501 电磁波4 电介质及其极化
- keras、tf、numpy实现logloss对比
- BDS-HA:构建高可用、低延迟的HBase服务
- 你家的饮水机,到底可以有多脏?
- 用条件运算符编写java程序_Java 编程入门课程丨第 8 单元:条件运算符和控制语句...
- iOS开发Item属性总结
- 《孙子兵法》【火攻第十二】
- 项目的权限设计的小计
- Django-开胃菜
- Mycat-server-1.6.5 常见分片方式
- 复制slave-skip-errors及error查看
- 【滤波器】基于matlab GUI分数延迟滤波器设计【含Matlab源码 1347期】
- 案例解读|江苏银行—智多星大数据分析云平台实践
- 短信API接口比较常见的回调状态
- double比较大小
- iPhone屏幕适配 新增iPhone XS iPhone XR iPhone XS Max
热门文章
- zabbix 报警	Lack of free swap space on Zabbix server 处理
- 【Python】【pygame】更逼真的星星、连绵细雨
- 计算机的经历和灵感,从电脑编程灵感中得到的启发
- 2017-11-18 借白银说点市场心得
- python 插值求包络线
- 经历“海潮效应”,云图如何成为智能家居界的苹果?
- wireshark抓包分析IP数据报
- 红杉资本合伙人Maguire:Crypto将是未来30年最大趋势 |链捕手
- 怎么样用计算机弹出小星星,【钢琴入门自写教程 1】小星星弹奏
- Atom-beautify插件的安装,使用过程