从Turbo Vision源码看事件驱动

本文深入探讨了事件驱动机制,通过分析Turbo Vision的源码,揭示了系统如何收集用户输入并包装成事件,以及如何分发这些事件。文章首先介绍了事件的基本结构,接着详细讲解了事件的产生、获取、传送和处理过程,包括鼠标事件、键盘事件的获取,以及事件在视图链中的传递。最后,通过一个实例展示了事件如何驱动程序响应用户操作,如在状态行上按下鼠标左键触发程序退出的过程。
摘要由CSDN通过智能技术生成

1:缘起
在传统的程序中,一个具有交互功能的应用程序的主体无疑是如下的一段循环代码:不断读取用户的输入,根据输入采取相应的动作,完成所需的功能。例如:
bool quit=false;
char ch;
while(!quit) {
 ch=read_input();
 switch(ch) {
  case 'i':
   // ... …
   break;
  case 'q':
   quit=true;  // … …
   break;
  default:
   // ... …
 } }
而基于事件驱动机制的程序则不大相同,主程序可能如下这般:
int main()
{  
TMyApp myApp;
    myApp.run();
    return 0;
}
在整个程序中,唯一与事件有点关系的要属handleEvent函数了,它可能并不像你我想像的那样(注:以Turbo Vision中的应用程序为例,根据类的继承关系,函数的调用序列依次为:TMyApp::run()  TApplication::run()  TGroup::execute()  TMyApp::handleEvent() 来处理事件):
void TMyApp::handleEvent(TEvent& event) {
    TApplication::handleEvent(event);   // act like base!
    if( event.what == evCommand ) {
        switch( event.message.command ){
            case cmMyNewWin:       // but respond to additional commands
                myNewWindow();     // define action for cmMyNewWin
                break;
            default:
    // … …
                return;
            }
        clearEvent( event );       // clear event after handling
        }
}
从这里,我们明显可以看到一份简单,一个鸿沟:没有了令人头疼的循环,程序中的对象只需要处理自己收到的事件,程序的结构变得异常简单清晰;但也正是这份简单,让本来清楚明白的流程变得神秘起来,没有了读取用户输入,摆放在面前的已经是送到的事件,这多少有点让人措手不及,前面的路是谁铺就的?一切的一切,都缘起于事件驱动机制:读取了用户的输入,并把其包装成事件,然后按照一定的规则分发给不同的对象;正是它,造就了简单,也成就了神秘;有了它,用户才可以把所有的精力集中于事件的处理上,而不用分心其他琐事。例如:在一个非活动窗口上按下鼠标左键,用户只需确保该窗口在接收到该消息时,能够把自己调到前台,正确地显示即可。在鼠标轻点与窗口响应之间,系统在幕后默默地做了许多事情:读取鼠标的动作并形成的事件,按照一定的规则把事件发送给该非活动窗口。
系统替我们完成的这许多事情,给事件驱动蒙上几分神秘、几分诱惑。不论是好奇心、还是求知欲,都使人有揭开面纱,一探究竟的冲动。最直接的方法是去看源码,借用一句话:“源码之前,了无秘密”。源码之中,会清楚地显示系统是如何收集用户的输入,又是如何把用户的输入打包成事件,分发给程序中的各个对象的。追踪到源码级别,相信已经足以理解事件驱动机制。然而,去哪儿找到这样的源码呢?Windows操作系统是基于事件驱动的,但哪儿有其源码?Linux操作系统倒是有源码,然而,面对其浩如烟海的文件,如何简洁、干练地抽出事件驱动的源码而不至于陷于泥沼无法自拔?因此,最好是能够有一个基于事件驱动的、微型的应用程序框架,既能把事件驱动机制讲个清楚明白又不至于吓退登山者。Turbo Vision无疑是最佳人选。
Turbo Vision是一个应用程序框架,为基于DOS的应用程序开发提供了全新的方法,可以为用户生成完整的界面,包括窗口、对话框、菜单、鼠标以及简单的编辑器等。Borland C++3.1中就附带有Turbo Vision的源码,网上也可以找到Turbo Vision的源码。
Turbo Vision应用程序的框架如图:

TMyApp-->TApplication-->TProgram-->TGroup-->TView-->TObject
                                                      -->TProgInit            -->TStreamable
 
图1:Turbo Vision应用程序框架图
一个Turbo Vision应用程序是视图、事件及哑对象的组合。下面,分别对视图和哑对象作一简单的介绍,至于事件,后面会有详尽的介绍。
视图是屏幕上可见的程序元素对象。在Turbo Vision程序中,凡可见的,都是视图。标题、窗口边框、滚动条、菜单条等都是视图。视图也可以组合,形成复杂的程序元素,如对话框。这些视图的集合称为组。组作为特殊的视图,由其它称为其子视图的元素组成,而组自身也可以作为单一的视图与其他视图形成更复杂的元素,这样形成了一个复杂的视图链。
哑对象是程序中非视图的对象,在屏幕上不显示,无法与用户交互,故称为其哑对象。它们完成计算、与外围设备的通讯等后台任务,当其需要显示信息时,必须通过视图来进行。
这是只对Turbo Vision做一简单的介绍,在后面用到某些概念时,会略加注释,帮助读者理解。
2:事件的介绍
事件是一个无法再细分的信息包,描述了应用程序必须响应的具体事件。每一次击键、每一个鼠标动作以及程序的某一部分引起的某种特定情况都构成一个单独的事件。因此,用户输入一个单词不是一个事件,而是一系列独立的击键事件的集合。
不同的事件具有不同的性质,具有不同的结构,因此,有必要先了解不同种类的事件。事件的结构如下:
struct TEvent{
    ushort what;
    union{
        MouseEventType mouse;
        KeyDownEvent keyDown;
        MessageEvent message;
    };
    void getMouseEvent();
    void getKeyEvent();
};
由事件TEvent的结构可以清楚地看到,从本质上讲,有四类事件:鼠标事件,键盘事件,消息事件和空事件,对应于TEvent::what成员的四个可能取值,evMouse,evKeyboard,evMessage,evNothing。根据TEvent::what的值,TEvent对象可以决定自身的类型,使用相应的成员函数getMouseEvent()或getKeyEvent()来获得事件。
鼠标事件包括四种:鼠标键的按下与松开导致的evMouseDown、evMouseUp事件,移动鼠标产生的evMouseMove事件,保持按下某一键产生的evMouseAuto事件等,故鼠标事件

LTE Turbo码在LTE通信系统中被广泛采用,它是一种前向纠错码,可以提高信号传输的可靠性。LTE Turbo码的编解码过程可以使用Matlab编程实现,以下是一个简单的LTE Turbo码的Matlab源码示例: function [coded_bits, decoded_bits] = LTE_TurboCoder(input_bits,SNR) % Turbo码编码 trellis = poly2trellis(4, [13 15], 13); encoder = comm.ConvolutionalEncoder(trellis); coded_bits = step(encoder,input_bits); % 添加噪声 noise = comm.AWGNChannel('EbNo',SNR,'BitsPerSymbol',1); noisy_coded_bits = noise(coded_bits); % Turbo码解码 decoder = comm.TurboDecoder(trellis); decoded_bits = step(decoder,noisy_coded_bits); % 返回编码后的比特流和解码后的比特流 end 在这个源码中,首先定义了一个LTE Turbo码的编码器和译码器。编码器使用poly2trellis()函数创建一个trellis对象,指定了4状态的卷积编码器和13和15两个生成多项式。然后,通过comm.ConvolutionalEncoder对象将输入比特流input_bits进行编码,得到编码后的比特流coded_bits。 接下来,添加了一个AWGN信道模拟噪声,并使用EbNo信噪比和BitsPerSymbol参数设置信噪比和每个符号的比特数。将编码后的比特流传递给噪声信道,得到带有噪声的编码比特流noisy_coded_bits。 最后,使用comm.TurboDecoder对象将带有噪声的编码比特流解码,得到解码后的比特流decoded_bits。 最终,函数返回编码后的比特流coded_bits和解码后的比特流decoded_bits。 这段Matlab源码可以用于对LTE Turbo码进行编码和解码的仿真实验,通过调整输入比特流和信噪比参数,可以测试编码和解码的性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值