wxWidgets:使用事件

本文介绍了wxWidgets框架中事件处理的概念和使用,包括事件表、回调函数和事件宏的运用。通过实例展示了如何将事件映射到处理函数,如EVT_MENU用于处理菜单事件。文章强调了wxWidgets在简化事件编程方面的优势,同时也提到了处理事件的复杂性。

wxWidgets:使用事件

介绍

许多年前,我在两种不同的操作系统上工作。一个是分时系统,操作系统调度程序为每个用户提供了一段使用计算机资源的时间。另一个是事件驱动系统,它是一个工业过程控制器,过程不能等待用户各自获得资源份额。该计算机系统旨在快速响应外部事件,例如即将发生的核芯熔化。在某些方面,GUI 系统将事件驱动模型与分时模型相结合。

事件是在程序之外发生的一些有趣的事件。它可能是由用户选择菜单项或按下热键启动的。它可能是由计算机环境中但程序外的某些东西启动的,计时器停止工作,通信端口上可用的一些数据,系统关闭消息等。无论事件的起源如何,都需要处理。

在我撰写本文时,我的系统(Windows 98 系统)上加载了 10 个应用程序。除了这个编辑器,应用程序似乎没什么用,偶尔硬盘灯会闪烁。但是,如果我单击任务栏上的应用程序,该应用程序将出现并准备工作。任务栏接收鼠标单击事件,将事件和相关信息弹出到由操作系统管理的队列中,然后适当的应用程序以某种方式收到一条消息,说明它已被调用。

事件处理的常用编程技术是使用回调函数。下面是一个在FLTK(另一个跨平台框架)中使用回调函数的例子:

Fl_Menu_Item menuitems[] = {
	{ "&File", 0,0,0, FL_SUBMENU },
	{ "&New", FL_ALT + 'n', (Fl_Callback *) new_cb }, 
	...    
}

void new_cb(void)
{
	if ( changed && !check_save() ) return;

	filename[0] = '\0';
	input->value("");
	set_changed(0);
}

程序片段显示了一个菜单项,该菜单项具有与其关联的函数new_cb。该函数被类型转换为指向 Fl_Callback 的指针。当应用程序接收到来自操作系统的消息,表明选择了新建菜单项时,应用程序可以调用 new_cb()。Win32 API 也有类似的机制。需要响应事件的窗口具有声明为 CALLBACK 类型函数的函数。

wxWidgets 和微软的 MFC 框架(微软基础类)都使用了不同的技术,至少从程序员的角度来看是这样。很有可能在回调机制下仍然使用。它被称为“事件表”,它简化了事件编程的业务。

wxWidgets 事件表

BEGIN_EVENT_TABLE (BasicFrame, wxFrame)
	EVT_MENU ( BASIC_EXIT,  BasicFrame::OnExit)
	EVT_MENU ( BASIC_ABOUT, BasicFrame::OnAbout)
	EVT_MENU ( BASIC_OPEN,  BasicFrame::OnOpenFile)
END_EVENT_TABLE()

正如您在此处看到的,wxWidgets 事件表本身很简单。它是宏的集合,第一个预示事件表的开始,接下来的三个用类方法链接某种常量,最后一个预示事件表的结束。事件表将由诸如 BASIC_OPEN 之类的常量标识的事件映射到诸如 BasicFrame::OnOpenFile 之类的函数和方法。

我们的程序中可能有许多事件表,因此我们需要明确哪个类将处理任何给定事件表的事件。所述BEGIN_EVENT_TABLE宏声明此事件表所属BasicFrame其从wxFrame类派生的。我们还需要明确该类将使用偶数表,并使用DECLARE_EVENT_TABLE()宏执行此操作,该宏出现在接口文件的类原型中。最后,我们必须提供处理事件的成员函数。我们应该看一个关于所有这些的实际例子:

#ifndef BASIC_H
#define BASIC_H

#include <wx/wx.h>

static const wxChar *TITLE = _T("Basic - Step 3: Responding to Events");

class BasicApplication : public wxApp
{
public:
	virtual bool OnInit();
};

class BasicFrame : public wxFrame
{
public:
	BasicFrame( const wxChar *title, int xpos, int ypos, int width, int height );
	~BasicFrame();

	wxTextCtrl *theText;
	wxMenuBar  *menuBar;
	wxMenu     *fileMenu;

	void OnOpenFile (wxCommandEvent & event);
	void OnAbout    (wxCommandEvent & event);
	void OnExit     (wxCommandEvent & event);

	DECLARE_EVENT_TABLE()
};

enum {
	BASIC_EXIT  =   1,
	BASIC_OPEN  = 100,
	BASIC_ABOUT = 200
};

#endif

这是头文件,你会在这里看到一些新的东西,并不是所有的东西都与事件有关。首先是这个奇怪的工作:

static const wxChar *TITLE = _T("Basic - Step 3: Responding to Events");

你可以猜到我们声明了一个指向 char 的指针,它是一个常量值并且它是静态的。在这个特定的例子中,将变量声明为静态没有多大意义。这样做的原因是我们通常使用静态来确保在函数调用之间保留值(内部静态)或隐藏其他文件中的变量(外部静态)。因为我们在这个例子中没有使用任何其他文件,所以静态内存类是多余的。尽管如此,将外部或全局变量(即在函数外部声明的变量)声明为静态变量是一种很好的做法。原因是我们可能在其他地方使用此文件并希望避免名称冲突的可能性。宏_T是另一个宏wxTRANSLATE的化名,它与语言环境信息有关,但我还不知道!但是现在事件表的问题:你可以看到左边我们有三个成员函数,每个都是一个空函数,每个都有一个 wxCommandEvent 参数。这些实际上是我们的回调函数。还有一个宏 DECLARE_EVENT_TABLE() 警告编译器这个类将有一个事件表。最后是一个枚举范围,我们用它来为一些数值提供一些有意义的标识符。

#include "basic.h"

IMPLEMENT_APP(BasicApplication)

bool BasicApplication::OnInit()
{
	...
}

BasicFrame::BasicFrame(...)
{
	...

	fileMenu = new wxMenu;
	fileMenu->Append(BASIC_OPEN,  _T("&Open file"));
	fileMenu->Append(BASIC_ABOUT, _T("&About"));
	fileMenu->AppendSeparator();
	fileMenu->Append(BASIC_EXIT,  _T("E&xit"));

	menuBar = new wxMenuBar;
	menuBar->Append(fileMenu, _T("&File"));
	SetMenuBar(menuBar);
	CreateStatusBar(3);  
}

BasicFrame::~BasicFrame() { ... }

BEGIN_EVENT_TABLE (BasicFrame, wxFrame)
	EVT_MENU ( BASIC_EXIT,  BasicFrame::OnExit)
	EVT_MENU ( BASIC_ABOUT, BasicFrame::OnAbout)
	EVT_MENU ( BASIC_OPEN,  BasicFrame::OnOpenFile)
END_EVENT_TABLE()

void BasicFrame::OnOpenFile( wxCommandEvent & event )
{
	theText->LoadFile(_("data.txt"));
}


void BasicFrame::OnAbout( wxCommandEvent & event )
{
	wxString t = TITLE;
	t.append( _T("\nDB 2001") );

	wxMessageDialog aboutDialog( this, t, _T("About Basic"), wxOK | wxCANCEL );
	aboutDialog.ShowModal();
}

void BasicFrame::OnExit( wxCommandEvent & event )
{
	Close(TRUE);
}

用户警告:我尝试使用最新的 SVN Code::Blocks 与自定义创建的项目编译此内容,但最终出现错误“应用程序无法正确初始化()”。我对此的解决方法是在项目设置中定义:“WXUSINGDLL”

左边是实现文件。除了我们添加了以下内容外,这里没有任何变化:

将事件映射到函数的事件表
处理事件的成员函数 wxWidgets 帮助程序员区分不同类型事件的一种方式是提供不同类型的宏。该表包含三个专门处理菜单事件的 EVT_MENU() 宏。其他宏包括:
EVT_BUTTON
EVT_CHECKBOX
EVT_RADIOBTON
EVT_SLIDER
EVT_SCROLLBAR 等等。在后面的课程中,我们将学习如何使用其他事件,现在我们只专注于基础知识。OnOpenFile 方法演示了 wxTextCtrl 是多么有用。它有一个方法可以将文件的内容直接加载到控件中。当我们单击 File 菜单的“Open file”项时,这会触发一个事件,操作系统捕获它并通知我们的应用程序,然后应用程序调用适当的函数 - 将文件加载到theText 中。 OnAbout 方法使用一个新类wxMessageDialog。我将在本次会议的后面介绍这个类和 wxCommandEvent 类。

概括

虽然这是一个重要的会议,但我保持简短并限制了范围,以便您可以对 wxWidgets 事件有一个很好的基本了解。处理事件可能是一项相当复杂的业务,即使 wxWidgets 框架使程序员更容易,但仍然存在合理的复杂程度。

在下一个会话中,我们将了解使用一些常见对话框。

该博文为原创文章,未经博主同意不得转载,如同意转载请注明博文出处
本文章博客地址:https://cplusplus.blog.csdn.net/article/details/118890603

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

源代码大师

赏点狗粮吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值