【问题标题】:Trying to access QGLWidget from entire application试图从整个应用程序访问 QGLWidget
【发布时间】:2012-07-09 17:58:25
【问题描述】:

我基本上想做的是创建QGLWidget 的一个实例(或者更确切地说是QGLWidget 的派生类),将其添加到QMainWindow,然后访问QGLWidget 的渲染来自我的 QTCreator 程序中任何地方的上下文,以便能够在我选择的任何地方调用裸 OpenGL。

我尝试过的事情:

1) 创建一个名为OGLWidgetQGLWidget 的子类并将其制成单例,然后尝试将单例类“OGLWidget”子类化。我认为这将使我能够访问 OGLWidget 单例使用的相同渲染上下文,但它不起作用。

2) 使用构造函数QGLWidget(QWidget * parent, QGLWidget * shared, Qt::WindowFlags)。对于这个,我尝试将单例对象转换为 QGLWidget,然后在我将 QGLWidget 子类化到另一个名为“Display”的类中时将其粘贴在此构造函数中。我尝试在每个类 openGl 调用之前调用 makeCurrent ,但只有原始单例会绘制。我还检查了 isSharing 并返回 true。

【问题讨论】:

    标签: c++ opengl qt4 qglwidget


    【解决方案1】:

    首先,虽然信号\槽是 Qt 的一个强大而令人敬畏的特性,但由于增加的开销和渲染顺序问题,我永远不会在我的渲染例程中使用它们;尤其是后者。此外,没有必要按照您建议的方式进行。 因此,在我看来,您将渲染例程分散在整个项目中的想法是一个非常糟糕的想法。 我在自己的项目中所做的如下:

    我派生的QGLWidget 拥有一个Renderer 类,该类实现为单例。它包含几个函数中的所有 OpenGL 调用。我创建了一个系统,其中可绘制的所有内容都派生自同一个基类。当我想渲染时,我构建了一个渲染队列,我将其实现为带有自定义排序功能的priority_queue。当是渲染帧的时候了,我只是不停地弹出并渲染,直到队列为空。 使用事件驱动的渲染系统执行此操作,同时保持正确的渲染顺序可能会让您发疯。

    为了完整起见,我的(简化的)QGLWidget 定义:

    #include <QtOpenGL/QGLWidget>
    
    #include "global.h"
    #include "renderer.h"
    
    /**
     * Derivation of QGLWidget.
     */
    class Engine : public QGLWidget
    {
        Q_OBJECT
    private:
        Renderer* renderer;
    private slots:
        void renderTimeout(); // my render-loop is timer based
        void onTap(QMouseEvent* qme);
        void onMove(QMouseEvent* qme);
    protected:
        void initializeGL();
        void resizeGL(int w, int h);
        /* for debugging I use QPainter for drawing overlays, 
         * so I can't use PaintGL */
        void paintEvent(QPaintEvent *event); 
        void mousePressEvent(QMouseEvent* qme);
        void mouseMoveEvent(QMouseEvent* qme);
    public:
        Engine( QWidget* parent = 0 );
        ~Engine();
    signals:
        void tapOccurred(QMouseEvent* qme);
        void moveOccurred(QMouseEvent* qme);
    };
    

    【讨论】:

      【解决方案2】:

      您为什么不直接使用 Qt 的设计用途:使用信号和插槽?也许您的问题比我乍一看更复杂,但在我看来,如果您将插槽添加到您的 QGLWidget 并将它们连接到应用程序中的任何位置的信号,您就可以完成您想要的。例如,可以在QMainWindow 中连接它们。然后这个槽可以调用paintGL()paintEvent() 的实现来更新QGLWidget 中的区域。像这样:

      class MyQGLWidget : public QGLWidget {
      // constructors and destructor...
      
      protected:
          void paintGL();      // <-- implement this in any way you want if you use OpenGL
          void paintEvent();   // <-- or implement this one if you prefer using QPainter
      
      public slots:
          void updateMyWindow();
      }
      
      void MyQGLWidget::updateMyWindow() {
          // Change some data here in any way you like
          // ...
      
          paintGL();
      }
      

      【讨论】:

      • 在我看来,这将导致可怕的意大利面条代码,很难调试 OpenGl 渲染错误。我同意在使用 Qt 时信号\插槽几乎是强制性的,但我只在接收对象不依赖于全局状态(即本例中的 OpenGl)时才使用它。
      • 好吧,我明白你的意思,但我不太同意。我认为这可能取决于您的程序有多复杂,但是这种方法在我的(相对较小的)应用程序中一直很有效。顺便说一句,它与大多数 Qt 示例项目的方法非常相似。
      • 对于小型应用程序,它可以正常工作是的,这也是我的经验。目前我正在开发一款 Android 游戏,在将所有 OpenGl 代码移至一个类后,我感觉重生了。我必须注意,我需要严格的渲染顺序,此外还有许多具有不同渲染参数的对象,我需要一种方法来轻松地最小化状态变化。所以我选择了我的答案中描述的方法。但这主要是品味\意见是的,没有性能问题让我走这条路。
      猜你喜欢
      • 1970-01-01
      • 2013-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-06
      • 1970-01-01
      • 2021-01-15
      相关资源
      最近更新 更多