wxWidgets学习日记

本文介绍了wxWidgets应用程序的基本结构和创建步骤,包括派生wxApp类、定义窗口、处理事件等核心概念。

运行一个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;

}

 
wxWidgets是一个开源的C++跨平台GUI工具包,能够让开发人员使用统一的代码库开发Windows、Linux和Mac等不同平台上的应用程序。本文档将介绍wxWidgets的基本概念、用法和一些实例。 1. wxWidgets的基本概念 wxWidgets中最重要的概念是控件(Widget),它是指窗口中的各种元素,如按钮、文本框、列表框等。每个控件都有一个唯一的ID,用来标识它。对控件的操作(如改变控件的值、显示或隐藏控件)要通过控件的ID来进行。 另一个重要的概念是事件(Event),它是指窗口中发生的各种动作,如用户单击按钮、移动滚动条等。当用户进行某种操作时,系统会产生一个事件,并将其发送给相应的控件。控件可以根据接收到的事件来进行相应的操作。事件处理函数是用来处理事件的回调函数,一般是在控件被创建时指定的。 2. wxWidgets的用法 使用wxWidgets开发应用程序的基本步骤是: ① 定义一个wxApp类(继承自wxApp),在该类的OnInit方法中创建主窗口(MainFrame); ② 在MainFrame类中定义各个控件和事件处理函数; ③ 在wxApp类的OnRun方法中显示主窗口,并进入消息循环,等待用户操作事件。 下面是一个简单的示例代码: ``` c++ // MyApp.h文件 class MyApp: public wxApp { public: virtual bool OnInit(); }; // MyApp.cpp文件 bool MyApp::OnInit() { wxFrame *frame = new wxFrame(NULL, wxID_ANY, "Hello wxWidgets", wxPoint(50, 50), wxSize(800, 600)); frame->Show(); return true; } IMPLEMENT_APP(MyApp); // Main.cpp文件 #include <wx/wx.h> #include "MyApp.h" wxIMPLEMENT_APP(MyApp); ``` 上述程序创建了一个名为“Hello wxWidgets”的窗口,大小为800*600。要增加控件,只需在MyApp类中的OnInit方法中添加相应的代码。 3. wxWidgets实例 以下示例程序演示了如何使用wxWidgets开发一个简单的计算器应用程序。 ``` c++ // Calculator.h文件 class Calculator: public wxFrame { public: Calculator(const wxString &title, const wxPoint &pos, const wxSize &size); private: enum { BUTTON_0 = 100, BUTTON_1, BUTTON_2, BUTTON_3, BUTTON_4, BUTTON_5, BUTTON_6, BUTTON_7, BUTTON_8, BUTTON_9, BUTTON_ADD, BUTTON_SUB, BUTTON_MUL, BUTTON_DIV, BUTTON_EQUAL, BUTTON_CLEAR }; wxString m_inputValue; void OnButtonClicked(wxCommandEvent &event); wxTextCtrl *m_textctrl; wxDECLARE_EVENT_TABLE(); }; // Calculator.cpp文件 Calculator::Calculator(const wxString &title, const wxPoint &pos, const wxSize &size) : wxFrame(NULL, wxID_ANY, title, pos, size) { wxPanel *panel = new wxPanel(this, wxID_ANY); wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL); m_textctrl = new wxTextCtrl(panel, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, wxTE_RIGHT); m_textctrl->SetFont(wxFont(20, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); vbox->Add(m_textctrl, 0, wxEXPAND | wxTOP | wxBOTTOM, 4); wxBoxSizer *hbox1 = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer *hbox2 = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer *hbox3 = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer *hbox4 = new wxBoxSizer(wxHORIZONTAL); hbox1->Add(new wxButton(panel, BUTTON_1, wxT("1")), 1, wxEXPAND | wxALL, 4); hbox1->Add(new wxButton(panel, BUTTON_2, wxT("2")), 1, wxEXPAND | wxALL, 4); hbox1->Add(new wxButton(panel, BUTTON_3, wxT("3")), 1, wxEXPAND | wxALL, 4); hbox1->Add(new wxButton(panel, BUTTON_ADD, wxT("+")), 1, wxEXPAND | wxALL, 4); vbox->Add(hbox1, 0, wxEXPAND); hbox2->Add(new wxButton(panel, BUTTON_4, wxT("4")), 1, wxEXPAND | wxALL, 4); hbox2->Add(new wxButton(panel, BUTTON_5, wxT("5")), 1, wxEXPAND | wxALL, 4); hbox2->Add(new wxButton(panel, BUTTON_6, wxT("6")), 1, wxEXPAND | wxALL, 4); hbox2->Add(new wxButton(panel, BUTTON_SUB, wxT("-")), 1, wxEXPAND | wxALL, 4); vbox->Add(hbox2, 0, wxEXPAND); hbox3->Add(new wxButton(panel, BUTTON_7, wxT("7")), 1, wxEXPAND | wxALL, 4); hbox3->Add(new wxButton(panel, BUTTON_8, wxT("8")), 1, wxEXPAND | wxALL, 4); hbox3->Add(new wxButton(panel, BUTTON_9, wxT("9")), 1, wxEXPAND | wxALL, 4); hbox3->Add(new wxButton(panel, BUTTON_MUL, wxT("*")), 1, wxEXPAND | wxALL, 4); vbox->Add(hbox3, 0, wxEXPAND); hbox4->Add(new wxButton(panel, BUTTON_CLEAR, wxT("C")), 1, wxEXPAND | wxALL, 4); hbox4->Add(new wxButton(panel, BUTTON_0, wxT("0")), 1, wxEXPAND | wxALL, 4); hbox4->Add(new wxButton(panel, BUTTON_EQUAL, wxT("=")), 1, wxEXPAND | wxALL, 4); hbox4->Add(new wxButton(panel, BUTTON_DIV, wxT("/")), 1, wxEXPAND | wxALL, 4); vbox->Add(hbox4, 0, wxEXPAND); panel->SetSizer(vbox); Bind(wxEVT_BUTTON, &Calculator::OnButtonClicked, this); } void Calculator::OnButtonClicked(wxCommandEvent &event) { int id = event.GetId(); wxString value = m_textctrl->GetValue(); if (id >= BUTTON_0 && id <= BUTTON_9) { // 处理数字按钮事件 wxString digit = wxString::Format(wxT("%d"), id - BUTTON_0); m_inputValue += digit; m_textctrl->SetValue(m_inputValue); } else if (id == BUTTON_ADD) { // 处理加号按钮事件 m_inputValue += wxT(" + "); m_textctrl->SetValue(m_inputValue); } else if (id == BUTTON_SUB) { // 处理减号按钮事件 m_inputValue += wxT(" - "); m_textctrl->SetValue(m_inputValue); } else if (id == BUTTON_MUL) { // 处理乘号按钮事件 m_inputValue += wxT(" * "); m_textctrl->SetValue(m_inputValue); } else if (id == BUTTON_DIV) { // 处理除号按钮事件 m_inputValue += wxT(" / "); m_textctrl->SetValue(m_inputValue); } else if (id == BUTTON_CLEAR) { // 处理清除按钮事件 m_inputValue = wxT(""); m_textctrl->SetValue(m_inputValue); } else if (id == BUTTON_EQUAL) { // 处理等号按钮事件 wxStringTokenizer tokenizer(m_inputValue, wxT(" ")); double result = 0; wxString op; while (tokenizer.HasMoreTokens()) { wxString token = tokenizer.GetNextToken(); if (token == wxT("+") || token == wxT("-") || token == wxT("*") || token == wxT("/")) { op = token; } else { double value = 0; token.ToDouble(&value); if (op.IsEmpty()) { result = value; } else if (op == wxT("+")) { result += value; } else if (op == wxT("-")) { result -= value; } else if (op == wxT("*")) { result *= value; } else if (op == wxT("/")) { result /= value; } } } m_inputValue = wxString::Format(wxT("%f"), result); m_textctrl->SetValue(m_inputValue); } } wxBEGIN_EVENT_TABLE(Calculator, wxFrame) EVT_BUTTON(wxID_ANY, Calculator::OnButtonClicked) wxEND_EVENT_TABLE() // MyApp.h文件 class MyApp: public wxApp { public: virtual bool OnInit(); }; IMPLEMENT_APP(MyApp); // MyApp.cpp文件 bool MyApp::OnInit() { Calculator *frame = new Calculator("Calculator", wxPoint(50, 50), wxSize(320, 240)); frame->Show(); return true; } ``` 上述程序创建了一个简单的计算器应用程序。通过继承wxFrame类并添加各种控件,可以实现各种GUI应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值