gpt4 book ai didi

c++ - 如何线程化 QGLWidget?

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:54:07 25 4
gpt4 key购买 nike

我有小部件:

class Main_Widget : public QWidget
{
Q_OBJECT
public:
explicit Main_Widget(QWidget *parent = 0);
~Main_Widget();
private:
MyOGLWidget *mOGL;
QThread *mThread;
QPushButton *mStart;
QPushButton *mStop;
}

然后,我创建了如下所有内容:

mOGL = new MyOGLWidget();
mThread = new QThread();
mStart = new QPushButton();
mStop = new QPushButton();
//move to other thread
mOGL->moveToThread(mThread);

我想在 mOGL 中使用动画。对于这个想法,我有如下代码:

class MyOGLWindow : public QGLWidget
{
private:
bool mEnd; //default false

//...

public:
void doLoop()
{
while(mEnd)
{
//animation
updateGL();
}
}
public slots:
void slotStart()
{
mEnd = true;
}
void slotStop()
{
mEnd = false;
}
}

我确实将我的两个按钮连接到 slotStart()slotStop()。但是如果我使用开始按钮(这会导致 slotStart()),我的 Main_Widget 会卡住,但我的动画会成功运行。我如何才能开始我的无限循环而不卡住我的 Main_Window,以及如何停止?

最佳答案

除 OpenGL View 外,UI 会卡住,因为您没有返回到事件循环。将派生自 QWidget 的任何类(包括 QGLWidget)移动到另一个线程是错误的。

要从另一个线程进行渲染,您需要将QGLContext(而不是QGLWidget)移动到渲染线程。在这方面遵循 QGLWidget 的文档。小部件的绘制事件处理程序不得执行任何操作——否则它将使用来自错误 (GUI) 线程的 GL 上下文。您可以在渲染线程中运行的 QObject 中使用零持续时间计时器,以避免需要自定义 end 标志。每当通过调用 QThread::quit() 完成线程的事件循环时,对象将停止执行。

您还需要使用可以安全销毁的线程类。正确设计的 C++ 类总是可破坏的。 QThread 是个怪人 - 我们在这里修复它。

作为一种风格,没有必要在堆上分配子部件。事实上,这是对堆的轻微浪费,因为堆 block 的开销与 QObject 实例的大小相当。

下面显示了 Qt 中多线程 OpenGL 需要解决的问题的草图。

class Thread : public QThread {
using QThread::run; // final
public:
~QThread() { quit(); wait(); }
};

class ThreadGLWidget : public QGLWidget
{
void paintEvent(QPaintEvent *) {}
void resizeEvent(QResizeEvent *) { emit resized(size()); }
public:
explicit ThreadGLWidget(QWidget * parent = 0) : QGLWidget(parent) {
// Release the context in this thread.
doneCurrent();
}
Q_SIGNAL void resized(QSize);
};

class Animator : public QObject
{
Q_OBJECT
QBasicTimer mTimer;
QSize mWidgetSize;
QPointer<QGLContext> mGLContext;
void nextFrame() {
mGLContext.makeCurrent();
...
updateGL();
}
void timerEvent(QTimerEvent * ev) {
if (ev->timerId() == mTimer.timerId()) nextFrame();
}
public:
explicit Animator(QGLContext * ctx, QObject * parent = 0) :
QObject(parent), mGLContext(ctx)
{
// The use of the timer obviates the custom stop flag. Our
// thread's event loop is not blocked and is quittable.
mTimer.start(0, this);
}
Q_SLOT void setSize(QSize size) { mWidgetSize = size; }
};

class Main_Widget : public QWidget
{
Q_OBJECT
public:
explicit Main_Widget(QWidget *parent = 0) : QWidget(parent),
mLayout(this), mStart("Start"), mStop("Stop"),
mAnimator(mOGL.context())
{
mLayout.addWidget(&mOGL, 0, 0, 1, 2);
mLayout.addWidget(&mOGL, 1, 0);
mLayout.addWidget(&mOGL, 1, 1);
mAnimator.setSize(mOGL.size());
mOGL.context()->moveToThread(&mThread);
mAnimator.moveToThread(&mThread);
mAnimator.connect(&mOGL, SIGNAL(resized(QSize)), SLOT(setSize(QSize)));
mThread.start();
}
private:
QGridLayout mLayout;
ThreadGLWidget mOGL;
QPushButton mStart;
QPushButton mStop;
Animator mAnimator; // must be declared before its thread and after the GL widget
QThread mThread;
// Destruction order of GL-related objects:
// 1. mThread - stops the animation, makes the animator and context threadless
// 2. mAnimator - now threadless, can be destructed from our thread
// 3. mOGL - its context is threadless and can be destructed from our thread
}

关于c++ - 如何线程化 QGLWidget?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22889963/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com