Qt 中的 GLWidget 仅在 mousemove 上更新

Posted

技术标签:

【中文标题】Qt 中的 GLWidget 仅在 mousemove 上更新【英文标题】:GLWidget in Qt only updating on mousemove 【发布时间】:2009-01-15 17:54:11 【问题描述】:

我目前正在使用 Qt 尝试设置一个小型粒子系统。其中,我将 GLWidget 子类化并破解了它。一切都很顺利,直到我做了一些未知的更改,现在小部件只在我移动鼠标时重新绘制(由于我已经触发了 QTimer,它应该一直在这样做)。相关代码:

OpenGLWidget.h

class OpenGLWidget :  public QGLWidget  

   Q_OBJECT

public:
   OpenGLWidget(QWidget * parent = 0);
   ~OpenGLWidget();

public slots:
   void toggleEmitter();

protected:
   void initializeGL();
   void paintGL();
   void resizeGL(int width, int height);
   QSize minimumSizeHint() const;
   QSize sizeHint() const;
   void mousePressEvent(QMouseEvent *event);
   void mouseMoveEvent(QMouseEvent *event);

protected slots:
   void timeOut();

private:

   void testFunc(Particle & p, unsigned int t);

   QTime time;
   QTimer timer;

   Emitter emitter;

.cpp 中的相关代码

// in the constructor
time.start();
connect(&timer, SIGNAL(timeout()), this, SLOT(timeOut()));
timer.start(0);

void OpenGLWidget::initializeGL()  
   GLuint tex = 0;

   qglClearColor(bgColor);
   glEnable(GL_DEPTH_TEST);   
   glClearDepth(1.0f);
    glDepthFunc(GL_LEQUAL);
   glShadeModel(GL_SMOOTH); 

   glDisable(GL_CULL_FACE);
   glEnable(GL_TEXTURE_2D); 
   glEnable( GL_BLEND );
   glBlendFunc( GL_SRC_ALPHA, GL_ONE); // _MINUS_SRC_ALPHA );

   glPointSize(3.0f);

   tex = bindTexture(QPixmap(QString("testparticle2.png")), GL_TEXTURE_2D);
   emitter = Emitter(Vector(0, 0, 0.0f), tex, 50, fastdelegate::FastDelegate2<Particle &, unsigned int>(this, &OpenGLWidget::testFunc));


void OpenGLWidget::paintGL()  
   makeCurrent();
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   mainCam.SetView();

   glRotatef(xRot, 1, 0, 0);
   glRotatef(yRot, 0, 1, 0);

   emitter.Process(time.elapsed());

   totalTime += time.elapsed();
   time.restart();



void OpenGLWidget::resizeGL(int width, int height)  
   contextWidth = width;
   contextHeight = height;

   glViewport(0, 0, width, height);

   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluPerspective(55.0f, width / (float) height, 0.01f, 100.0f);

   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();



void OpenGLWidget::timeOut()  
   updateGL();


void OpenGLWidget::mousePressEvent(QMouseEvent *event)  
    lastX = event->pos().x();
    lastY = event->pos().y();


void OpenGLWidget::mouseMoveEvent(QMouseEvent *event)  
    int dx = event->x() - lastX;
    int dy = event->y() - lastY;

    if (event->buttons() & Qt::LeftButton) 
        xRot += 3 * dy;
        yRot += 3 * dx;
     else if (event->buttons() & Qt::RightButton) 
        xRot += 3 * dy;
        yRot += 3 * dx;
    

    lastX = event->pos().x();
    lastY = event->pos().y();


【问题讨论】:

【参考方案1】:

只有在事件循环获得控制权时才会触发具有 0 秒超时的 QTimer。我怀疑情况并非如此。但是,当您移动鼠标时,事件循环(再次)处理一些事件,然后传递未决的计时器事件。也许您需要在更新循环中调用processEvents() 以确保处理来自 QTimer 的未决计时器事件。

【讨论】:

【参考方案2】:

考虑到 updateGL() 调用 glDraw(),而 glDraw() 又调用了paintGL(),您会认为计时器应该调用与 mousemove 事件相同的功能。

你确定计时器真的在计时吗?

顺便说一句,paintGL() 中不需要调用 makeCurrent()。

编辑:添加额外信息后:

QTimer says:

"作为一种特殊情况,QTimer 与 超时 0 超时,一旦所有 窗口系统事件中的事件 队列已处理完毕。”

所以,如果您希望它尽可能快地运行(尽管 10 毫秒可能是 Windows 和大多数基于 x386 的系统上的最小值),那么使用值 1 而不是 0 来启动您的计时器。我假设这是问题在于,它只有在 完成 从队列中读取消息时才会滴答作响。

【讨论】:

makeCurrent 用于调试目的。事实证明,计时器正在计时,但时间步长没有正确更新,除非在移动鼠标时。 尝试非零时间步长? 1/60 秒是 ~17 毫秒。【参考方案3】:

计时器根本无法在少于 20 毫秒的情况下工作。它等于 0。您可以使用简单的循环来测量从一次迭代到另一次迭代的时间。测量方法可能应该使用您操作系统的API。

【讨论】:

以上是关于Qt 中的 GLWidget 仅在 mousemove 上更新的主要内容,如果未能解决你的问题,请参考以下文章

GraphicsScene 中的 Qt GLWidget 用于从图像数据(C++、Windows)中快速显示视频?

Qt - 从 QMainWindow 向 GLWidget 发送按键事件

Qt App 在 GLWidget.show() 上导致分段错误;

Qt designer里面没有glwidget这个控件,我要怎么弄出来呢

在Qt示例项目的C ++ / QML源中的//! [0]的含义是什么?

Qt4 插槽和信号:Qt4 无法找到信号