I am working on a small Desktop Application in C++ using wxWidgets, it is about visualizing different types of sorting. In order to keep GUI responsive while the sorting is taking place and being drawn on the screen I am trying to do some work on a different thread, but I know that GUI updates must take place from the main thread - so I found a tutorial in which CallAfter
was used so that GUI was updated from the main thread. However, the result I am getting is that the table is being sorted almost immediately (by worker thread) and gets displayed on screen but the GUI freezes for some time and gets updated a lot (nothing changes on the screen as the table gest sorted at the beginning).
Some of the code Im talking about:
#include "GUIMyFrame1.h"
GUIMyFrame1::GUIMyFrame1(wxWindow* parent)
:
MyFrame1(parent), _maxElemValue{ 25 }
{
UpdateTabSize();
Draw();
}
void GUIMyFrame1::drawPanelOnSize(wxSizeEvent& event)
{
Draw();
}
void GUIMyFrame1::m_slider_Num_of_ElemOnScroll(wxScrollEvent& event)
{
_maxElemValue = _tab.size();
UpdateTabSize();
Draw();
}
void GUIMyFrame1::m_button_SortOnButtonClick(wxCommandEvent& event)
{
auto f = [this]() {
for (int i = 0; i < _tab.size() - 1; i++)
for (int j = 0; j < _tab.size() - i - 1; j++) {
wxGetApp().CallAfter([this, j] {
Draw();
});
if (_tab[j + 1] < _tab[j])
std::swap(_tab[j + 1], _tab[j]);
}
wxGetApp().CallAfter([this] {
Draw();
});
};
std::thread worker(f);
worker.detach();
}
void GUIMyFrame1::m_button_ShuffleOnButtonClick(wxCommandEvent& event)
{
UpdateTabSize();
Draw();
}
void GUIMyFrame1::Draw()
{
wxClientDC dc1(drawPanel);
wxBufferedDC dc(&dc1);
dc.Clear();
int w, h;
drawPanel->GetSize(&w, &h);
int tempWidth = w / _tab.size();
double unitHeight = (double)h / _maxElemValue;
int shift = GetShift(w);
for (int i = 0; i < _tab.size(); i++) {
wxBrush tempBrush(_tab[i]._color);
wxPen tempPen(_tab[i]._color, 0);
dc.SetBrush(tempBrush);
dc.SetPen(tempPen);
dc.DrawRectangle(
wxRect(
shift + i * tempWidth, h - (int)(unitHeight * _tab[i]._value) + 2,
tempWidth, (int)(unitHeight * _tab[i]._value) - 4
));
}
}
void GUIMyFrame1::UpdateTabSize()
{
_tab.clear();
for (int i = 0; i < m_slider_Num_of_Elem->GetValue(); i++)
_tab.push_back(getNewRandomElement(_maxElemValue));
}
int GUIMyFrame1::GetShift(int w) {
int AllElemWidth = _tab.size() * int(w / _tab.size());
return (w - AllElemWidth) / 2;
}
My question is how do I fix that? I guess the whole drawing process is taking much longer than every comparison in sorting but why don't the GUI updates stop as soon as the table gest sorted? I did try std::mutex
as I thought the synchronization might help, because _tab
might be changed and read at the same time while sorting and drawing to screen but it didn't help.
I think your program would work just fine if you simply replace calls to Draw()
inside CallAfter()
with the calls to Refresh()
-- and only actually draw your window from your wxEVT_PAINT
handler which is the only really supported and portable way to do it.