李北泉 發表於 2025-6-19 11:53:00

在Linux下使用wxWidgets进行跨平台GUI开发(三)

<h2 id="创建wxwidgets应用程序">创建wxWidgets应用程序</h2>
<p>在本文中,我们将了解创建wxWidgets应用程序所需的基础知识。首先创建一个简单的示例程序,展示如何显示图标;接着通过另一个示例演示事件的使用方法;最后探讨wxWidgets应用程序中控件之间的通信机制。</p>
<h3 id="一个简单的应用程序">一个简单的应用程序</h3>
<p>首先我们创建一个非常基础的wxWidgets程序。</p>
<pre><code class="language-cpp">// simple.h
#include &lt;wx/wx.h&gt;

class Simple : public wxFrame
{
public:
    Simple(const wxString&amp; title);

};

// simple.cpp
#include "simple.h"

Simple::Simple(const wxString&amp; title)
       : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(250, 150))
{
Centre();
}

// main.h
#include &lt;wx/wx.h&gt;

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

// main.cpp
#include "main.h"
#include "simple.h"

IMPLEMENT_APP(MyApp)

bool MyApp::OnInit()
{
    Simple *simple = new Simple(wxT("Simple"));
    simple-&gt;Show(true);

    return true;
}
</code></pre>
<p>用CMake构建工具,须编写CMakeLists.txt</p>
<pre><code>cmake_minimum_required(VERSION 3.10)
project(simple)

if(WIN32)
find_package(wxWidgets 3.2 REQUIRED COMPONENTS core base CONFIG)
else()
find_package(wxWidgets 3.2 REQUIRED COMPONENTS core base)
endif()

if(wxWidgets_USE_FILE)                 # not defined in CONFIG mode
include(${wxWidgets_USE_FILE})
endif()

set(SRC_FILES
    main.cpp
    simple.cpp
    )

# Define the build target for the executable, e.g. windows application.
add_executable(${PROJECT_NAME} WIN32 MACOSX_BUNDLE ${SRC_FILES})
target_link_libraries(${PROJECT_NAME} ${wxWidgets_LIBRARIES})

if(MSVC)
target_include_directories(${PROJECT_NAME} PUBLIC "${wxWidgets_INCLUDE_DIRS}/msvc")
endif()

if(CMAKE_SIZEOF_VOID_P EQUAL 8)
message(STATUS "Configuring for 64-bit build.")
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/out)
if(NOT MSVC)
    set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE})
endif()

else()
message(STATUS "Configuring for 32-bit build.")
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/out/b32)
if(NOT MSVC)
    set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/out/b32/${CMAKE_BUILD_TYPE})
endif()
endif()
</code></pre>
<p>现在,生成的可执行程序将会放在out文件夹内部。值得一提的是CMake采用Config模式在Windows下构建wxWidgets应用程序更好用,而在Linux下这个模式反而更麻烦了。<br>
这个非常基础的示例在屏幕上显示了一个小窗口。该窗口位于屏幕中央。<br>
<code>Centre();                //这个方法将窗口在屏幕上水平和垂直居中。</code><br>
<code>IMPLEMENT_APP(MyApp)         //实现应用程序的代码被隐藏在这个宏后面。</code><br>
这段代码通常是复制粘贴复用的,我们一般不需要关心它。<br>
运行效果例如在Linux下将显示<br>
<img src="https://img2024.cnblogs.com/blog/3002049/202506/3002049-20250619114459864-600398672.png"></p>
<h3 id="应用程序图标">应用程序图标</h3>
<p>在本示例中,我们为应用程序提供了一个图标。在窗口左上角显示小图标已成为标准做法,该图标是程序的图形标识。</p>
<pre><code class="language-cpp">// icon.h
#include &lt;wx/wx.h&gt;

class Icon : public wxFrame
{
public:
    Icon(const wxString&amp; title);

};

// icon.cpp
#include "icon.h"

Icon::Icon(const wxString&amp; title)
       : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(250, 150))
{
SetIcon(wxIcon(wxT("web.xpm")));
Centre();
}

// main.h
#include &lt;wx/wx.h&gt;

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

// main.cpp
#include "main.h"
#include "icon.h"

IMPLEMENT_APP(MyApp)

bool MyApp::OnInit()
{
    Icon *icon = new Icon(wxT("Icon"));
    icon-&gt;Show(true);

    return true;
}
</code></pre>
<p>在我们的示例中,我们展示了一个小小的网页图标。<br>
<code>SetIcon(wxIcon(wxT("web.xpm")));</code><br>
只需一行代码即可显示应用程序图标。XPM(X PixMap)是一种ASCII图像格式。</p>
<h3 id="一个简单的按钮">一个简单的按钮</h3>
<p>在以下示例中,我们将在框架部件上创建一个按钮。我们将展示如何创建一个简单的事件处理器。</p>
<pre><code class="language-cpp">// button.h
#include &lt;wx/wx.h&gt;

class Button : public wxFrame
{
public:
    Button(const wxString&amp; title);

    void OnQuit(wxCommandEvent &amp; event);
};

// button.cpp
#include "button.h"

Button::Button(const wxString&amp; title)
       : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(270, 150))
{
wxPanel *panel = new wxPanel(this, wxID_ANY);

wxButton *button = new wxButton(panel, wxID_EXIT, wxT("Quit"),
      wxPoint(20, 20));
Connect(wxID_EXIT, wxEVT_COMMAND_BUTTON_CLICKED,
      wxCommandEventHandler(Button::OnQuit));
button-&gt;SetFocus();
Centre();
}

void Button::OnQuit(wxCommandEvent &amp; WXUNUSED(event))
{
    Close(true);
}

// main.h
#include &lt;wx/wx.h&gt;

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

// main.cpp
#include "main.h"
#include "button.h"

IMPLEMENT_APP(MyApp)

bool MyApp::OnInit()
{

    Button *btnapp = new Button(wxT("Button"));
    btnapp-&gt;Show(true);

    return true;
}
</code></pre>
<p>首先我们创建一个 wxPanel 部件,它将被放置在 wxFrame 部件内部。<br>
我们创建一个 wxButton 部件,将其放置在面板上。我们为按钮使用了预定义的 wxID_EXIT ID,这会使按钮上显示一个小的退出图标。按钮的标签是"退出"(Quit)。按钮被手动定位在坐标 x=20,y=20 处。坐标系的起点位于左上角。<br>
当我们点击按钮时,会生成一个 wxEVT_COMMAND_BUTTON_CLICKED 事件。我们将该事件连接到 Button 类的 OnQuit 方法。因此当我们点击按钮时,就会调用 OnQuit 方法。<br>
我们将键盘焦点设置在该按钮上。这样当我们按下回车键时,就会触发按钮的点击事件。<br>
在 OnQuit 方法内部,我们调用了 Close 方法。这将终止我们的应用程序。<br>
(补充说明:在 wxWidgets 框架中,调用 Close() 方法会触发 wxEVT_CLOSE_WINDOW 事件,该事件的默认处理程序会调用 wxWindow::Destroy() 来销毁窗口。对于应用程序的主窗口来说,这会进一步导致整个应用程序退出,前提是没有其他顶级窗口存在。这是 wxWidgets 应用程序的标准退出流程之一)</p>
<h3 id="组件通信">组件通信</h3>
<p>了解组件如何在应用程序中进行通信非常重要。请看以下示例。</p>
<pre><code class="language-cpp">// Panels.h
#include &lt;wx/wx.h&gt;
#include &lt;wx/panel.h&gt;

class LeftPanel : public wxPanel
{
public:
    LeftPanel(wxPanel *parent);

    void OnPlus(wxCommandEvent &amp; event);
    void OnMinus(wxCommandEvent &amp; event);

    wxButton *m_plus;
    wxButton *m_minus;
    wxPanel *m_parent;
    int count;

};

class RightPanel : public wxPanel
{
public:
    RightPanel(wxPanel *parent);

    void OnSetText(wxCommandEvent &amp; event);

    wxStaticText *m_text;

};

const int ID_PLUS = 101;
const int ID_MINUS = 102;


// Panels.cpp
#include &lt;wx/stattext.h&gt;
#include "Communicate.h"

LeftPanel::LeftPanel(wxPanel * parent)
       : wxPanel(parent, -1, wxPoint(-1, -1), wxSize(-1, -1), wxBORDER_SUNKEN)
{
count = 0;
m_parent = parent;
m_plus = new wxButton(this, ID_PLUS, wxT("+"),
      wxPoint(10, 10));
m_minus = new wxButton(this, ID_MINUS, wxT("-"),
      wxPoint(10, 60));
Connect(ID_PLUS, wxEVT_COMMAND_BUTTON_CLICKED,
      wxCommandEventHandler(LeftPanel::OnPlus));
Connect(ID_MINUS, wxEVT_COMMAND_BUTTON_CLICKED,
      wxCommandEventHandler(LeftPanel::OnMinus));
}

void LeftPanel::OnPlus(wxCommandEvent &amp; WXUNUSED(event))
{
count++;

Communicate *comm = (Communicate *) m_parent-&gt;GetParent();
comm-&gt;m_rp-&gt;m_text-&gt;SetLabel(wxString::Format(wxT("%d"), count));
}

void LeftPanel::OnMinus(wxCommandEvent &amp; WXUNUSED(event))
{
count--;

Communicate *comm = (Communicate *) m_parent-&gt;GetParent();
comm-&gt;m_rp-&gt;m_text-&gt;SetLabel(wxString::Format(wxT("%d"), count));
}


RightPanel::RightPanel(wxPanel * parent)
       : wxPanel(parent, wxID_ANY, wxDefaultPosition,
         wxSize(270, 150), wxBORDER_SUNKEN)
{
    m_text = new wxStaticText(this, -1, wxT("0"), wxPoint(40, 60));
}


// Communicate.h
#include "Panels.h"
#include &lt;wx/wxprec.h&gt;


class Communicate : public wxFrame
{
public:
    Communicate(const wxString&amp; title);


    LeftPanel *m_lp;
    RightPanel *m_rp;
    wxPanel *m_parent;

};


// Communicate.cpp
#include "Communicate.h"

Communicate::Communicate(const wxString&amp; title)
       : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(290, 150))
{
m_parent = new wxPanel(this, wxID_ANY);

wxBoxSizer *hbox = new wxBoxSizer(wxHORIZONTAL);

m_lp = new LeftPanel(m_parent);
m_rp = new RightPanel(m_parent);

hbox-&gt;Add(m_lp, 1, wxEXPAND | wxALL, 5);
hbox-&gt;Add(m_rp, 1, wxEXPAND | wxALL, 5);

m_parent-&gt;SetSizer(hbox);

this-&gt;Centre();
}


// main.h
#include &lt;wx/wx.h&gt;

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

// main.cpp
#include "main.h"
#include "Communicate.h"

IMPLEMENT_APP(MyApp)

bool MyApp::OnInit()
{

    Communicate *communicate = new Communicate(wxT("Widgets communicate"));
    communicate-&gt;Show(true);

    return true;
}
</code></pre>
<p>在我们的示例中,我们有两个面板:左侧面板和右侧面板。左侧面板有两个按钮,右侧面板有一个静态文本控件。这些按钮可以改变静态文本中显示的数字。现在的问题是:我们如何获取指向该静态文本控件的指针?<br>
我们保存了指向 LeftPanel 父部件的指针,该父部件是一个 wxPanel 组件。<br>
<code>Communicate *comm = (Communicate *) m_parent-&gt;GetParent();</code><br>
<code>comm-&gt;m_rp-&gt;m_text-&gt;SetLabel(wxString::Format(wxT("%d"), count));</code><br>
这两行代码是本示例中最关键的部分,它们展示了如何访问位于另一个面板上的静态文本控件。首先我们获取左右两个面板的父部件,这个父部件持有指向右侧面板的指针,而右侧面板又保存着指向静态文本控件的指针。在wxWidgets框架中,这种通过父窗口访问同级控件的模式是跨面板通信的典型实现方式。<br>
至此,在wxWidgets教程的这一部分中,我们已经创建了一些简单的程序。</p><br><br>
来源:https://www.cnblogs.com/bokong/p/18936227
頁: [1]
查看完整版本: 在Linux下使用wxWidgets进行跨平台GUI开发(三)