wxWidgets GUI应用程序中的多线程?

4
我在尝试为我的wxWidgets GUI应用程序创建一个工作线程,它将修改GUI属性之一(在这种情况下,是wxTextCtrl :: AppendText),但我遇到了问题(基本上,我感到困惑)。
到目前为止,我有两个源文件和两个头文件用于wx程序本身(不包括我的自己的库,MySQL库等),比如MainDlg.cpp,其中包含一个名为“MainDlg”的wxFrame派生类,以及MainForm.cpp,其中包含一个名为“MainForm”的wxApp派生类。
#include "MainHeader.h" // contains multiple header files

IMPLEMENT_APP(MainForm)

bool MainForm::OnInit()
{
    MainDlg *Server = new MainDlg(wxT("App Server 1.0"), wxDEFAULT_FRAME_STYLE - wxRESIZE_BORDER - wxMAXIMIZE_BOX);
    Editor->Show();

    return true;
}

MainDlg.cpp:

#include "MainHeader.h"

BEGIN_EVENT_TABLE(MainDlg, wxFrame)
EVT_BUTTON(6, MainDlg::StartServer)
EVT_BUTTON(7, MainDlg::StopServer)
END_EVENT_TABLE()

CNETServerConnection *cnServCon;
std::string ServerIP, DBHost, DBUser, DBName, DBPass;
int UserCapacity, DBPort, ServerPort;
MYSQL *sqlhnd;

MainDlg::MainDlg(const wxString &title, long style) : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(301, 230), style)
{
    cnServCon = new CNETServerConnection(100);
    this->InitializeComponent();
}

void MainDlg::InitializeComponent()
{
    this->SetTitle(wxT("App Server 1.0"));
    this->SetSize(396, 260);
    this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
    this->Centre();

    statBox = new wxTextCtrl(this, 4, wxT("Welcome to AppServer 1.0\n\n"), wxPoint(10, 10), wxSize(371, 141), wxTE_MULTILINE | wxTE_READONLY);

    //.................................
}

void MainDlg::StartServer(wxCommandEvent &event)
{
    this->startBtn->Enable(false);
    this->AppendStatus(wxT("\nLoading server configuration... "));

    //.................................

    this->AppendStatus(wxT("OK\n\nServer ready!\n\n"));

    // When the server is ready, I need to run a thread
    // that will update the statBox (through AppendStatus func or wxTextCtrl::AppendText directly)
    // regularly without interrupting the GUI itself.
    // Because the thread will contain a while-loop
    // to make the program keep receiving message from clients.

    this->startBtn->Hide();
    this->stopBtn->Show();
    this->cmdBtn->Enable();
    this->cmdBox->Enable();
}

void MainDlg::StopServer(wxCommandEvent &event)
{
    //...................................
}

void MainDlg::AppendStatus(const wxString &message)
{
    statBox->AppendText(message);
}

// Well, here is the function I'd like to run in a new thread
void MainDlg::ListenForMessages()
{
    int MsgSender = 0;
    while(1)
    {
        if(!cnServCon->GetNewMessage())
            continue;

        if(MsgSender = cnServCon->GetJoiningUser())
            this->AppendStatus(wxT("Someone connected to the server."));
    }
}

我还在C++中线程的简单用法示例中找到了一个使用wxThread的示例:

class MessageThread : public wxThread
{
private:
    MessageThread(const MessageThread &copy);
public:
    MessageThread() : wxThread(wxTHREAD_JOINABLE)
    {
    }

    void *Entry(void)
    {
        // My works goes here
        return;
    }
};

wxThread *CreateThread()
{
        wxThread *_hThread = new MessageThread();

        _hThread->Create();
        _hThread->Run();

        return _hThread;
}

但我不知道如何将它与我的程序关联,并使其能够修改我的 GUI 属性(statBox)。

非常感谢您的任何帮助! :)

谢谢。


1
请注意,Entry 返回的是 ExitCode 而不是 void*。因此,请确保您覆盖了正确的方法(使用 ExitCode)。 - Johannes Schaub - litb
我还想警告您关于wxThread的等待函数。在Windows上,它的等待会阻塞,但仍然处理任意事件。因此,在事件处理程序中,您调用可加入线程的等待,它在等待期间处理事件,然后调用另一个事件处理程序(在wx术语中称为“yielding”),这在我看来是完全愚蠢的。这就是我一直使用另一个修复了这个问题的线程类而不是wxThread的主要原因。 - Johannes Schaub - litb
1个回答

8

最简单的方法是创建一个事件类型id,并使用wxCommandEvent来使用该类型id,设置其字符串成员(“evt.SetText”),并将该事件发送到您的窗口之一(使用AddPendingEvent)。在该事件的处理程序中,您可以使用您发送的文本(evt.GetText)调用AppendText在控件上添加文本,因为此时您已经在GUI线程中。

// in header
DECLARE_EVENT_TYPE(wxEVT_MY_EVENT, -1)

// in cpp file
DEFINE_EVENT_TYPE(wxEVT_MY_EVENT)

// the event macro used in the event table. id is the window id you set when creating 
// the `wxCommandEvent`. Either use -1 or the id of some control, for example. 
EVT_COMMAND(window-id, event-id, handler-function)

这是一个关于它如何工作的概述:自定义事件

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接