GTK+, how to update widgets into mainloop? - c++

My program work with 2 threads (boost::thread) and, of course, 1 mainloop.
The problem is that I currently update 2 widgets at the end of each threads, and thoses updates sometime provoke segmentations faults.
I use the function "gtk_widget_queue_draw" to update widgets into my threads.
I saw somewhere on the web that we must update all of our widgets into the main loop and never into threads, so my question is simple, how do I do that ?
With signals maybe ?
I already tried with the fundtion "g_idle_add" but it don't work either.
It seems that I can also use gtk_thread_enter and gtk_thread_leave but thoses two functions are deprecated.
Thanks
Edit: I almost forgot; if I want to update manually my widgets, it's because they don't updates automatically (and one of thoses widgets is a chart drawn with cairo)
"g_idle_add" seem to be the good way to do that, but it ends up with segmentation fault too.
Here is the way I implemented this:
In my thread:
g_idle_add ((GSourceFunc)update_label_monitor_cpu, &string_cpu);
And the function itself:
void update_label_monitor_cpu(std::string *str)
{
std::string tmp = *str;
gtk_label_set_label(GTK_LABEL(label_monitor_cpu), (gchar*)tmp.c_str());
}

g_idle_add() is the correct way to do this. You get a segmentation fault because your strings go out of scope, and are destroyed, before the idle callback ever runs. You'll need to manually manage the memory for the strings in your idle callback; for instance, using g_strdup() and g_free().

Related

Search/Filtering functionality blocks the Main(GUI) thread

I have a custom table and I have implemented a search/filtering function which goes through all the elements in the table and then hides/shows the item in the table depending upon whether that item/element matches the one we are searching for.
For example, let's say I have a text control and I type "wxwidgets" in it then my custom function will go through all the elements in the table and hide the elements that do not match this "wxwidgets" entry. This works fine and I am correctly able to hide/show the elements. But the problem is that this search blocks the main thread(gui) since I am doing this in the main thread. The table has around 1000 entries or can be more in the future. My question is how can I avoid this blocking of the main thread. I am thinking of using another worker thread that will do this searching of elements. But then I read that "no secondary threads should call gui functions". But then how can i show/hide the elements of the table from the worker thread. For example, currently in the main thread I use Show(true) or Show(false) to show/hide a particular entry from the table and all this is done while I am in a for/while loop. But if i implement this(the for loop) in a worker thread then according to the quoted advice i should not use the Show() functions from inside that worker thread. What can be done in this situation? Also, is there any other way/advice of doing this searching for elements of the table. I am thinking of starting a new detachable thread every time the user enters some text in the text field. And then delete that old thread if the user appends some more text to the text field and start a new thread which starts searching from the beginning. Is this the right solution for this?
The problem is that inside my for loop i am using the wxWidgets functions. For example, this is what my for loop looks like:
void AnotherClass::onTextChanged(wxCommandEvent &event)
{
for(int i = 5; i<154;++i)
{
SomeClass *element = dynamic_cast<SomeClass*>(FindWindowById(i));
if(element.GetLabel() == textEnteredInTextCtrl)
{
element.Show(true);//element found
//update the necessary layout here using layout call
}
else
{
element.Show(false);//element not found
//update the necessary layout here using Layout() call
}
}
}
This is the main part of the search. Now inside the workerthread should/can i use the functions like FindWindowById() and GetLabel()? Are they considered GUI functions or not so that I can use them from the worker thread? Can i or can i not use FindWindowByID() and GetLabel() and other similar functions(like Layout() and Show()) from inside the worker thread. How should I make this work? I mean I know how to use wxThread and send events using QueueEvent and already have another worker thread in my program that does some other calculation but I am asking about how I should make it work in this particular case.
Another solution suggested by QuentinC would be to use a timer. His suggestion is as follows:
In my case, I don't start refreshing the list immediately after the
user has typed a letter in the search box. Instead, when the user has
typed a letter (wxEVT_TEXT), I start or restart a timer of 500ms. Only
when the timer goes out (the user stops typing for 500ms) then the list
is refreshed. Again, this is a measure to avoid a rapid succession of
useless refreshes.
But in this case of using a timer i have several queries. I am sending the wxEVT_TEXT from CustomTextCtrl's onTextChanged method to this class' onTextChanged method. I guess i could start the timer of 500ms inside the onTextChanged method of the CustomTextCtrl class when the user types a letter. But then where should i check that the timer is still running? In the CustomTextCtrl's onTextChanged method or inside the AnotherClass's onTextChanged method?
So for clarification i have two classes:
the CustomTextCtrl class which have a onTextChanged method which uses event.Skip() to forward this event to its parent.
The parent class AnotherClass which also have a onTextChanged method and this method receives this forwarded event and do the searching and updates the table.
Where and how should i start/restart/stop the timer to update the UI?
NOTE: The process of filtering the elements is working perfectly but the only problem is that the main(GUI) thread is blocked when the user type some text inside the textctrl. After lets say 6 or 7 seconds, the text appears inside the textctrl and the UI is updated. I don't want this unresponsiveness of the main UI for 6-7 seconds.
Also, note that i am not using any wxList/wxGrid. I am just using wxPanels and wxStaticText and using show/hide on them.
Edit: One improvement in the code above is that to only use Layout() call from outside the for loop. If i use the Layout() calls from outside the for loop then the search functionality works almost instantly. But this(method) still has the potential of blocking the main thread in the future if the table has many more elements. So i want to use a thread or a timer method. But i don't know how the secondary thread could use the gui functions or how can/should i use a wxTimer method(if any) to solve this problem.
I have several thoughts on this subjet
A) If you have a speed issue, then you better profile your code, to see where the bottle neck is.
B) Calling GDI functions from a not-main thread is risky. Maybe just asking for window-id and its label is not that dangerous, but I think calling Show() definitely is.
C) This piece of code is mainly GUI related. I don't think a worker thread is useful here. But stacking similar callings may improve its speed. For this, I have three advises:
Use CallAfter() passing the elemnt.Show() method
Use Freeze() before the loop and Thaw after it.
Call Layout()only once, right after the loop. About this I wonder if Show()/Hide() controls is better than Enable()/Disabñe()
D) Because you call FindWindowById() so many times, and also many user changes, it will be better to cache all affected windows in a container (a std::map with id as the key). Then, inside the loop use the container instead of 'FindWindowById()`.
E) As a last resource, if the GUI is still blocked, use wxYield() every xxx (say 100) loop-iterations. Depending of pending messages this solution may get things worse (reentrances, crossed effects, etc).

use QGridLayout::addWidget with mutythread

Since creating widgets takes a lot of time, I try to create widgets in different threads and add them to the main layout, but that fails. When creating widgets and then adding them sequentially, the program works normally. Notifications I received: "QObject::setParent: Cannot set parent, new parent is in a different thread"
Is there a way to do it?
No, there is no way to do it.
Qt GUI classes including QWidget must be used only from the main thread.
Quoting Qt documentation:
Although QObject is reentrant, the GUI classes, notably QWidget and
all its subclasses, are not reentrant. They can only be used from the
main thread. As noted earlier, QCoreApplication::exec() must also be
called from that thread.
This is enforced in Qt code by a Q_ASSERT_X when you construct a QWidget:
Q_ASSERT_X(q->thread() == qApp->thread(), "QWidget",
"Widgets must be created in the GUI thread.");
So, even if you would find some work around to make it work, you would not have any guarantee that your code will work in a reproducible way and that any Qt update will not break your code.
Regarding your specific problem, creating widgets should not be time consuming. I can think of 2 reasons why it would be time consuming:
Your widgets are doing heavy computation when you create them. Then you shoul put the computation, and only the computation, in another thread.
You are creating a lot of widgets in one shot. The you can deffer the creation using the event loop. Basically, you create some widgets then post an event or set a timer that will create some more widget, etc. until you meet some stop conditions.

Understanding OpenSceneGraph AddChild in an other thread

I am replacing the OpenGL code of my C++ app with code that uses OpenSceneGraph.
The app is based on Qt and using Qt Threads.
The main thread is calling the viewer->frame() while other threads are loading data.
Those threads directly works whith my scene graph, adding node with addChild().
But sometimes this group->addChild call make my app crash. I Can see, in the stacktrace, the group's vector containing the children is resizing.
I guess that I'm not supposed to add childrens in one thread while another may be drawing it. Am I right ?
What is the best way to do it ? Using a update callback ? Locking the main thread ?

Changing QLineEdit TextBox's inside of loop dynamically

I'm building some code where I'm running a while loop and, within the loop, am trying to change the contents of a couple of textboxes with QLineEdit's setText(). However, merely calling setText within the loop does not work; the textboxes only change their actual value once the code has run through, instead of at each iteration.
I have little experience with C++ or Qt, but the project I'm working on must use them. Any help?
EDIT: I'm guessing this must be something simple that I simply am having troubles because of my lack of familiarity/knowledge, but if more information is needed I'll gladly provide it!
The problem is that QT needs control to return to the UI thread's event loop in order to update the QLineEdit's visual appearance. The quick and dirty way to run the event loop is to add QCoreApplication::processEvents() after each call to setText(). The proper way to fix it is to move the blocking process that sets the value of the text box into another thread, expose an updateText(QString text) signal, connect it to the TextBox's setText(const QString & text) slot and emit that signal whenever you want the text to be updated.
Please see my answer to a similar question for more detail: unexplained delay after QProgressBar finish loading
You might also want to check out some of the documentation on QThreads and the Qt signal slot system: http://harmattan-dev.nokia.com/docs/library/html/qt4/threads-qobject.html
In my case, calling only repaint() or processEvents() won't do the job.
Within your function loop, call both QCoreApplication::processEvents(); and repaint();:
for (i;...)
{
//do your calculations
//...
QCoreApplication::processEvents();
repaint();
}
Calling ui->mywidget->update() didn't make any different as well.
(Tested for Qt4.8.3 on Kubuntu 12.10 and Qt5.0.1 on Windows XP)

C++ WxWidgets: Redirecting Stdout to a wxTextCtrl across mulitple threads

My application is a multi threaded app (using wxThreads). At the moment, the main thread along with it's child worker threads are outputting various messages to Stdout (using cout).
I have a new frame/window with a wxTextCtrl, and would like to redirect all the StdOut messages in to it.
GuiLogFrame *logframe;
logframe = new GuiLogFrame(NULL, wxID_ANY, wxEmptyString);
logframe->Show();
logredirector = new wxStreamToTextRedirector(logframe->get_log_textctrl());
This doesn't work. But if I replace the last line
wxStreamToTextRedirector redir(logframe->get_log_textctrl());
The standard out will be redirected to the logframe wxTextCtrl as long as redir is in scope... I want it to stay even when it goes out of scope.
What I want is the wxStreamToTextRedirector to stay intact the entire time the application is running... so even the new thread's cout will also redirect in to the same wxTextCtrl.
Any thoughts?
One thing that is very important to know is that GUI operations should only be done on the main thread; if you don't, it will crash or lock up when you have more than one GUI operation happening at the same time. This is definitely true under windows, but I believe it applies to all platforms. What you will need to do is post an event to the control using GetEventHandler()->AddPendingEvent. Then wx will add the event to the object's queue and when the main thread runs, it can do the GUI operation.
This might not be the exact answer to your question, but it is relevant information.
I found one way of doing it but I didn't try it out in a multi-threaded app.
You can create a pointer to the wxStreamToTextRedirector on a constructor() using new.
And then, don't forget to delete the pointer in the destructor.
wxStreamToTextRedirector is a RAII class associating the stream with the text control in its ctor and breaking the association in its dtor. You can, of course, create it on the heap instead of using it as a local variable or even just manually do what its ctor/dtor do, i.e. call ostr.rdbuf(text) and restore the original value of rdbuf() at some later time.
However, as arolson101 wrote, you'd still could have a problem in your code if you allow multiple threads use the same wxTextCtrl and simple redirection won't help you with this. You would need to write your own custom streambuf-derived class which would avoid outputting the text immediately but post a message to the main GUI thread asking it to do it, which is not completely trivial.