Page246~250 11.1GUI下的I/O基础

11.1.1  从“控制台”说起

“命令行交互界面”(简称CUI,也有人称为CLI)。

CUI需要我们记忆并在控制台输入命令文本内容,而GUI则以图形的方式呈现、组织各类命令,比如Windows的“开始”菜单,用户只需通过简单的键盘或鼠标操作,就可以发起命令。

GUI操作系统重,用户可以同时处理多个任务,然而,一个总喜欢等待你“按下任意键”的CUI屏幕,就是史前操作系统展现各用户的全部,难以实现多任务

CUI和GUI的形同之处

我们写过的许多与用户交互的代码,其过程基本类似于图11-1

                                        图11 -1 典型的CUI主循环

11.1.2    GUI下的输入处理

基于控制台的程序,输入用cin, 输出用cout,非常简单。

GUI的输入,并非通过一个函数直接读取用户的一个按键操作或鼠标动作(也包括触摸屏的输入)的结果,而是操作系统,帮我们捕获这些输入操作,然后再有它转发到程序。

在GUI的世界里,往往有多个程序同时运行,哪怕就只有一个程序在运行,屏幕也可能有多个“图形元素”等待用户输入,所以必须有一套机制,以方便操作系统将用户的输入准确地转发到特定的那个图形元素。

这套机制最基础的要求是:每个图元元素都有一个“编号”(可以理解为“地址”)。综上所述,输入过程如图11-2所示

                                                        图11-2  消息传递与分发

统一术语:

以Windows操作系统为例,操作系统发送给各个应用程序的信息(包括用户输入),称为“消息(Message/Msg)”;各个拥有标号的“图形元素”,称为“窗口(Windows/Wnd)”;而编号也不是普通编号,它叫“句柄(Handle)

句柄的含义:句柄就是每个窗口在操作系统中唯一的编号。

控制台程序中,当程序运行到“cin >> i”之类的语句时,程序就卡在那里等待用户输入了。

但在GUI环境下,一个带窗口的程序运行起来之后,用户抓过鼠标就在窗口上挪动,并乱点一气……,这些操作都被认为是合理的,于是就将这些消息一次发送给程序了;如果程序不处理这些消息(哪怕是收到后就直接丢弃),操作系统就会会怀疑这个程序挂掉了。

所以编写一个GUI应用,最重要的事情,就是抓紧搞一个“死循环”来接收这些消息。以Windows操作系统为例,这个“死循环”的C代码类似:

//Windows API编程示例的伪代码
MSG msg; //消息
while(::GetMessage(&msg)
{
    ::TranslateMessage(&msg);
    ::DispatchMessage(&msg);
}

三个全局函数,都是Windows操作系统提供的编程接口(API)函数。

GetMessage源源不断地获取属于当前进程的消息

然后通过TranslateMessage做必要的转换

再调用DispatchMessage将它们正确地分派给本进程内的窗口。

但,代码里没有看到窗口句柄,怎么知道各个消息属于哪个窗口呢?猜一下就知道了,MSG结构里有一个成员,就是这个消息所属窗口的句柄

再往后的工作,就是每个窗口都会有一个术语为"WndProc(窗口过程)"的函数,它会收到操作系统发来的消息,然后搞一个“switch / case”结构来区分消息是什么,再做处理。

                                                图  11-3    GUI下的消息循环

这个过程被称为消息循环。简单地理解,就是应用程序将源源不断地接收到消息,然后判断这消息是什么,根据这个消息触发并执行一段事件(回调函数),然后再收到新消息……

一个从零开始的GUI应用代码,需要从“GetMessage(...)”开始写起,但多数C++  GUI库,都将这个过程封装起来,所以编程重心变成是为每一类窗口(如图11-3中的窗口1和窗口2)写它处理消息的过程;但一大块的"switch / case"是令人厌烦的结构,所以GUI库提供了一些手段,帮助我们绕过"switch / case"。

11.1.3    GUI下的输出处理

既然叫“图形用户界面”,自然要在屏幕上画各种信息。屏幕再大,面积总是有限的,外加“多任务”,每个进程都抢这在屏幕上涂鸦,结果很容易想到:后面画的内容,会将前面的内容覆盖掉。

电脑上打开QQ登录框,把它摆在屏幕中央;然后打开浏览器,拖过去盖住QQ登录框,此时,我们看到的那个QQ登录框还在吗?

那个QQ登录框真的不在了。QQ程序肯定还在内存里,QQ登录框的窗口句柄也还在操作系统的“账本”里,但此时操作系统无需尝试网屏幕上“画”那个对话框;

假设我们将浏览器一点一点地挪开,此时QQ程序会收到一个消息:“你快重画窗口,不过就这一小块有效。

如此,是否可以推出GUI程序和CUI程序在界面显示上最大的不同?

CUI程序是主动的,在你想要的时间,地点,想说一句话是,直接cout一下,比如:

char C;

//此时,此处,需要一句提示
cout << "请输入一个字母:";
cin >> C;

//此时,此处,又需要一句话
cout << "您输入的字母是:" << C << "。" << endl;
//想想,觉得需要再补一句
cout << "我是不是很聪明?" << endl;

GUI程序在这方面却是被动的,它必须等操作系统发消息通知它:“嘿,你可以在屏幕上输出点什么了。”  操作系统通知一次,就得响应一次。

假设GUI程序使用DrawText(int x, int y, char const* text)函数可以在屏幕上指定位置上输出一句话,但程序只是主动调用一次,比如:

DrawText(100, 100, "Hello World");

屏幕上确实有可能出现那句话,但此时再把浏览器拖过啦,“盖住”那行话,然后移开……那行话消失不见了,浏览器就像一个橡皮擦,把那行话擦掉了

其间原因在于:我们写的程序也接收到了操作系统“快重画吧”的消息,却不理会这个消息,没有再次调用DrawText()操作。

那么,是不是屏幕上显示的所有内容,都需要我们写代码自行绘画呢?当然不是,像常规窗口,对话框,按钮,列表框和菜单等标准袁术,它们在不同的应用中长得样子都相似,可见其画法都一样。因为它们统一由操作系统(或其GUI支持库)负责在屏幕上画出来,除非我们想搞定制,比如画一个不规则多边形的按钮。

  • 15
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值