wxWidgets wxThreadHelper Example Question - c++

I'm relatively new to wxWidgets and trying to get a grasp on how to properly implement threading and events and all that good stuff. I was able to get a simple frame running in my projects directory just fine, but as I ran into issues when trying to add in threading.
I ran the Thread demo given in the "samples" of the repo without issue but as I understand it, the more recent preferred method is to use wxThreadHelper because you don't need to pass around frame pointers.
I'm essentially starting off in the wxThreadHelper example that's given here. All I really did was separate things into header and src.
Header:
// 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 &notebook 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();
}
Which results in this compilation error:
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)
As you can see this is a basic syntax error that I can see/fix if I go into /usr/local/include/wx-3.1/wx/event.h:4350
but this doesn't make sense, I can't be the first person to find a simple syntax error? Something must be wrong on my machine (ubuntu). This is the header that's added to my sys includes from make install right? How would a syntax error appear if the demos/Samples built from the source all work fine. Just thinking out loud I suppose.
I built the lib from source using the suggestions from here.
I also saw this post on wxWidget's forum here. Who didn't seem to have the same syntax issue I'm having. But also, I didn't really understand how to use the suggested macro because the wiki says the macro is actually wrapped by wx__DECLARE_EVT2. If this is the solution perhaps a simple example would be helpful to show me how to use it properly.
I appreciate any input. Thanks!
PS I've tried posting this question on the forum but was unable to register (tried with multiple browsers) so here I am.

There are many issues here. First, the compilation error you mention is due to a missing semicolon, the line:
wxDEFINE_EVENT(EVT_COMMS_UPDATE, wxThreadEvent)
should be
wxDEFINE_EVENT(EVT_COMMS_UPDATE, wxThreadEvent);
Second, the onCommsUpdate_t method needs to take a wxThreadEvent& parameter
void onCommsUpdate_t(wxThreadEvent&);
Obviously, the definition for the method needs to be updated too.
Third, I honestly don't how the EVT_THREAD macro is supposed to work, but I know the line
EVT_THREAD(EVT_COMMS_UPDATE, wxMainFrame::onCommsUpdate_t)
doesn't work. The easiest way to handle a thread event is to use the Bind method. Add a line like this to the frame constructor to handle the event
Bind(EVT_COMMS_UPDATE,&wxMainFrame::onCommsUpdate_t,this);
Fourth, as written, your wxMainFrame::Entry method will be constantly spamming the event queue freezing up the application. In a real application, presumably the thread will do some work before queuing each event. Since in this example, no work is being done, you should add a line like
wxMilliSleep(500);
to the end of the while loop to make the thread sleep for a little bit before sending each event.
Fifth, you never actually signal your thread to shutdown and it never shuts down on its own. Consequently the line GetThread()->Wait(); will be an infinite loop. There are many ways to signal the thread, but the easiest might be to add a bool member named something like m_shutdown to the frame class. Then
a. initialize m_shutdown to false in the frame constructor.
b. In the wxMainFrame::OnClose, use the critical section to set it to true before calling Wait:
if (GetThread() && // DoStartALongTask() may have not been called
GetThread()->IsRunning())
{
{
wxCriticalSectionLocker lock(m_dataCS);
m_shutdown = true;
}
GetThread()->Wait();
}
c. In the wxMainFrame::Entry method, add a check for the value of m_shutdown in the while loop (guarded by the critical section).
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++;
if ( m_shutdown )
break;
}
...
Sixth, I don't know what the line
wxLog::SetActiveTarget(this);
is supposed to do, but it causes a crash at program exit. If you need this, you'll need to store the initial log target and restore it either in the frame destructor or in the close event handler.

Related

How can I execute the function when button in wxYES_NO is pressed?

Maybe my title is unclear, so I will tell here a more precise explanation:
I am just learning WxWidgets, and I am now trying to make two files: main.cpp and Quit.h. Main.cpp will have the core of the application, and Quit.h will have the class for the quit dialog: Do you really want to quit this application (Yes / No).
Now this is my Quit.h file (without include part):
class Quit : public wxFrame
{
public:
Quit(const wxString& tekst);
};
Quit::Quit(const wxString& tekst)
{
wxMessageDialog* dial = new wxMessageDialog(NULL, _("Do you really want to quit?"), _("Quit"), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION);
dial->ShowModal();
}
And here I am stuck. I tried with wxDECLARE_EVENT_TABLE(), but I don't know which event stands for this: "on the press of yes button (in wxYES_NO system of buttons)". I can't say: on the press of wxYES_NO because these are two buttons (both YES and NO).
So how can I execute the function when the button YES is pressed?
Thank you!
P.S.
I really apologize for this unclear question, but I hope, that you'll understand. Note that I am just a beginner, so please don't use so many "technical" words and expressions in the answer. I read the documentation, but it uses so many technical expressions and explanation. Also, I read this book.
P.P.S.
Have you noticed that there are a lot of questions on SE now, while there is COVID-19 on its way?
EDIT: When I was making the program on, I came to the other error. Minimal code:
Quit.h
class Quit : public wxFrame
{
public:
Quit(const wxWindow* parent, const wxString& text);
};
Quit::Quit(const wxWindow* parent, const wxString& text)
{
int dialog_return_value = wxNO;
wxMessageDialog* dial = new wxMessageDialog(NULL, text, _("Exit"), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION);
dialog_return_value = dial->ShowModal();
switch (dialog_return_value)
{
case wxYES:
Close(true);
break;
case wxNO:
Close(false);
break;
default:
Close(false);
};
}
and then I have this line in main.cpp:
void MyFrame::CloseWindow(wxCommandEvent& event)
{
Quit* quit = new Quit(this, _("Do you really want to close the App?"));
}
And then it doesn't work. I can't find the solution, so, if you have some time, please help.
Thank you again!
I would suggest using the wxEvtHandler::Bind<>() function as detailed in the wxWidgets documentaton at https://docs.wxwidgets.org/3.0/overview_events.html. The Bind() function allows dynamic binding of events and the syntax is one line of code as compared to setting up tables to link events to objects.
Additionally see this wxWidgets user forum thread which has detailed explanation for calling member and nonmember methods https://forums.wxwidgets.org/viewtopic.php?t=39817
wxYES_NO is a style flag that tells wxWidgets framework that you want both yes and no buttons in your dialog. Check if the return value of ShowModal() is equal to one of the builtin macros defined as wxYES and wxNO.
See here for the macro definitions https://docs.wxwidgets.org/trunk/defs_8h.html
And you should read up on wxDiaglog. Start here https://docs.wxwidgets.org/trunk/classwx_dialog.html
Do you want to return the value to the caller of Quit::Quit()? Constructors do not return values, you can set a member variable to the value but remember that if the object is destroyed then your member variable is gone too. You have not provided enough information to know what needs to be done for cleanup when you Quit() so I will provide you with the code to check the return value, just fill in what you need in the case body.
Here is how you would check the return value:
class Quit : public wxFrame
{
public:
Quit(const wxString& tekst);
};
Quit::Quit(const wxString& tekst)
{
int dialog_return_value = wxNO; // initialize to a sane default value
wxMessageDialog* dial = new wxMessageDialog(NULL, _("Do you really want to quit?"), _("Quit"), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION);
dialog_return_value = dial->ShowModal();
// You do not have cancel button so only check wxYES and wxNO
switch( dialog_return_value) // Use switch, scales to more buttons later
{
case wxYES :
/* do something */
break;
case wxNO :
/* do something */
break;
default : /* ignore or handle error */ ;
};
}
You are doing a technical task, it is reasonable to expect that learning "technical" words will be involved.
I checked the code return values are not the same as the input style values, we need to check the return value with wxID_YES instead of wxYES!
I was trying to stick to using as much as possible your code but it makes no sense to me using a plain class to close the application. In that case with wxWidgets you still need to reference your main frame to accomplish the closure. There are easier ways as shown in the example below.
Following is a full working example of an application which simply has a quit button on a frame. You click the button and get the quit message dialog. wxWidgets allows creating dialogs on the stack as opposed to the heap and that is what you need here because the dialog is trivial and will not be reused.
You can copy/paste/compile/run the following code as long as you are using wxWidgets 3+ (I am pretty sure Bind() was added then, may have been slightly earlier)
#include <wx/wx.h>
// toolkit requires defining a wxApp class, OnInit() will be called automatically
// when the wxIMPLEMENT_APP macro is invoked below
class MyApp : public wxApp
{
public:
virtual bool OnInit();
};
class MyFrame : public wxFrame
{
public:
MyFrame();
~MyFrame();
private:
void OnExit( wxCommandEvent& event );
// these pointer are owned by the wxWidgets toolkit, do not delete them
// but you need them in a "real" app to add items to the sizer or change
// button properties
wxSizer* m_frame_sizer;
wxButton* m_quit_button;
};
// toolkit requires calling this macro with a wxApp object to bootstrap the GUI framework
wxIMPLEMENT_APP( MyApp );
// OnInit is loosely synonymous with main(), it is where the GUI thread is started
bool MyApp::OnInit()
{
// Create a frame with button
MyFrame* frame = new MyFrame();
// Show the frame with its button
frame->Show( true );
// If return value is false, the wxWidgets framework will kill the app
return true;
}
MyFrame::MyFrame() : wxFrame( NULL, wxID_ANY, "Test Exit" )
{
// wxWidgets requires all controls to be placed in a sizer
m_frame_sizer = new wxBoxSizer( wxVERTICAL );
// Assign the sizer to the frame
this->SetSizer( m_frame_sizer );
m_quit_button = new wxButton( this, wxID_EXIT, "Quit" );
// Put the button into the sizer
m_frame_sizer->Add( m_quit_button, wxSizerFlags().Center() );
// Here we bind the button click event to the OnExit method of MyFrame
// keep in mind that this technique will bind all buttons with id wxID_EXIT to the method
// m_quit_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MyFrame::OnExit, this) will also work
// to handle the event for just the m_quit_button (notice the lack of wxID_EXIT, it is not needed in this case)
Bind( wxEVT_COMMAND_BUTTON_CLICKED, &MyFrame::OnExit, this, wxID_EXIT );
}
MyFrame::~MyFrame()
{
// for illustration, not strictly needed here becasue the entire app is shutting down
Unbind( wxEVT_COMMAND_BUTTON_CLICKED, &MyFrame::OnExit, this, wxID_EXIT );
// OR m_quit_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MyFrame::OnExit, this) for the alternative form
}
void MyFrame::OnExit( wxCommandEvent& event )
{
// Setup a message box with (in order below) the user query text, a title, and style which puts yes/no button and a question mark icon
// Create the message box on the stack as opposed to the heap becasue we only need it here
int answer = wxMessageBox( "Do you rally want to quit?", "Exit App", wxYES_NO | wxICON_QUESTION );
if( answer == wxYES )
{
this->Close( true );
}
// else just return
}
wxYES is a different value than wxID_YES (the codes are 2 vs. 5103). wxMessageDialog::ShowModal returns "one of wxID_OK, wxID_CANCEL, wxID_YES, wxID_NO or wxID_HELP". So the switch statement as written will always trigger the default case. This applies for wx3.1- hopefully those variables will be consolidated in the future as the redundant values do lend themselves to mistakes.
For completeness, the provided switch statement should be:
switch (dialog_return_value)
{
case wxID_YES: //Subtly different from wxYES
Close(true);
break;
case wxID_NO: //Not wxNO
Close(false);
break;
default:
Close(false);
};

QT - Mainwindow doesn't update unless it's closed

I'm trying to update the main window by calling updateGUI function in a thread every 500 ms. The window is displayed but not updated with the new values unless I close the window. When I do so, a new window is opened with the new value. I found this question but it didn't answer my question. I knew that (as stated in qt documentation)
QApplication::exec enters the main event loop and waits until
exit() is called.
I tried to use processEvents() but the main window is opened and closed repeatedly and very fast that I can't even see it. Here is my code:
float distanceToObject;
bool objectDetected;
Modes currentMode;
void timerStart(std::function<void(void)> func, unsigned int interval)
{
std::thread([func, interval]()
{
while (true)
{
auto x = std::chrono::steady_clock::now() + std::chrono::milliseconds(interval);
func();
std::this_thread::sleep_until(x);
}
}).detach();
}
int updateGUI(void)
{
int argc = 0;
char **argv = NULL;
QApplication a(argc, argv);
MainWindow w;
// Set text of a label
w.setDistance(QString::number(distanceToObject));
// Also update objectDetected and currentMode values
w.show();
//a.processEvents();
return a.exec();
}
void sendMsg(void)
{
// Send heartbeat signal to another device
}
void receiveMsg(void)
{
// Read messages from the other device and update the variables
// These two values change continuously
objectDetected = true;
distanceToObject = 5.4;
}
void decide(void)
{
// The core function of the program. Takes relatively long time
// Run a decision-making algorithm which makes decisions based on the values received from the other device.
// Update some variables according to the made decisions
currentMode = Auto;
// Execute functions according to the made decisions.
setMode(currentMode);
}
int main(void)
{
timerStart(updateGUI, 500);
timerStart(sendMsg, 1000);
timerStart(receiveMsg, 10);
timerStart(decide, 500);
}
How can I update the main window with the variables' values correctly?
Your thread does not update the MainWindow, but it does create an entirely new QApplication and MainWindow on every iteration. Your thread should be stuck inside QApplication::exec until you quit the application (e.g. by closing the window). Only then should your thread's loop make further progress.
In general, you must be very careful when doing updates from outside the main thread, since typically GUI operations must be performed inside the main thread.
Think about using QThread, which already comes with its own event loop, which you can use to notify/update your window using a respective slot.
Without further details about what you are actually trying to achieve, it is not possible to give you further direction. I, at least, recommend that you create your QApplication and MainWindow inside the main thread (e.g. main). Then it depends what you are trying to 'update'. If you need to progress some data, then you can do that within your second thread and send the results to your MainWindow instance using signal-slot. If you need to draw onto the window, then this either has to be done in the main thread directly, or you might find a way to render into a separate buffer (i.e. QImage) from within your thread and then send this buffer to the main thread for drawing it into the window.
I try to sketch how something like this can be done. Notice, however, that this it neither complete nor compilable, but merely an outline.
First, you have your MainWindow and add to it a signal, that notifies all observers to start doing their work (will become clear in a moment). Furthermore, you add slots that will be invoked whenever one of your values changes. Those slots run in the main thread (and are members of the MainWindow) and thus can update the window however they need to:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
// constructors and stuff
void startWorking()
{
emit startWorkers();
}
public slots:
void onModeChanged(Modes m)
{
// update your window with new mode
}
void onDistanceChanged(float distance)
{
// update your window with new distance
}
signals:
void startWorkers();
};
Next, you build a Worker class, that encapsulates all the 'background work' you like to do (basically what your thread did in your original code):
class Worker : public QObject
{
Q_OBJECT
public:
// constructors and stuff
public slots:
void doWork()
{
while(!done)
{
// do stuff ...
Modes m = // change mode
emit modeModified(m);
// do stuff ...
float distance = // compute distance
emit distanceModified(distance);
// do stuff ...
}
}
signals:
void modeModified(Modes m);
void distanceModified(float distance);
};
Note, that Worker must inherit QObject and that your doWork method must be a public slot. Furthermore, you add a signal for each of the values you like your MainWindow to be informed about. No implementation for them is needed, since it is generated by the Qt MOC (Meta Object Compiler). Whenever one of the respective values changes, simply emit the corresponding signal and pass the new value.
Lastly, you put everything together:
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
MainWindow window;
// create a worker object
Worker* worker = new Worker;
// connect signals and slots between worker and main window
QObject::connect(worker, &Worker::modeModified,
&window, &MainWindow::onModeChanged);
QObject::connect(worker, &Worker::distanceModified,
&window, &MainWindow::onDistanceChanged);
QObject::connect(&window, &MainWindow::startWorkers,
worker, &Worker::doWork);
// create a new thread
QThread* thread = new QThread;
// send worker to work inside this new thread
worker->moveToThread(thread);
thread->start();
// show window and start doing work
window.show();
window.startWorking();
// start main loop
int result = app.exec();
// join worker thread and perform cleanup
return result;
}
Alright, let's go through it. First, you create your QApplication and MainWindow inside your main thread. Next, create an instance of your Worker object (could create multiple here). Then you connect the signals of the worker to the slots of the window and vice versa. Once these connections are established, whenever you emit a signal, the connected slot is invoked by Qt (and passed values are transmitted). Notice, that this connection works across thread boundaries. Whenever a signal is emitted from a thread different then the receiving object's thread, Qt will send a message, which is processed in the receiving object's thread.
Then you tell Qt that you want your worker to live inside another thread using QObject::moveToThread. See here for a very detailed explanation of how to correctly use QThread and objects inside it.
The rest is then simple. show your window and start processing. Here different ways are possible. I just call the startWorking method here, which then emits the startWorkers signal, which is connect to the worker's doWork method, such that doWork will start executing after this signal is received by the other thread.
You then call QApplication::exec which runs the main thread's event loop, where all these signals are processed by Qt. Once your application is closed (e.g. by calling quit or closing the main window) the exec method returns and you are back in main. Notice, that you need to correctly close the thread (e.g. by sending an addition signal that stops the while loop) and join it. You also should delete all the allocated objects (worker, thread). I omitted this here for simplicity of the code example.
Answering your Question
I have many functions, e.g., updateClips and mavReceive that should be called periodically and run independently from each other. I should create a different Worker class for each function, as each has different signals, and a QThread object for each of these functions, right? I don't need startTimer() anymore? If yes, how can I control the calling interval for each function (used to be done in startTimer()
from the comment:
The answer greatly depends on what exactly you mean by "should be called periodically". Who is supposed to call them? The user? Or should they just be executed periodically?
So in principle, you can have multiple workers in one thread. However, if they are supposed to do work all the time (spin in a while loop) it does not make sense, since one is running and all others are blocked. In that case you would have one thread for each worker.
If I understand you correctly, you are interested in updating something periodically (e.g. every 500ms). In that case I highly recommend using the QTimer. You can set an interval and then start it. The timer will then periodically emit the timeout signal, which you can connect to whatever function (more precisely slot) you want to have executed.
An updated version of the Worker could look like this:
class Worker : public QObject
{
Q_OBJECT
public:
Worker()
{
QObject::connect(&modeTimer_, &QTimer::timeout,
this, &Worker::onModeTimerTimeout);
QObject::connect(&distanceTimer_, &QTimer::timeout,
this, &Worker::onDistanceTimerTimeout);
modeTimer_.start(500); // emit timeout() every 500ms
distanceTimer_.start(100); // emit timeout() every 100ms
}
public slots:
void onModeTimerTimeout()
{
// recompute mode
Modes m = // ...
emit modeModified(m);
}
void onDistanceTimerTimeout()
{
// recompute distance
float distance = // ...
emit distanceModified(distance);
}
signals:
void modeModified(Modes m);
void distanceModified(float distance);
private:
QTimer modeTimer_;
QTimer distanceTimer_;
};
Notice, the connections established in the constructor. Whenever one of the timers times out, the connected slot is invoked. This slot then may compute whatever it needs to and afterwards send the result back to the MainWindow in the main thread using the same signal as before.
So, as you see, you can have multiple timers / re-computations / update signals within one Worker (and thus, one thread). However, the crucial point for an implementation is, how long the computations take. If they take very long (e.g. nearly as long as the intervals) then you should think about using multiple threads to speed up the computation (meaning: perform one computation in each thread). As I slowly seem to get a clearer picture of what you want to achieve, I am wondering whether it is only about these periodic updates that you 'misused' the thread for in your question. If this is indeed the case, then you do not need that thread and Worker at all. Then simply add the timers to your MainWindow and connect their timeout signal to the respective slot of the MainWindow directly.

gtkmm and Gtk::Builder: Lifetime of objects after calling get_widget

I think I must be "doing something wrong" here. I have a program using gtkmm. The main window for the program is a subclass of Gtk::Window and I have the bare bones of the application drawn out in Glade.
Here's an edited version of the main window's constructor:
template<class T>
static T*
get_widget (Glib::RefPtr<Gtk::Builder> builder, const Glib::ustring& name)
{
T* widget;
builder->get_widget (name, widget);
if (! widget) no_such_widget (name);
return widget;
}
app_window::app_window ()
{
Glib::RefPtr<Gtk::Builder> builder;
try {
builder = Gtk::Builder::create_from_file (installed_ui_name);
}
catch (const Glib::FileError& err) {
g_error ("Couldn't open UI definition file at %s",
installed_ui_name);
throw;
}
// main_box is a std::unique_ptr<Gtk::Widget>, a field of app_window.
//
// This works fine: the Gtk::Box gets added as the main child of this
// app_window and survives until the app_window is destroyed.
main_box.reset (get_widget <Gtk::Box> (builder, "main-box"));
add (* main_box);
auto accel_group = get_accel_group ();
// This doesn't work so well
//
// menu_quit is a Gtk::MenuItem*. The object seems to be actually
// constructed for the call to builder->get_widget, because its existence
// stops the menu item from being finalized at the end of the application.
auto menu_quit (get_widget<Gtk::MenuItem> (builder, "menu-quit"));
menu_quit->add_accelerator ("activate", accel_group,
GDK_KEY_q, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE);
using std::bind;
menu_quit->signal_activate ().connect (bind (& app_window::on_close, this));
show ();
}
When setting up the window, I want to register various signal handlers for menu items etc. (the menu_quit widget in the example is just one of them). To do so, I think I need to use builder->get_widget() to get hold of an object to talk about.
The problem is that I've now got an instance of (a subclass of) Gtk::Widget and I don't know what to do with it. If I call delete on the pointer, the widget doesn't appear in the application, but no other problems happen. That's a bit confusing: I would expect either no effect or a segmentation fault (depending on whether something else thought it owned the object or not).
If, on the other hand, I leak the pointer, assuming that object will be owned by the container into which main_box has been added, I get a memory leak. In particular, menu_quit's underlying gtk_image_menu_item doesn't get finalised because the reference count is one too high. (I can check easily enough that with GDB)
A "solution" is to store a pointer to each object that I get with builder->get_widget as a field in the app_window and then delete it in the destructor (automated with std::auto_ptr or std::unique_ptr). But that's really horrible: I don't want to have to write out a field for every single menu item! Avoiding that sort of nonsense was the whole point of using GtkBuilder in the first place!
Assuming that this isn't a bug (gtkmm 3.12.0, if that's relevant), I assume I'm just doing it wrong. How is an application supposed to do this?

How to force Qt to update GUI from not main thread

I'm fighing since last week with problem caused by update of QPlainTextEdit. I'm trying to create separate from QMainWindow Dialog window with QPlainTextEdit inside. The problem begins when I try to use appendHtml signal (also tried with appendText), text that is placed is not visible unless marked by by mouse. Repainting or updating cause in program crash or no visible action.
Simplified code of QDialog with QPlainTextEdit header:
namespace Ui {
class LogWindow;
}
class LogWriter: public QDialog
{
Q_OBJECT
QMutex print_lock;
public:
class Log{
Q_OBJECT
const static int MAX_SIZE = 100;
bool to_terminal;
QString color;
QMutex *print_lock;
QPlainTextEdit *text_place;
QVector< QPair<QString,time_t> > history;
LogWriter * obj;
public:
bool print;
Log(bool _print,QString _color,LogWriter *obj_ = NULL)
{print = _print; color = _color; obj = obj_;}
void setLock(QMutex *print_lock_){print_lock = print_lock_;}
void setTextField(QPlainTextEdit *_text) {text_place = _text;}
Log& operator<<(QString &a);
Log& operator<<(const char* a);
};
static LogWriter* getInstance()
{
static LogWriter instance; // Guaranteed to be destroyed.
// Instantiated on first use.
return &instance;
}
~LogWriter();
Log LOW,MEDIUM,HIGH;
Ui::LogWindow *ui;
signals:
void signalLogAppend(QString);
};
Simplified code of methods definitions:
LogWriter::LogWriter(QWidget * parent): QDialog(parent) {
ui = new Ui::LogWindow;
ui->setupUi(this);
LOW.setLock(&print_lock);
MEDIUM.setLock(&print_lock);
HIGH.setLock(&print_lock);
connect(this,SIGNAL(signalLogAppend(QString)),ui->plainTextEdit,
SLOT(appendHtml(QString)),Qt::DirectConnection);
}
LogWriter::Log& LogWriter::Log::operator<< (QString &s){
history.push_front(qMakePair(s,time(NULL)));
if(history.size() > MAX_SIZE) history.pop_back();
if(print){
//print_lock->lock();
QString text = "<font color=\"";
text += color + "\">";
text += s + "</font>";
//cout << text.toStdString() << endl;
//text_place->appendHtml(text);
//text_place->repaint();
emit (obj)->signalLogAppend(text);
//print_lock->unlock();
}
return *this;
}
I have two separate ui files (first for main window, second for log window).
I have to use log window all across my program (something about 10 threads), and I stucked on this issue. My question is - is it possible to force GUI update without using main thread and if not - what else possibilities I have. If possible I would rather avoid reconstructing all my code - it would take me some time to do it. Right now logging is super easy - I ony need:
LogWindow *log = LogWindow::getInstance();
log->MEDIUM << "something";
As additional info I add QTCreator warning:
QObject::connect: Cannot queue arguments of type 'QTextBlock'
(Make sure 'QTextBlock' is registered using qRegisterMetaType().)
QObject::connect: Cannot queue arguments of type 'QTextCursor'
(Make sure 'QTextCursor' is registered using qRegisterMetaType().)
If I understand your code correctly, you're trying to log from a background thread and are using a direct connection to pass the signal to the GUI thread? That's not going to work, you have to send the signal via the default connection so Qt can figure out that it's a cross-thread signal and pass it across threads accordingly (ie, via the message loop on the foreground thread).
In Qt, any GUI interaction has to happen in the Main/foreground thread otherwise bad things happen as you discovered. You can certainly send a signal from a background thread to trigger a GUI update - I do this all the time - but you need to ensure that you're using the correct connection for it. The direct connection results in a direct function call and is not going to work for you in this case.
In your code, the problem is the call to connect() - you explicitly specify the connection mode for the signal to slot connection when you should just use the default setting. If you set the connection explicitly to Qt::DirectConnection, the underlying code will execute a direct call to the specified slot, which means that you end up calling the slot in the thread context of the signal. You don't want that because the signal is triggered in a background thread.
You can't pass arbitrary types/classes to signals and slots. The list is limited and not all Qt classes are in the list. To add types/classes to the list of those that can be passed to a signal/slot, you must call qRegisterMetaType for that class. I recommend calling it in the constructor of the class you're trying to pass to a signal like this:
MyClass::MyClass() : MyParentClass()
{
static int reg = qRegisterMetaType<MyClass>("MyClass");
}
The static int ensures the registration is only called once and before any instance of MyClass could ever be used.

Closing a QMainWindow on startup?

I have a Qt application that uses a QMainWindow-derived class for the main UI. On startup I want to make some security checks and, if they fail, display a message to the user and close the main window. Currently I make these checks in the QMainWindow constructor, but if I call the close method, nothing happens and the application continues to run. For example:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
setupUi(this);
...
if (checkFails())
{
QMessageBox::warning(this, tr("Error"), tr("You cannot run this app"));
// This has no effect
close();
}
}
Alternatively I could make the checks in the main function but then I lose the ability to display a language-specific message box (the tr macro only works in a QObject-derived class by the looks of things.)
Any ideas on how to close the main window on startup or make the tr macro work outside of a QObject derived class?
The event loop needs to be running before you can successfully close the main window. Since you probably first construct a window, and then start the event loop the close() call has no effect. Try the following solution instead:
QTimer::singleShot(0, this, SLOT(close()));
The QTimer::singleShot() will fire as soon as an event loop has been started, and subsequently calls the close() method on your application main window.
The above solution will probably cause your main application window to be visible for a short period of time, causing unwanted flickering.
A cleaner solution should perform the security checks prior to constructing the main window. Since tr() is also available as a static method on QObject, this can be done from the main function.
Most applications start up in three steps: 1) construct the window; 2) show the window; 3) start the event loop. You can make steps 2 and 3 conditional on the success of step 1 by adding a flag, whose value is set by the window constructor, to the window class:
Window class:
class myMainWindowClass : public QMainWindow
{
Q_OBJECT
public:
myMainWindowClass()
: isFinished_(false) { if (error) isFinished_ = true; } // constructor
bool isFinished() const { return isFinished_; }
private:
bool isFinished_;
}
Application code:
int main()
{
myMainWindowClass main_window(); // Step 1
// Finish early if isFinished flag is set
if (main_window.isFinished())
return 0;
main_window.show(); // Step 2
return a.exec(); // Step 3
}
This should also avoid any flicker as the application will end before the window is show()n.
tr is a public static member of QObject. You should be able to call QObject::tr("Error") in your main function.
Have you tried first hide()ing the window (this should occur anyway when close() is called) to see if this then allows close() to destroy the window.
If this does not work, you could always try destroy(true, true)ing the window along with any sub-windows.