百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

2.1.3-4窗口消息 窗口消息处理函数

liebian365 2024-10-26 12:59 21 浏览 0 评论

2.1.3 窗口

Windows窗口是用来和用户进行交互信息的,可以在窗口中输入信息,也可以在窗口中输出信息。这些信息包括文本、图形、动画等等。对比控制台黑窗口,Windows窗口可以输入和输出的信息要丰富的多。

自定义窗口

窗口就是对象,作为程序员来说,就是一块内存。这块内存中通常包含一个标题栏、一个菜单栏、一个工具栏和一个滚动条等其他小的对象(更小的一块内存)。通常我们会使用窗口对象的句柄对窗口进行操作。

如果我们要创建一个窗口,需要告诉Windows系统一些明确的信息:

typedef struct tagWNDCLASSA {

UINT style; //创建一个什么样风格的窗口

WNDPROC lpfnWndProc; //由谁来负责处理窗口的消息—窗口过程

int cbClsExtra; //要根据窗口类结构分配的额外字节数

int cbWndExtra; //在窗口实例之后分配的额外字节数

HINSTANCE hInstance; //窗口所属的进程

HICON hIcon; //窗口的图标

HCURSOR hCursor; //窗口的鼠标

HBRUSH hbrBackground; //窗口的背景颜色

LPCSTR lpszMenuName; //窗口所包含的菜单

LPCSTR lpszClassName; //窗口类名(等同于进程名)

} WNDCLASSA, *PWNDCLASSA, *NPWNDCLASSA, *LPWNDCLASSA;

显然,将创建窗口的所有信息组合到一起就是一个结构体。细心的读者可能会发现,创建窗口的信息还应该包含窗口的尺寸。这是一定需要的,我们将在下一节中使用示例代码来说明。

预定义对话框窗口

Windows还预定义另一种窗口,可以不带标题栏,而是包含各种各样的控件,例如按钮、列表框、滚动条和文本框等。

对话框窗口可以分为:

●模态对话框:当程序显示一个模态对话框时,用户不能在对话框和该程序的其他窗口之间进行切换。用户必须先明确地终止该对话框。这通常由单击OK或Cancel按钮来实现。但是当对话框正在显示时,用户可以切换到其他的程序。有些对话框(所谓“系统模态”)则连这种切换都不允许。在Windows 中,用户必须先结束系统模态对话框才可以进行其他操作。典型的默认对话框就是MessageBox框了。

●非模态对话框:非模态对话框允许用户在对话框和窗口之间,以及在对话框和其他程序之间进行切换。非模态对话框因此更接近于程序自定义的正常弹出窗口。如果在一段时间内,一直要显示某个对话框,用户更倾向于使用非模态对话框,因为它更方便。典型的非模态对话框如查找和替换对话框。

●公用对话框:为了方便用户快速熟悉和使用Windows应用程序,从Windows 3.1开始,提供了统一标准的“公用对话框库”(common dialogue box library)。这个库包括了一些函数,可以用来激活打开和存储文件、查找和替换、选择颜色、选择字体(所有这些将在本书第十一章中演示)以及打印(将在第十三章中演示)的对话框。

预定义子窗口控件

子窗口控件也是一种窗口,也是Windows预定义的窗口类型。虽然我们也可以自定义子窗口控件,但是直接使用Windows提供的标准子窗口控件更为方便快捷。Windows预定义了子窗口控件的窗口类和窗口过程,并且提供多种不同风格的子窗口样试供我们选择。常用的子窗口控件包括按钮类的BUTTON控件、静态文本控件、滚动条控件、文本编辑控件和列表框控件。我们将在第八章详细讲解子窗口控件。

2.1.4 消息

Windows操作系统是一种消息驱动的系统,这句话应该被每一位从事Windows程序设计的开发人员所熟知。那么什么是消息呢?也许有很多已经从事多年Windows程序开发的程序员都无法说清楚。这是因为他们并不清楚消息传递的实现过程。

消息的本质

消息其实非常简单,就是函数调用时传递的参数,仅此而已。只不过我们并不能从代码中真实的感受到消息传递的整个过程,所以会觉得不可琢磨。Windows操作系统中有很多很多消息,这些消息可以是键盘消息、鼠标消息、滚动条消息、字符消息、绘图消息、控件消息、菜单消息或者是系统消息等等。键盘消息和鼠标消息肯定是由用户操作键盘和鼠标产生的,这是人机交互的需要。其他消息又是如何产生的呢?如果我们把消息看作是参数,那么这些消息肯定是在调用函数调用传递参数时产生的,消息本身就是参数。例如绘图时,我们将绘图消息WM_PAINT作为实参传递给GDI绘图函数。不论什么样的消息都是由操作系统捕捉并分发的。API函数的调用和执行也是由Windows操作系统实现的,这些都是潜藏在水面以下的冰山。正是因为我们看不见,所以才会感到困惑。

既然消息就是一个参数,我们来了解一下消息本身:

typedef struct tagMSG {

HWND hwnd; //接收消息的窗口的句柄

UINT message; //指定消息类型-消息ID,例如 WM_PAINT、WM_CLOSE等。

WPARAM wParam; //针对特定消息的附加信息

LPARAM lParam; //详细的附加信息,通常与wParam一起配合使用

DWORD time; //消息发布的时间

POINT pt; //鼠标在发布消息的时候在屏幕上的位置(鼠标消息特性)

DWORD lPrivate; //仅在某些消息类型中使用,其他情况下是保留项

} MSG, *PMSG, *NPMSG, *LPMSG;

我们用一个结构体来描述消息,显然消息是一个对象(Windows系统处处是对象)。消息结构体中包含7个成员,我们只需要关系前面四个成员,后面三个成员仅提供给操作系统使用。

hwnd:接收消息的窗口的句柄,所有的消息都是发送给指定窗口的。

message:指定消息类型-消息ID,Windows系统使用一个32位无符号整数标识消息。

wParam 和lParam:针对特定消息的附加信息。仅有一个消息ID远远不够的,还需要借助于32位的wParam 和32位的lParam传递具体的信息。

我们在Windows程序中通常会将上述四个成员作为参数传递。

举例

例如发送一个消息:

LRESULT SendMessage(

[in] HWND hWnd, //接收消息的窗口句柄

[in] UINT Msg, //消息ID

[in] WPARAM wParam, //附加参数,其他的消息特定信息

[in] LPARAM lParam //附加参数,其他的消息特定信息

);

很显然,这里的消息就是参数。在Windows系统内部产生和传递消息也是如此。

Windows系统中的消息虽然非常多,但是绝大多数消息都是由Windows系统按照默认方式处理的,不需要我们劳心费力,目的当然是不想为难我们这些开发者了。

窗口过程

在Winodws程序中,我们需要写一个函数来处理各种消息,这个函数称为窗口过程。它是一个回调函数。正常情况下,在Windows程序中是由我们来调用操作系统的API函数,回调的意思是由操作系统反过来调用我们写的窗口过程来处理消息。窗口过程只需要处理我们关心的一小部分消息,绝大多数消息都是交给默认的Windows系统的窗口过程来处理。本书的学习过程也就是学习各种各样消息处理的过程。

队列消息

Windows操作系统的消息可以分为队列消息和非队列消息。Windows操作系统中有一个总消息队列,所有进程的队列消息都会被送入总消息队列中。然后再根据消息所属的窗口,将消息分发到各个窗口队列。还记得消息结构的第一个成员就是接收消息的窗口。以此判断该消息属于哪个窗口。

什么样的消息属于队列消息呢?鼠标消息、键盘消息肯定是属于队列消息,一定会被送入消息队列。这是由于用户通过鼠标、键盘与窗口进行交互产生的消息,而用户的操作是有先后顺序的,因此需要使用队列进行同步操作。因此可以认为,凡是与窗口进行交互或需要保持同步操作的消息都是队列消息,一定会被送上消息队列。队列消息都是调用PostMessage函数将消息送入指定窗口的消息队列。

BOOL PostMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

消息队列存在于线程中,理论上每个线程都可以创建一个消息队列。

假如一个Windows进程只有一个主线程,那么非常简单,所有的窗口消息都是送入主线程的消息队列。

假如一个Windows进程同时拥有多个线程,其中只有一个主线程负责处理窗口消息,其它线程执行其他任务。意思是在多线程的Windows程序中,同样只有一个消息队列,所有消息都交给主线程处理,不存在多个线程间的冲突问题。因此,虽然窗口是不包含消息队列的,但是我们将线程消息队列称为窗口消息队列也没什么错。

在Windows程序设计中,需要遵循“十分之一秒原则”。“十分之一秒原则”是指用户在做出操作后,至少应在0.1秒之内得到某种形式的反馈,这样才能让用户感觉到系统在对他的操作给予响应。如果一个任务执行时间超过0.1秒,我们为了良好的用户体验,就需要考虑新建一个线程来单独处理这个任务。我们将在本书的第二十章详细讲解进程与线程。

windows应用程序中一般都包含一小段称为“消息循环”的代码,该段代码用于从消息队列中检索消息,并将其分发给相应的窗口过程。其他非队列消息则不经过消息队列直接发送给窗口过程。

非队列消息

除了队列消息之外,剩下的消息就都属于非队列消息了。不需要被送入消息队列的消息可以通过SendMessage函数将消息直接发送给负责处理消息的窗口过程。

在Windows程序设计中,SendMessage函数被用于将一个消息发送给指定窗口或线程,它会等待消息处理完毕才会返回,也就是说它是一个同步或者说阻塞的函数。这是一个非常重要的用来在窗口间或线程间通信的函数。SendMessage函数可以在同一个线程内、同一个进程内的线程间或者不同进程的线程间通过消息进行通信。

下面是SendMessage函数的定义:

LRESULT SendMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

SendMessage函数应该是使用最频繁的一个函数了,在后面的章节中我们将深有体会。

相关推荐

Linux-常用操作命令介绍(linux常用的命令大全)

1.帮助命令帮助命令1.1help命令语法格式:命令--help作用:查看某个命令的帮助信息示例#ls--help#netstat--help1.2man命令语法格式:man命令...

推荐:一个小而美的Java工具类库(java工具软件)

前言是的,你没看错,没看错,它就是hutool!相信很多做java开发的朋友应该都已经认识并使用过它了,今天带大家再重温一下它都有哪些功能,并以示例来看看hutool是如何简便实现JWT认...

【SpringBoot后端开发】第三部分 Linux操作系统常用命令(3)

创作不易,请帮忙转发、点赞和评论!四、Linux常用命令对于Linux系统来说,中央处理器、内存、磁盘驱动器、键盘、鼠标、用户等都是文件,而Linux系统管理的命令是它正常运行的核心,与之DOS命令类...

linux常用命令在线查询工具(linux常用命令在线查询工具有哪些)

linuxvi编辑器常用命令linux查看iplinuxfind-name查找文件名linuxshelllinux查看端口占用linux删除文件命令linuxcp命令复制文件到另一个...

使用免费绿色工具chfs,将文件夹共享成网盘

需求:业务需求方有个需要将apk包上传到服务器中,通过chfs可以将服务器目录共享出来,可以可以登录后台自行上传apk文件包。本文就教大家三个知识点1.centos7下使用chfs,共享目录。2.使用...

Mysql和Hive之间通过Sqoop进行数据同步

文章回顾理论大数据框架原理简介大数据发展历程及技术选型实践搭建大数据运行环境之一搭建大数据运行环境之二本地MAC环境配置CPU数和内存大小查看CPU数sysctlmachdep.cpu#核数为...

真实案例记录Linux被植入rootkit导致服务器带宽跑满的解决过程

一、关于linux下的rootkitrootkit是Linux平台下最常见的一种木马后门工具,它主要通过替换系统文件来达到攻击和和隐蔽的目的,这种木马比普通木马后门更加危险和隐蔽,普通的检测工...

python周期任务调度工具Schedule使用详解

如果你想周期性地执行某个Python脚本,最出名的选择应该是Crontab脚本,但是Crontab具有以下缺点:不方便执行秒级任务。当需要执行的定时任务有上百个的时候,Crontab的管...

Linux 系统日常巡检脚本(shell巡检脚本)

Linux系统日常巡检脚本,巡检内容包含了,磁盘,内存cpu进程文件更改用户登录等一系列的操作直接用就行了。报告以邮件发送到邮箱在log下生成巡检报告。#!/bin/bash#@Au...

Schedule—简单实用的 Python 周期任务调度工具

如果你想周期性地执行某个Python脚本,最出名的选择应该是Crontab脚本,但是Crontab具有以下缺点:1.不方便执行秒级任务。2.当需要执行的定时任务有上百个的时候,Cronta...

celery定时与异步任务详解(定时任务异步执行)

celery简介Celery是一个简单、灵活且可靠的,处理大量消息的分布式系统,专注于实时处理的异步任务队列,同时也支持任务调度。Celery的架构由三部分组成,消息中间件(messagebroke...

开源免费的定时任务管理系统:Gocron

Gocron:精准调度未来,你的全能定时任务管理工具!-精选真开源,释放新价值。概览Gocron是github上一个开源免费的定时任务管理系统。它使用Go语言开发,是一个轻量级定时任务集中调度和管理...

PHP Laravel定时任务Schedule(laravel定时任务原理)

前提:本文方法是利用Linux的crontab定时任务来协助实现Laravel调度(Mac也一样)。一、首先添加Crontab定时任务,这里只做简单介绍:用命令crontab-e添加如下内容**...

Linux的常用命令就是记不住,怎么办?于是推出了这套教程

1.帮助命令1.1help命令#语法格式:命令--help#作用:查看某个命令的帮助信息#示例:#ls--help查看ls命令的帮助信息#netst...

如何定期执行 Python 脚本:5 种常见方法

定期执行任务是自动化工作流程中的重要环节,无论是数据抓取、文件备份,还是定期报告生成,定时运行脚本都可以极大提高效率。本文将介绍五种方法,通过这些方法,你可以轻松设置定期执行Python脚本的任务...

取消回复欢迎 发表评论: