是否可以使用标准 C++ 线程而不是 FLTK 超时来更新窗口?

Posted

技术标签:

【中文标题】是否可以使用标准 C++ 线程而不是 FLTK 超时来更新窗口?【英文标题】:Is it possible to use standard C++ threads instead of FLTK timeouts to update window? 【发布时间】:2017-12-02 20:04:47 【问题描述】:

我需要创建一个无需用户交互即可自行完成的简单动画。 有a bunch of solutions 使用包含的 FLTK 计时器在固定时间段内重绘窗口,并且该方案工作正常,无需我移动鼠标或按键,但只要它在 std:: 中使用 redraw() 更改为简单循环:线程,只有在用户将事件推送到程序时,一切都会中断和重绘。

这是我的代码。如果您费心启动它,您会看到updateFunc 每秒稳定地向输出发送垃圾邮件,但draw 仅在您使用鼠标或键盘执行某些操作时才会出现在那里,因此窗口会改变其颜色。如果这是正常行为,我需要以某种方式对其进行更改。

#include <bits/stdc++.h>
using namespace std;
#include <FL/Fl.h>
#include <FL/gl.h>
#include <FL/Fl_Gl_Window.h>
chrono::time_point<chrono::system_clock> execStart;
void log(const char* fmt, ...) 
    va_list arg;
    va_start(arg,fmt);
    fprintf(stderr,"[%10.3f] ",chrono::duration_cast<chrono::milliseconds>(
        chrono::system_clock::now()-execStart
    ).count()/1000.0);
    vfprintf(stderr,fmt,arg);
    fprintf(stderr,"\n");
    va_end(arg);


double rand01() return (double)rand()/RAND_MAX;

class Window: public Fl_Gl_Window 
private:
    thread updateThread;
    void updateFunc() 
        while (1) 
            log("%s",__func__);
            this_thread::sleep_for(1s);
            redraw();
        
    
protected:
    void draw() 
        log("%s",__func__);
        glClearColor(rand01(),rand01(),rand01(),1);
        glClear(GL_COLOR_BUFFER_BIT);
    
public:
    Window(int x,int y,int w,int h,const char* s):
        Fl_Gl_Window(x,y,w,h,s),
        updateThread(&Window::updateFunc,this)
        
    Window(): Window(320,240,800,600,"FLTK OpenGL test") 
;

int main() 
    execStart=chrono::system_clock::now();
    log("execution started");
    srand(time(0));

    Window *wnd=new Window();
    wnd->show();

    return Fl::run();

【问题讨论】:

【参考方案1】:

这是正常行为。但幸运的是,FLTK 已经涵盖了它。

简而言之,您必须在启动线程之前调用Fl::lock(),在进行任何更新之前在线程中调用Fl::lock(),在更新GUI 之后调用Fl::unlock(),并使用Fl::awake() 而不是redraw

Read the documentation 了解更多信息。

【讨论】:

很好,很不错!只是为了确保,是否也可以等待 FLTK 从工作线程完成绘图?因为我的线程中有很多多余的循环迭代,这不是很好,所以我想避免这种情况。 FLTK 只有一半。在后台线程上,您可以使用Fl::awake(Fl_Awake_Handler cb, void* userdata) 调用在渲染线程上调度一个函数,并等待完成。在该函数中调用redraw,并通知后台线程它已完成。需要自己实现wait+notifications,现代C++方式大概是std::promise&lt;void&gt; 或者如果你要发布多个请求,你可以使用 std::queue 来获取结果,使用 std::mutex 来保护它,使用 std::condition_variable 来实现睡眠/唤醒。跨度>

以上是关于是否可以使用标准 C++ 线程而不是 FLTK 超时来更新窗口?的主要内容,如果未能解决你的问题,请参考以下文章

使用c ++删除发送到FLTK中线程的数据

FLTK 中的线程

如何让 Octave 默认使用“gnuplot”而不是“fltk”?

在C ++中,是否有任何理由产生并立即加入一个线程,而不是直接调用该函数?

FLTK 事件映射/多线程

在 C++ 中使用 FLTK 的简单电话簿