第一个wxWidgets程序 - Go语言中文社区

第一个wxWidgets程序


设置开发环境

在创建应用程序前,需要设置Visual Studio开发环境和WxWidgets的相关变量,具体包括:

  • 包含目录:包含WxWidgets头文件。在项目“属性→配置属性→C++目录→包含目录”项中,添加C:wxWidgets-3.0.2includemsvcC: wxWidgets-3.0.2include
  • 库目录:包含WxWidgets库文件。在项目“属性→配置属性→C++目录→库目录”项中,添加C:wxWidgets-3.0.2libvc_dll
  • 系统环境变量:设置WxWidgets动态链接库文件目录。在Windows控制面板“系统→高级系统设置→高级→环境变量→系统变量”中,在Path变量的内容中增加C:wxWidgets-3.0.2libvc_dll
  • 预处理器定义:设置与Windows平台相关的WxWidgets宏,主要包括 _WXMSW_WXUSINGDLL等。
  • 在程序中包含程序所需的头文件。

其中,预处理器定义和包含程序所需头文件两个步骤可以通过创建一个头文件wxInc.h来集中解决,用户代码中只需包含该头文件即可。

/// wxInc.h

#ifndef _WX_INC_H_
#define _WX_INC_H_

#define __WXMSW__   /// 使用windows平台
#define WXUSINGDLL  /// 使用动态链接库

#ifdef _DEBUG
#define __WXDEBUG__  /// 使用WxWidgets调试
#endif //_DEBUG

#include "wx/config.h"

#include "wx/wx.h"       /// 使用WxWidgets通用功能和类
#include "wx/aui/aui.h" /// 使用AUI
#include "wx/artprov.h"  /// 使用预定义的图标资源

#endif ///_WX_INC_H_

简单窗口程序

最简单的WxWidgets窗口程序需要2个类:
(1)wxApp类,代表了应用程序,负责消息循环。
(2)wxFrame,代表了窗口,处理各类窗口事件。

下面创建一个简单的窗口程序。程序运行效果如下图所示。
简单窗口程序效果图

简单窗口程序创建步骤如下:
(1)从wxApp派生用户类MyApp。
wxApp采用了类似MFC的宏定义和处理机制,通过DECLARE_APP()IMPLEMENT_APP()两个宏声明和定义程序全局变量(也就是程序的入口点)。

/// MyApp.h

#include "wxInc.h"

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

DECLARE_APP(MyApp)

如未声明DECLARE_APP()和IMPLEMENT(),则编译时会报错如下:
MSVCRTD.lib(crtexew.obj) : error LNK2019: 无法解析的外部符号 _WinMain@16,该符号在函数 ___tmainCRTStartup 中被引用

(2)重载wxApp::OnInit函数,在该函数内新建和显示主窗口。

/// MyApp.cpp

#include "MyApp.h"

IMPLEMENT_APP(MyApp)

bool MyApp::OnInit()
{
    /// 1.创建窗口
    wxFrame * mainWnd = new wxFrame(NULL, wxID_ANY, wxT("main window"));                    

    /// 2.将窗口设置为程序主窗口
    SetTopWindow(mainWnd); 

    /// 3.显示窗口。
    mainWnd->Show(true);   

    return true;
}

上述程序的wxPython版本如下(简单明了):

/// MyApp1.py

import wx

if __name__ == "__main__":
    app = wx.App()
    mainWnd = wx.Frame(None, -1, "main window")
    app.SetTopWindow(mainWnd)
    mainWnd.Show()

    app.MainLoop()

添加菜单、工具栏和状态栏

前面程序显示了一个“白板”窗口,没有什么实际的意义。作为一个应用程序,必须通过与用户进行交互,提供用户所需的内容。应用程序中,与用户交互的最简单的方式是菜单、工具栏、状态栏等。

下面,我们就创建一个有菜单、工具栏和状态栏的应用程序界面。程序运行效果如下图所示。
这里写图片描述

该程序的主要界面要素包括:

  • 2个菜单项,每个菜单项下又各包含2个子项
  • 1个工具栏,工具栏上有3个按钮
  • 1个状态栏,状态栏上分3个显示区

具体步骤如下:
(1)自定义窗口类,在该窗口类中创建菜单、工具栏和状态栏。

/// MyFrame.h

#pragma once

#include "wxInc.h"

class MyFrame : public wxFrame
{
public:
    MyFrame();
};
/// MyFrame.cpp

#include "MyFrame.h"

enum {
    ID_ITEM_1 = wxID_HIGHEST + 1,
    ID_ITEM_2,
    ID_ITEM_3,
    ID_ITEM_4,
    ID_ITEM_5,
    ID_ITEM_6,
    ID_ITEM_7,
};

MyFrame::MyFrame() : wxFrame(NULL, wxID_ANY, wxT("main window"))
{
    /// 1. 创建菜单栏
    wxMenuBar * menuBar = new wxMenuBar();

    wxMenu * menu1 = new wxMenu();
    menu1->Append(ID_ITEM_1, wxT("subitem 1-1"));
    menu1->Append(ID_ITEM_2, wxT("subitem 1-2"));
    menuBar->Append(menu1, wxT("item 1"));

    wxMenu * menu2 = new wxMenu();
    menu2->Append(ID_ITEM_3, wxT("subitem 2-1"));
    menu2->Append(ID_ITEM_4, wxT("subitem 2-2"));
    menuBar->Append(menu2, wxT("item 2"));

    SetMenuBar(menuBar);

    /// 2. 创建工具栏
    wxToolBar * toolBar = new wxToolBar(this, wxID_ANY);
    toolBar->AddTool(ID_ITEM_5, wxT("button1"), wxArtProvider::GetBitmap(wxART_GO_BACK, wxART_TOOLBAR));
    toolBar->AddTool(ID_ITEM_6, wxT("button2"), wxArtProvider::GetBitmap(wxART_TIP, wxART_TOOLBAR));
    toolBar->AddSeparator();    
    toolBar->AddTool(ID_ITEM_7, wxT("button3"), wxArtProvider::GetBitmap(wxART_UNDO, wxART_TOOLBAR));
    toolBar->Realize();  /// 在增加按钮后必须调用此函数
    SetToolBar(toolBar);    

    /// 3. 创建状态栏
    wxStatusBar * statusBar = CreateStatusBar(3);
    statusBar->SetStatusText(wxT("this is pane 0"), 0);
    statusBar->SetStatusText(wxT("this is pane 1"), 1);
    statusBar->SetStatusText(wxT("this is pane 2"), 2);
}

(2)将该窗口类的实例作为主窗口

/// MyApp.cpp

#include "MyApp.h"

IMPLEMENT_APP(MyApp)

bool MyApp::OnInit()
{
    /// 1.创建窗口
    wxFrame * mainWnd = new wxFrame(NULL, wxID_ANY, wxT("main window"));                    

    /// 2.将窗口设置为程序主窗口
    SetTopWindow(mainWnd); 

    /// 3.显示窗口。
    mainWnd->Show(true);   

    return true;
}

至此,代码完毕,编译执行后可以得到预期的界面。但是,此程序只是显示了界面要素,并未执行消息处理。后续还将在此基础上添加消息处理部分。

上述程序需注意的有以下几点:
(1)wxToolBar的AddTool函数,在3.0.2版本后应使用建议的函数签名,以避免编译器告警。
(2)wxToolBar在调用完AddTool增加按钮后,必须调用Realize()函数,以使工具栏更新。
(3)可以利用wxArtProvider获取预定义的图像资源。


上述程序的wxPython版本如下(也不复杂):

/// MyApp1.py

import wx

class MyFrame(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self, None, -1, "main window")

        #1.增加菜单栏
        menuBar = wx.MenuBar()

        menu1 = wx.Menu()
        menu1.Append(-1, "subitem 1-1")
        menu1.Append(-1, "subitem 1-2")
        menuBar.Append(menu1, "item 1")

        menu2 = wx.Menu()
        menu2.Append(-1, "subitem 2-1")
        menu2.Append(-1, "subitem 2-2")
        menuBar.Append(menu2, "item 2")    

        self.SetMenuBar(menuBar)

        #2.增加工具栏
        toolBar = wx.ToolBar(self)
        toolBar.AddTool(-1, wx.ArtProvider.GetBitmap(wx.ART_GO_BACK, wx.ART_TOOLBAR))
        toolBar.AddTool(-1, wx.ArtProvider.GetBitmap(wx.ART_TIP, wx.ART_TOOLBAR))
        toolBar.AddSeparator()
        toolBar.AddTool(-1, wx.ArtProvider.GetBitmap(wx.ART_UNDO, wx.ART_TOOLBAR))
        toolBar.Realize()
        self.SetToolBar(toolBar)

        #3.增加状态栏
        statusBar = self.CreateStatusBar(3)
        statusBar.SetStatusText("this is pane 0", 0)
        statusBar.SetStatusText("this is pane 1", 1)
        statusBar.SetStatusText("this is pane 2", 2)



if __name__ == "__main__":
    app = wx.App()
    mainWnd = MyFrame()
    app.SetTopWindow(mainWnd)
    mainWnd.Show()

    app.MainLoop() #启动消息循环

添加消息处理

wxWidgets消息处理主要有两种模式:
(1)静态绑定消息处理函数
一是类似MFC的预定义模式。通过DECLARE_EVENT_TABLEBEGIN_EVENT_TABLEEND_EVENT_TABLE等宏,将消息映射至指定的函数。
下面用一个例子来说明事件相关的宏的定义和使用.

/// MyFrame.h

class MyFrame : public wxFrame
{
    DECLARE_EVENT_TABLE()

public:
    MyFrame();

public:
    void OnItem1(wxCommandEvent & evt);
};
/// MyFrame.cpp

BEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_MENU(ID_ITEM_1, OnItem1)
END_EVENT_TABLE()

…

void MyFrame::OnItem1(wxCommandEvent & evt)
{
    wxMessageBox(wxT("item 1"));
}

上面的例子中,将ID为ID_ITEM_1的菜单事件绑定至MyFrame的OnItem1函数。选择该菜单项后,将会调用MyFrame的OnItem1函数。

(2)动态绑定消息处理函数
通过调用Bind函数,将消息绑定至指定的处理函数(函数对象)。
下面用一个例子来说明Bind的使用方法:

/// MyFrame.cpp

MyFrame::MyFrame(...)
{
    Bind(wxEVT_COMMAND_MENU_SELECTED, &MyFrame::OnExit, this, wxID_EXIT);
}

上面的例子中,将ID为wxID_EXIT的菜单事件绑定至MyFrame的OnExit函数。选择该菜单项后,将会调用MyFrame的OnExit函数。

下面,在前面的窗口程序基础上,分别使用静态和动态绑定方法增加消息处理,形成一个有简单交互的程序。程序在选择不同的菜单项后,会弹出相应的对话框。运行效果如下:
这里写图片描述
下面,分别修改MyFrame.h和MyFrame.cpp程序,代码如下:

/// MyFrame.h

#pragma once

#include "wxInc.h"

class MyFrame : public wxFrame
{
    DECLARE_EVENT_TABLE()

public:
    MyFrame();

public:
    void OnItem1(wxCommandEvent & evt);
    void OnItem2(wxCommandEvent & evt);
};
/// MyFrame.cpp

#include "MyFrame.h"

enum {
    ID_ITEM_1 = wxID_HIGHEST + 1,
    ID_ITEM_2,
    ID_ITEM_3,
    ID_ITEM_4,
    ID_ITEM_5,
    ID_ITEM_6,
    ID_ITEM_7,
};

/// 静态绑定消息处理
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_MENU(ID_ITEM_1, OnItem1)   
END_EVENT_TABLE()

MyFrame::MyFrame() : wxFrame(NULL, wxID_ANY, wxT("main window"))
{
    /// 1. 创建菜单栏
    wxMenuBar * menuBar = new wxMenuBar();

    wxMenu * menu1 = new wxMenu();
    menu1->Append(ID_ITEM_1, wxT("subitem 1-1"));
    menu1->Append(ID_ITEM_2, wxT("subitem 1-2"));
    menuBar->Append(menu1, wxT("item 1"));

    wxMenu * menu2 = new wxMenu();
    menu2->Append(ID_ITEM_3, wxT("subitem 2-1"));
    menu2->Append(ID_ITEM_4, wxT("subitem 2-2"));
    menuBar->Append(menu2, wxT("item 2"));

    SetMenuBar(menuBar);

    /// 2. 创建工具栏
    wxToolBar * toolBar = new wxToolBar(this, wxID_ANY);
    toolBar->AddTool(ID_ITEM_5, wxT("button1"), wxArtProvider::GetBitmap(wxART_GO_BACK, wxART_TOOLBAR));
    toolBar->AddTool(ID_ITEM_6, wxT("button2"), wxArtProvider::GetBitmap(wxART_TIP, wxART_TOOLBAR));
    toolBar->AddSeparator();    
    toolBar->AddTool(ID_ITEM_7, wxT("button3"), wxArtProvider::GetBitmap(wxART_UNDO, wxART_TOOLBAR));
    toolBar->Realize();  /// 在增加按钮后必须调用此函数
    SetToolBar(toolBar);    

    /// 3. 创建状态栏
    wxStatusBar * statusBar = CreateStatusBar(3);
    statusBar->SetStatusText(wxT("this is pane 0"), 0);
    statusBar->SetStatusText(wxT("this is pane 1"), 1);
    statusBar->SetStatusText(wxT("this is pane 2"), 2);

    /// 4. 动态绑定消息
    Bind(wxEVT_COMMAND_MENU_SELECTED, &MyFrame::OnItem2, this, ID_ITEM_2);
}

void MyFrame::OnItem1(wxCommandEvent & evt)
{
    wxMessageBox(wxT("item 1"));
}

void MyFrame::OnItem2(wxCommandEvent & evt)
{
    wxMessageBox(wxT("item 2"));
}

由于Python没有wxWidgets宏定义处理方式,所以需要通过动态绑定消息处理,代码如下:

/// MyFrame.py

import wx

class MyFrame(wx.Frame):

    def __init__(self):

        ID_ITEM1 = wx.ID_HIGHEST + 1
        ID_ITEM2 = wx.ID_HIGHEST + 2        

        wx.Frame.__init__(self, None, -1, "main window")

        #1.增加菜单栏
        menuBar = wx.MenuBar()

        menu1 = wx.Menu()
        menu1.Append(ID_ITEM1, "subitem 1-1")
        menu1.Append(ID_ITEM2, "subitem 1-2")
        menuBar.Append(menu1, "item 1")

        menu2 = wx.Menu()
        menu2.Append(-1, "subitem 2-1")
        menu2.Append(-1, "subitem 2-2")
        menuBar.Append(menu2, "item 2")    

        self.SetMenuBar(menuBar)

        #2.增加工具栏
        toolBar = wx.ToolBar(self)
        toolBar.AddTool(-1, wx.ArtProvider.GetBitmap(wx.ART_GO_BACK, wx.ART_TOOLBAR))
        toolBar.AddTool(-1, wx.ArtProvider.GetBitmap(wx.ART_TIP, wx.ART_TOOLBAR))
        toolBar.AddSeparator()
        toolBar.AddTool(-1, wx.ArtProvider.GetBitmap(wx.ART_UNDO, wx.ART_TOOLBAR))
        toolBar.Realize()
        self.SetToolBar(toolBar)

        #3.增加状态栏
        statusBar = self.CreateStatusBar(3)
        statusBar.SetStatusText("this is pane 0", 0)
        statusBar.SetStatusText("this is pane 1", 1)
        statusBar.SetStatusText("this is pane 2", 2)

        #4.增加消息处理
        self.Bind(wx.EVT_MENU, self.OnItem1, id=ID_ITEM1)
        self.Bind(wx.EVT_MENU, self.OnItem2, id=ID_ITEM2)

    def OnItem1(self, event):
        wx.MessageBox("item 1")
        pass

    def OnItem2(self, event):
        wx.MessageBox("item 2")
        pass

if __name__ == "__main__":
    app = wx.App()
    mainWnd = MyFrame()
    app.SetTopWindow(mainWnd)
    mainWnd.Show()

    app.MainLoop() #启动消息循环
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/penny_hardaway/article/details/44620111
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2019-08-26 23:31:28
  • 阅读 ( 1137 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

推荐文章

猜你喜欢