Chinaunix首页 | 论坛 | 博客
  • 博客访问: 8621622
  • 博文数量: 1413
  • 博客积分: 11128
  • 博客等级: 上将
  • 技术积分: 14685
  • 用 户 组: 普通用户
  • 注册时间: 2006-03-13 10:03
个人简介

follow my heart...

文章分类

全部博文(1413)

文章存档

2013年(1)

2012年(5)

2011年(45)

2010年(176)

2009年(148)

2008年(190)

2007年(293)

2006年(555)

分类: C/C++

2007-03-28 17:35:16

运行一个wxWidgets应用程序,需要派生一个wxApp类,并覆盖它的wxApp::OnInit方法。

一个应用程序必须有一个顶层wxFrame或一个wxDialog窗体,任一个frame可能包含一个或多个如wxPanel和wxSplitterWindow的实例,也可能是其他的窗体或控件。

一个frame可以包含一个wxMenuBar、一个wxToolBar,一个状态条、一个wxIcon(如果说这个frame有图标的话)。

wxDialog的实例同样可以被用来作控件,用它的优点是它不需要额外建一个frame。

你也可以不用创建一个dialog并组装它的各个组件,因为你可以使用一些已经便利的dialog类,如wxMessageDialog、wxFileDialog。

你不能直接在窗体上draw,而是使用一个设备上下文(device context DC),wxDC是wxClientDC、wxPaintDC、wxMemoryDC、wxPostScriptDC、wxMemoryDC、wxMetafileDC和wxPrinterDC的基类。如果你的绘制函数中用到了wxDC作为参数的话,也就意味着你可以传递任何的DC类,也就是说你可以用同样的代码来绘制不同的设备。你可以用到wxDC的一些成员函数来进行绘制,比如wxDC::DrawLine和wxDC::DrawText。窗体上控件的有颜色(wxColour)、brush(wxBrush)和pen(wxPen)等一些常用到的属性。

要拦截事件,你可以添加一个DECLARE_EVENT_TABLE的宏到你的窗体类定义中,并要添加一个BEGIN_EVENT_TABLE ... END_EVENT_TABLE块到你的实现代码中去。在这些宏中,你可以添加事件宏来映射事件(比如单击鼠标)到成员函数。这样做将覆盖掉预先定义好的事件处理如wxKeyEvent和wxMouseEvent。

大部分modern的应用会有一个在线、超文本帮助系统,为此,你需要用到wxHelp及wxHelpController类来控制wxHelp。

GUI应用并非都是图形化wizardry,List以及hash table以wxList、wxStringList和wxHashMap的形式给出。当然,你需要一些与平台无关的文件处理函数,你会发现使用wxPathList来保存和查找一组path非常方便。

wxWidgets也提供了一个Hello World示例,并作了一定的说明,这里我进行一下简要的翻译。

首先,你要确认包含了wxWidgets的头文件。这可以是基础文件"wx/window.h",或者是全局包含"wx/wx.h",它对一些支持预编译头的编译器(在Windows平台上多数是这样)同样有效。

//

// file name: hworld.cpp

//

//   purpose: wxWidgets "Hello world"

//

 

// 针对一些支持预编译头的编译器,includes "wx/wx.h".

#include "wx/wxprec.h"

 

#ifdef __BORLANDC__

    #pragma hdrstop

#endif

 

#ifndef WX_PRECOMP

    #include "wx/wx.h"

#endif

实际上,任何一个应用都应该定义一个wxApp的派生类,并重写它的OnInit()方法使得程序能够被初始化。

class MyApp: public wxApp

{

    virtual bool OnInit();

};

主窗体的创建是通过派生wxFrame类并在构造器中为它添加一个菜单和一个状态条。同样,任何一个希望对"event"作出响应的类都应该定义一个事件表,使用下面的宏。最后,要定义好这些事件的处理"handlers"使其起作用。在这个例子中,我们处理两菜单项"Quit"和"About"(显示一个"about"窗体)。这些处理事件不能是虚函数。

class MyFrame: public wxFrame

{

public:

    MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);

 

    void OnQuit(wxCommandEvent& event);

    void OnAbout(wxCommandEvent& event);

 

private:

    DECLARE_EVENT_TABLE()       //注意,后面没有分号哦!!

};

对每一个菜单项,给它们定义唯一的ID。这里使用一个enum

enum

{

    ID_Quit = 1,

    ID_About,

};

然后定义一个事件表来指定类wxFrame的事件处理者。当然已经有一些预先定义的宏来指明所有基本事件包括了从选择列表框到resize事件。如果给的ID为-1,那么处理事件会对任何事件作出反应,所以你只需要添加一个条目到事件表来应付所有的菜单事件或按钮事件。事件的源在事件处理器中仍然是可以区分的,就像处理器中的参数是对wxEvent的一个引用,它包含了大量事件相关的信息(如发出事件的类的的ID以及指向它的指针)。

BEGIN_EVENT_TABLE(MyFrame, wxFrame)

    EVT_MENU(ID_Quit,  MyFrame::OnQuit)

    EVT_MENU(ID_About, MyFrame::OnAbout)

END_EVENT_TABLE()

如同在所有程序中一样,必须有一个"main"函数。在wxWidgets中,main的是通过一个宏实现的,它创建一个应用实例并启动程序。

IMPLEMENT_APP(MyApp)

正如前面提及的wxApp::OnInit()在启动的时候调用,用来初始化一个程序,你可能用它来显示一个"splash screen"并创建一个主窗体。frame可以获取一个标题("hello world")以及位置和起始大小。一个frame可以申明为top窗体。初始化成功返回true。

bool MyApp::OnInit()

{

    MyFrame *frame = new MyFrame( "Hello World", wxPoint(50,50), wxSize(450,340) );

    frame->Show( true );

    SetTopWindow( frame );

    return true;

}

在主窗体的构造器中,我们创建一个菜单,它有两个菜单项,同样创建一个状态条。添加在frame中。添加菜单和状态条调用的是不同的方法哦!

MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)

       : wxFrame((wxFrame *)NULL, -1, title, pos, size)

{

    wxMenu *menuFile = new wxMenu;

 

    menuFile->Append( ID_About, "&About..." );

    menuFile->AppendSeparator();

    menuFile->Append( ID_Quit, "E&xit" );

 

    wxMenuBar *menuBar = new wxMenuBar;

    menuBar->Append( menuFile, "&File" );

 

    SetMenuBar( menuBar );

 

    CreateStatusBar();

    SetStatusText( "Welcome to wxWidgets!" );

}

实际事件处理器已经申明过。MyFrame::OnQuit()用来关闭主窗体,调用Close()。参数true来指明其它窗体无权提示是否真正要关闭。如果无其他主窗体存在,应用程序将退出。

void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))

{

    Close( true );

}

MyFrame::OnAbout()用来显示一个有一些文本的小窗体。

void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))

{

    wxMessageBox( "This is a wxWidgets' Hello world sample",

                  "About Hello World", wxOK &line; wxICON_INFORMATION );

       //像不像MessageBox?

}

wxWidgets应用程序没有一个main,取而代之的是wxApp的派生类所定义的OnInit()函数。

与早些版本的wxWidgets不同,OnInit不再返回一个frame,而是返回一个bool值,说明处理是否可以继续。

你也可以调用wxApp::SetTopWindow来让wxWidgets知道顶层窗体。

注意,程序的command参数,也即以前的argc和argv在wxApp成员函数中仍然是有效的。

程序的结束要消毁所有的窗体。因为如此,尽可能地用父frame来创建新frame,这样在delete顶层frame的时候会自动delete子frame。当然,你也可以在顶层frame的wxCloseEvent事件中手动地delete各个子frame。

在有的时候,可以调用wxExit函数来kill程序。

举个例子,定义一个应用程序:

class DerivedApp : public wxApp

{

public:

  virtual bool OnInit();

};

 

IMPLEMENT_APP(DerivedApp)

 

bool DerivedApp::OnInit()

{

  wxFrame *the_frame = new wxFrame(NULL, ID_MYFRAME, argv[0]);

  ...

  the_frame->Show(true);

  SetTopWindow(the_frame);

 

  return true;

}

注意IMPLEMENT_APP(appClass)的用法,它使得wxWidgets在初始化的时候在合适的地方动态地创建一个应用程序的实例。以前的版本使用的方法依赖于一个全局应用程序对象,现在不推荐这样做了,因为需要一个全局的初始化过程可能使得它并不在应用程序构建的时候发生。你也可以在头文件中使用DECLARE_APP(appClass)来申明wxGetApp函数,它会返回一个应用程序对象的引用。否则你只能用全局的wxTheApp指针(一个wxApp型的指针)。

 

应用程序的关闭

当所有的顶层(top level)窗体都被关闭的时候,应用程序会正常结束。正常情况下是这样的,也就是说如果你只有一个顶层窗体那么调用一个Close()来处理菜单的"Exit"是足够的。如果这并不能令人满意,也可以调用wxApp::SetExitOnFrameDelete来改变它。注意,从wxWidgets 2.3.3开始,在应用程序进入main loop之前这一过程是不会起作用的,换句话说,你可以非常安全地在wxApp::OnInit中显示一个对话框而不必担心这个对话框的关闭而导致应用程序的结束,尽管这个对话框当时是唯一的顶层窗体。

应用程序结束的另一个要注意的就是OnExit,它在应用程序结束时且在wxWidgets清理其内部结束之前调用。你必须在OnExit结束之前清除所有你所创建的wxWidgets对象。特别不要在类的析构器中清理它们

举例,下面的代码会出问题:

class MyApp : public wxApp

{

 public:

    wxCHMHelpController m_helpCtrl;

    ...

};

原因在于m_helpCtrl是一个成员对象,这样它只有在类的析构器中清理。但MyApp对象只有在wxCHMHelpController所依赖的wxWidgets结构清理之后删除。解决的办法是在OnExit中清理HelpCtrl。

class MyApp : public wxApp

{

 public:

    wxCHMHelpController *m_helpCtrl;

    ...

};

 

bool MyApp::OnInit()

{

  ...

  m_helpCtrl = new wxCHMHelpController;

  ...

}

int MyApp::OnExit()

{

  delete m_helpCtrl;

  return 0;

}

阅读(3024) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~