daiya2008 2026-04-15 19:48 采纳率: 60%
浏览 10

QT使用openglWidget时遇到闪退问题

QT使用openglWidget时遇到闪退问题,敬请各位指导!

pathViewer.h
#ifndef PATHVIEWER_H
#define PATHVIEWER_H

#include <QWidget>
#include <QOpenGLWidget>
//#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLBuffer>
#include <QMatrix4x4>
#include <QVector3D>

class PathViewer : public QOpenGLWidget, protected QOpenGLFunctions
{
    Q_OBJECT

public:
    explicit PathViewer(QWidget *parent = nullptr);
    void setPath(const QList<QVector3D> &points);
    void setShowPath(bool show);
    void setToolPath(const QList<QVector3D> &points);

protected:
    void initializeGL() override;
    void resizeGL(int w, int h) override;
    void paintGL() override;

private:
    void setupShaders();
    QMatrix4x4 createFANUCViewMatrix() const;
    QMatrix4x4 createProjectionMatrix(int w, int h) const;

    // Shader
    QOpenGLShaderProgram m_program;

    // Path VAO/VBO
    QOpenGLVertexArrayObject m_pathVAO;
    QOpenGLBuffer m_pathVBO{QOpenGLBuffer::VertexBuffer};

    // Axis VAO/VBO
    QOpenGLVertexArrayObject m_axisVAO;
    QOpenGLBuffer m_axisVBO{QOpenGLBuffer::VertexBuffer};

    // Data
    QList<QVector3D> m_pathPoints;
    bool m_showPath = false;
    int m_pathVertexCount = 0;

    // Uniform locations
    GLuint m_projLoc = 0;
    GLuint m_viewLoc = 0;
    GLuint m_colorLoc = 0;
};

#endif // PATHVIEWER_H

pathViewer.cpp
#include "pathViewer.h"
#include <QtMath>

// ===== Vertex Shader =====
static const char* vertShaderSrc = R"(
#version 330 core
layout (location = 0) in vec3 aPos;
uniform mat4 uProjection;
uniform mat4 uView;
void main() {
    gl_Position = uProjection * uView * vec4(aPos, 1.0);
}
)";

// ===== Fragment Shader =====
static const char* fragShaderSrc = R"(
#version 330 core
out vec4 FragColor;
uniform vec3 uColor;
void main() {
    FragColor = vec4(uColor, 1.0);
}
)";

PathViewer::PathViewer(QWidget *parent)
    : QOpenGLWidget(parent)
{
//    setMinimumSize(400, 300);
}

void PathViewer::setPath(const QList<QVector3D> &points)
{
    m_pathPoints = points;
    m_pathVertexCount = points.size();

    if (m_pathVertexCount > 0) {
        makeCurrent();
        m_pathVBO.bind();
        m_pathVBO.allocate(m_pathPoints.data(), m_pathPoints.size() * static_cast<int>(sizeof(QVector3D)));
        m_pathVBO.release();
        doneCurrent();
    }

    update();
}

void PathViewer::setShowPath(bool show)
{
    m_showPath = show;
    update();
}

void PathViewer::initializeGL()
{
    initializeOpenGLFunctions();

    // 编译着色器
    setupShaders();

    // 获取 uniform 位置
    m_projLoc = m_program.uniformLocation("uProjection");
    m_viewLoc = m_program.uniformLocation("uView");
    m_colorLoc = m_program.uniformLocation("uColor");

    // 初始化 Path VAO/VBO
    m_pathVAO.create();
    m_pathVBO.create();

    m_pathVAO.bind();
    m_pathVBO.bind();
    m_program.enableAttributeArray(0);
    m_program.setAttributeBuffer(0, GL_FLOAT, 0, 3);
    m_pathVBO.release();
    m_pathVAO.release();

    // 初始化坐标轴数据(6个点:3条线 × 2端点)
    QVector3D axisVertices[] = {
        // X axis (red)
        QVector3D(0, 0, 0), QVector3D(30, 0, 0),
        // Y axis (green)
        QVector3D(0, 0, 0), QVector3D(0, 30, 0),
        // Z axis (blue)
        QVector3D(0, 0, 0), QVector3D(0, 0, 30)
    };

    m_axisVAO.create();
    m_axisVBO.create();
    m_axisVBO.bind();
    m_axisVBO.allocate(axisVertices, sizeof(axisVertices));
    m_axisVBO.release();

    m_axisVAO.bind();
    m_axisVBO.bind();
    m_program.enableAttributeArray(0);
    m_program.setAttributeBuffer(0, GL_FLOAT, 0, 3);
    m_axisVBO.release();
    m_axisVAO.release();

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // 黑色背景(FANUC 风格)
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LINE_SMOOTH);
    glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
}

void PathViewer::setupShaders()
{
    m_program.addShaderFromSourceCode(QOpenGLShader::Vertex, vertShaderSrc);
    m_program.addShaderFromSourceCode(QOpenGLShader::Fragment, fragShaderSrc);
    m_program.link();
}

QMatrix4x4 PathViewer::createFANUCViewMatrix() const
{
    QMatrix4x4 view;
    // 相机位置:右前上方(FANUC标准视角)
    // eye = (50, -40, 40), center = (0,0,0), up = (0,0,1)
    view.lookAt(
        QVector3D(50.0f, -40.0f, 40.0f),
        QVector3D(0.0f, 0.0f, 0.0f),
        QVector3D(0.0f, 0.0f, 1.0f)
        );
    return view;
}

QMatrix4x4 PathViewer::createProjectionMatrix(int w, int h) const
{
    QMatrix4x4 proj;
    proj.perspective(45.0f, float(w) / float(h ? h : 1), 0.1f, 200.0f);
    return proj;
}

void PathViewer::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h);
}

void PathViewer::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    QMatrix4x4 projection = createProjectionMatrix(width(), height());
    QMatrix4x4 view = createFANUCViewMatrix();

    m_program.bind();
    m_program.setUniformValue(m_projLoc, projection);
    m_program.setUniformValue(m_viewLoc, view);

    // === 绘制坐标轴 ===
    glLineWidth(2.5f);
    m_axisVAO.bind();

    // X - Red
    m_program.setUniformValue(m_colorLoc, QVector3D(1.0f, 0.0f, 0.0f));
    glDrawArrays(GL_LINES, 0, 2);

    // Y - Green
    m_program.setUniformValue(m_colorLoc, QVector3D(0.0f, 1.0f, 0.0f));
    glDrawArrays(GL_LINES, 2, 2);

    // Z - Blue
    m_program.setUniformValue(m_colorLoc, QVector3D(0.0f, 0.0f, 1.0f));
    glDrawArrays(GL_LINES, 4, 2);

    m_axisVAO.release();

    // === 绘制路径(白色)===
    if (m_showPath && m_pathVertexCount > 0) {
        glLineWidth(2.0f);
        m_program.setUniformValue(m_colorLoc, QVector3D(1.0f, 1.0f, 1.0f)); // White
        m_pathVAO.bind();
        glDrawArrays(GL_LINE_STRIP, 0, m_pathVertexCount);
        m_pathVAO.release();
    }

    m_program.release();
}

我在widget.h中添加:
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "pathViewer.h"

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget *ui;
    PathViewer *pv;
};
#endif // WIDGET_H

widget.cpp中添加:
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_pushButton_clicked()
{
    //    QVector<QVector3D> path;
    QList<QVector3D> path;
    path << QVector3D(0, 0, 0)
         << QVector3D(10, 0, 0)
         << QVector3D(10, 10, 0)
         << QVector3D(5, 15, -2)
         << QVector3D(0, 10, -2);
    pv->setPath(path);
}

openglTest.pro中添加:
QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

QT += core gui openglwidgets

LIBS += -lopengl32 -lglu32

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    pathViewer.cpp \
    widget.cpp

HEADERS += \
    pathViewer.h \
    widget.h

FORMS += \
    widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

![img](https://i-blog.csdnimg.cn/ask/bb1f3e0e9612447c8d09d6e7717d86d3.png "#left")

openglWidget也作了提升 ,运行时界面出来了,一旦点击按钮,就闪退了,百思不得其解,请各位指导

  • 写回答

2条回答 默认 最新

  • 檀越@新空间 2026-04-15 19:49
    关注

    晚上好🌙🌙🌙
    本答案参考通义千问

    你遇到的 闪退问题 通常与 OpenGL 的上下文管理、资源初始化或内存访问有关。根据你提供的代码,我们可以逐步排查并解决这个问题。


    🔍 问题分析

    从你的 PathViewer 类和 pathViewer.cpp 文件来看,问题可能出现在以下几个方面:

    1. 未正确初始化 OpenGL 上下文
    2. initializeGL() 中未正确绑定 VBO 和 VAO
    3. 使用了未初始化的 OpenGL 函数
    4. 在非当前线程中调用 OpenGL 操作

    ✅ 解决方案

    1. 确保 OpenGL 上下文已正确初始化

    确保你在调用任何 OpenGL 函数前,已经通过 makeCurrent() 正确激活了 OpenGL 上下文。

    ✅ 修改建议:

    • setPath() 方法中,避免直接调用 makeCurrent()doneCurrent(),而是将数据分配移到 initializeGL()paintGL() 中。
    • 仅在 initializeGL() 中初始化 VBO/VBO,而不是在 setPath() 中。

    ✅ 修改后的 setPath() 方法:

    void PathViewer::setPath(const QList<QVector3D> &points)
    {
        m_pathPoints = points;
        m_pathVertexCount = points.size();
        update(); // 触发重绘
    }
    

    2. 确保 VBO/VBO 初始化正确

    initializeGL() 中,你需要确保 VBO/VBO 已经被正确创建和绑定。

    ✅ 修改建议:

    • initializeGL() 中,对 m_pathVBOm_pathVAO 进行初始化。

    ✅ 修改后的 initializeGL() 示例:

    void PathViewer::initializeGL()
    {
        initializeOpenGLFunctions();
    
        // 编译着色器
        setupShaders();
    
        // 获取 uniform 位置
        m_projLoc = m_program.uniformLocation("uProjection");
        m_viewLoc = m_program.uniformLocation("uView");
        m_colorLoc = m_program.uniformLocation("uColor");
    
        // 初始化 Path VAO/VBO
        m_pathVAO.create();
        m_pathVBO.create();
    
        m_pathVAO.bind();
        m_pathVBO.bind();
        m_program.enableAttributeArray(0);
        m_program.setAttributeBuffer(0, GL_FLOAT, 0, 3);
        m_pathVBO.release();
        m_pathVAO.release();
    
        // 初始化坐标轴数据(6个点:3条线 × 2端点)
        QVector3D axisVertices[] = {
            // X axis (red)
            QVector3D(0, 0, 0), QVector3D(30, 0, 0),
            // Y axis (green)
            QVector3D(0, 0, 0), QVector3D(0, 30, 0),
            // Z axis (blue)
            QVector3D(0, 0, 0), QVector3D(0, 0, 30)
        };
    
        m_axisVAO.create();
        m_axisVBO.create();
        m_axisVBO.bind();
        m_axisVBO.allocate(axisVertices, sizeof(axisVertices));
        m_axisVBO.release();
    
        m_axisVAO.bind();
        m_axisVBO.bind();
        m_program.enableAttributeArray(0);
        m_program.setAttributeBuffer(0, GL_FLOAT, 0, 3);
        m_axisVBO.release();
        m_axisVAO.release();
    
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // 黑色背景(FANUC 风格)
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_LINE_SMOOTH);
        glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
    }
    

    3. 确保 paintGL() 中正确绘制

    paintGL() 中,你应该绑定 VAO 并绘制图形。

    ✅ 示例 paintGL() 方法:

    void PathViewer::paintGL()
    {
        makeCurrent(); // 确保当前上下文有效
    
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        // 绘制坐标轴
        m_axisVAO.bind();
        m_program.bind();
        m_program.setUniformValue(m_colorLoc, QVector3D(1.0f, 0.0f, 0.0f)); // X轴为红色
        glDrawArrays(GL_LINES, 0, 2); // X轴
    
        m_program.setUniformValue(m_colorLoc, QVector3D(0.0f, 1.0f, 0.0f)); // Y轴为绿色
        glDrawArrays(GL_LINES, 2, 2); // Y轴
    
        m_program.setUniformValue(m_colorLoc, QVector3D(0.0f, 0.0f, 1.0f)); // Z轴为蓝色
        glDrawArrays(GL_LINES, 4, 2); // Z轴
        m_axisVAO.release();
    
        // 如果需要绘制路径
        if (m_showPath && m_pathVertexCount > 0) {
            m_pathVAO.bind();
            m_program.setUniformValue(m_colorLoc, QVector3D(0.5f, 0.5f, 1.0f)); // 路径颜色
            glDrawArrays(GL_LINE_STRIP, 0, m_pathVertexCount);
            m_pathVAO.release();
        }
    
        doneCurrent(); // 释放上下文
    }
    

    4. 使用 QOpenGLWidget 时注意线程安全

    QOpenGLWidget 必须在主线程中使用。如果你在其他线程中操作它,可能会导致崩溃。

    ✅ 建议:

    • 确保 PathViewer 实例是在主线程中创建和使用的。
    • 不要在其他线程中直接调用 setPath()update()

    5. 添加错误检查

    在 OpenGL 操作后添加错误检查,可以帮助定位问题。

    ✅ 示例:

    GLenum err;
    while ((err = glGetError()) != GL_NO_ERROR) {
        qDebug() << "OpenGL Error:" << err;
    }
    

    🧠 总结

    ✅ 重点部分总结:

    • 不要在 setPath() 中直接调用 makeCurrent()doneCurrent(),应在 initializeGL() 中初始化 VBO。
    • 确保 paintGL() 中正确绑定 VAO 并绘制图形
    • 确保 QOpenGLWidget 在主线程中使用
    • 添加 OpenGL 错误检查,帮助定位崩溃原因。

    📌 最终修改后的 pathViewer.cpp 示例(关键部分):

    // setPath() 修改
    void PathViewer::setPath(const QList<QVector3D> &points)
    {
        m_pathPoints = points;
        m_pathVertexCount = points.size();
        update(); // 触发重绘
    }
    
    // paintGL() 修改
    void PathViewer::paintGL()
    {
        makeCurrent();
    
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        // 绘制坐标轴
        m_axisVAO.bind();
        m_program.bind();
        m_program.setUniformValue(m_colorLoc, QVector3D(1.0f, 0.0f, 0.0f)); // X轴为红色
        glDrawArrays(GL_LINES, 0, 2); // X轴
    
        m_program.setUniformValue(m_colorLoc, QVector3D(0.0f, 1.0f, 0.0f)); // Y轴为绿色
        glDrawArrays(GL_LINES, 2, 2); // Y轴
    
        m_program.setUniformValue(m_colorLoc, QVector3D(0.0f, 0.0f, 1.0f)); // Z轴为蓝色
        glDrawArrays(GL_LINES, 4, 2); // Z轴
        m_axisVAO.release();
    
        // 如果需要绘制路径
        if (m_showPath && m_pathVertexCount > 0) {
            m_pathVAO.bind();
            m_program.setUniformValue(m_colorLoc, QVector3D(0.5f, 0.5f, 1.0f)); // 路径颜色
            glDrawArrays(GL_LINE_STRIP, 0, m_pathVertexCount);
            m_pathVAO.release();
        }
    
        doneCurrent();
    }
    

    如需进一步调试,请提供完整的堆栈跟踪信息(如 crash log 或 core dump),以便更精确地定位问题。

    评论

报告相同问题?

问题事件

  • 创建了问题 4月15日