【发布时间】:2021-07-17 04:15:15
【问题描述】:
我对 wxWidgets 比较陌生,并试图掌握如何正确实现线程和事件以及所有这些好东西。我能够在我的项目目录中运行一个简单的框架,但在尝试添加线程时遇到了问题。
我运行 repo 的“示例”中给出的 Thread 演示没有问题,但据我了解,最近的首选方法是使用 wxThreadHelper,因为您不需要传递帧指针。
我基本上是从here 给出的 wxThreadHelper 示例开始的。我真正做的只是将内容分成 header 和 src。
标题:
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWidgets headers)
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#if !wxUSE_THREADS
#error "This sample requires thread support!"
#endif // wxUSE_THREADS
wxDECLARE_EVENT(EVT_COMMS_UPDATE, wxThreadEvent);
enum {LAYOUT_TEST_PROPORTIONS = wxID_HIGHEST+1,
LAYOUT_TEST_SIZER,
LAYOUT_TEST_NB_SIZER
};
class wxMainFrame : public wxFrame, public wxThreadHelper, private wxLog {
private:
public:
wxMainFrame();
~wxMainFrame(){
// it's better to do any thread cleanup in the OnClose()
// event handler, rather than in the destructor.
// This is because the event loop for a top-level window is not
// active anymore when its destructor is called and if the thread
// sends events when ending, they won't be processed unless
// you ended the thread from OnClose.
// See @ref overview_windowdeletion for more info.
}
void onCommsUpdate_t();
void OnClose(wxCloseEvent& evt);
wxTextCtrl * m_txtctrl;
protected:
virtual wxThread::ExitCode Entry();
//fields update from threads
double data_t;
wxCriticalSection m_dataCS; // protects field above - i don't really know how this thing scopes the CS
wxDECLARE_EVENT_TABLE();
};
SRC:
#include "wxMainFrame.h"
wxDEFINE_EVENT(EVT_COMMS_UPDATE, wxThreadEvent)
wxBEGIN_EVENT_TABLE(wxMainFrame, wxFrame)
EVT_THREAD(EVT_COMMS_UPDATE, wxMainFrame::onCommsUpdate_t)
EVT_CLOSE(wxMainFrame::OnClose)
wxEND_EVENT_TABLE()
wxMainFrame::wxMainFrame() : wxFrame(NULL, wxID_ANY, "wxWidgets Layout Demo") {
//Enable thread
if (CreateThread(wxTHREAD_JOINABLE) != wxTHREAD_NO_ERROR){
wxLogError("Could not create the worker thread!");
return;
}
// go!
if (GetThread()->Run() != wxTHREAD_NO_ERROR) {
wxLogError("Could not run the worker thread!");
return;
}
this->data_t = 0;
// Make a menubar
wxMenu *file_menu = new wxMenu;
file_menu->Append(LAYOUT_TEST_PROPORTIONS, "&Proportions demo...\tF1");
file_menu->Append(LAYOUT_TEST_SIZER, "Test wx&FlexSizer...\tF2");
file_menu->Append(LAYOUT_TEST_NB_SIZER, "Test ¬ebook sizers...\tF3");
wxMenuBar *menu_bar = new wxMenuBar;
menu_bar->Append(file_menu, "&File");
// Associate the menu bar with the frame
SetMenuBar(menu_bar);
// create the logging text control and a header showing the meaning of the
// different columns
wxTextCtrl *header = new wxTextCtrl(this, wxID_ANY, "",
wxDefaultPosition, wxDefaultSize,
wxTE_READONLY);
//DoLogLine(header, " Time", " Thread", "Message");
m_txtctrl = new wxTextCtrl(this, wxID_ANY, "",
wxDefaultPosition, wxDefaultSize,
wxTE_MULTILINE | wxTE_READONLY);
wxLog::SetActiveTarget(this);
// use fixed width font to align output in nice columns
wxFont font(wxFontInfo().Family(wxFONTFAMILY_TELETYPE));
header ->SetFont(font);
m_txtctrl ->SetFont(font);
m_txtctrl->SetFocus(); //Field to have focus on startu
// layout and show the frame
wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL);
sizer->Add(header, wxSizerFlags().Expand());
sizer->Add(m_txtctrl, wxSizerFlags(1).Expand());
SetSizer(sizer);
SetSize(600, 350);
}
wxThread::ExitCode wxMainFrame::Entry(){
// IMPORTANT: this function gets executed in the secondary thread context!
while (!GetThread()->TestDestroy()) {
// since this Entry() is implemented in MyFrame context we don't
// need any pointer to access the m_data, m_processedData, m_dataCS
// variables... very nice!
wxCriticalSectionLocker lock(m_dataCS);
this->data_t++;
// VERY IMPORTANT: do not call any GUI function inside this
// function; rather use wxQueueEvent():
wxQueueEvent(this, new wxThreadEvent(EVT_COMMS_UPDATE));
}
// TestDestroy() returned true (which means the main thread asked us
// to terminate as soon as possible) or we ended the long task...
return (wxThread::ExitCode)0;
}
void wxMainFrame::onCommsUpdate_t(){
//Do thread stuff
//wxCriticalSectionLocker lock(m_dataCS);
//std::cout << this->data_t;
}
void wxMainFrame::OnClose(wxCloseEvent& evt){
// important: before terminating, we _must_ wait for our joinable
// thread to end, if it's running; in fact it uses variables of this
// instance and posts events to *this event handler
if (GetThread() && // DoStartALongTask() may have not been called
GetThread()->IsRunning())
GetThread()->Wait();
Destroy();
}
这会导致这个编译错误:
In file included from /usr/local/include/wx-3.1/wx/wx.h:24,
from includes/wxMainFrame.h:10,
from src/wxMainFrame.cpp:2:
/usr/local/include/wx-3.1/wx/event.h:4350:5: error: expected ‘,’ or ‘;’ before ‘ const’
4350 | const wxEventTable theClass::sm_eventTable = \
| ^~~~~
src/wxMainFrame.cpp:5:1: note: in expansion of macro ‘wxBEGIN_EVENT_TABLE’
5 | wxBEGIN_EVENT_TABLE(wxMainFrame, wxFrame)
如您所见,这是一个基本语法错误,如果我进入 /usr/local/include/wx-3.1/wx/event.h:4350,我可以看到/修复它
但这没有意义,我不能是第一个发现简单语法错误的人吗?我的机器(ubuntu)上一定有问题。这是从make install 添加到我的系统包含的标头,对吗?如果从源代码构建的演示/示例都可以正常工作,将如何出现语法错误。我想只是大声思考。
我使用here 的建议从源代码构建了该库。
我还在 wxWidget 的论坛here 上看到了这篇文章。谁似乎没有我遇到的相同语法问题。而且,我并不真正理解如何使用建议的宏,因为 wiki 说宏实际上是由 wx__DECLARE_EVT2 包装的。如果这是解决方案,也许一个简单的示例将有助于向我展示如何正确使用它。
感谢任何意见。谢谢!
PS 我已经尝试在论坛上发布此问题,但无法注册(尝试使用多个浏览器)所以我在这里。
【问题讨论】: