使用wxWidgets中的CallAfter从另一个线程更新GUI

问题描述 投票:0回答:1

我正在使用 wxWidgets 用 C++ 开发一个小型桌面应用程序,它是关于可视化不同类型的排序。为了在排序发生并在屏幕上绘制时保持 GUI 响应,我尝试在不同的线程上做一些工作,但我知道 GUI 更新必须从主线程进行 - 所以我找到了一个教程使用

CallAfter
以便从主线程更新 GUI。然而,我得到的结果是,表格几乎立即被排序(通过工作线程)并显示在屏幕上,但 GUI 冻结了一段时间并更新了很多(屏幕上没有任何变化,因为表格在开始)。

我正在谈论的一些代码:

#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;
}

我的问题是如何解决这个问题?我猜整个绘图过程比排序中的每次比较花费的时间要长得多,但是为什么 GUI 更新在表排序后不立即停止?我确实尝试过

std::mutex
,因为我认为同步可能会有所帮助,因为
_tab
可能会在排序和绘制到屏幕时同时更改和读取,但它没有帮助。请不要对我太严厉,因为我经验不足:/

c++ multithreading wxwidgets
1个回答
0
投票

为了使其看起来有吸引力,您可以使用condition_variable,其中工作人员将在每个

wait
之后对其进行
callafter
,并且主线程将完成绘制然后
notify_one
,以便工作人员可以继续排序。

每次修改您都会得到一帧,请随意在工作人员中添加额外的sleep,直到结果足够吸引人。

© www.soinside.com 2019 - 2024. All rights reserved.