You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Qt应用信号与线程问题:图像显示信号调用失效排查

问题描述

我正在开发一个项目,客户端向服务器发送图像缓冲区,服务器通过QGraphicsView显示接收的图像。除信号调用部分外,其余功能均正常——直接通过按钮调用显示代码可以正常工作,但通过自定义信号触发时没有效果。

相关代码

source.cpp

#include "tela_monitoramentos.h"
#include <iostream>

char video_buffer[4096]; //存储图像二进制数据的缓冲区声明
int main_func();//主函数声明

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

    //关联信号与槽
    connect(this, SIGNAL(call_frameUpdate()), this, SLOT(frame_update()));

}

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

//调用主函数的按钮点击事件
void tela_monitoramentos::on_btn_iniciar_video_clicked()
{
    std::cout << "Calling main function" << std::endl;
    main_func();
}

int main_func(){
    
           class ThreadConect_video : public QThread { //创建子线程
           private:
               tela_monitoramentos* chatInstance; //信号所属类实例

           public:
               void run() override {

                   //示例代码
                 
                   while(true) {
                      
                      /*
                      #
                      # 接收缓冲区内容的代码
                      #
                      */
                        std::cout << "Calling function thar loads the buffer into the widget" << std::endl;
                        emit chatInstance->call_frameUpdate();                        
                        usleep(1000); //加载下一帧前等待1秒

                    }//循环结束
           };

           //启动新线程

           ThreadConect_video *thread = new ThreadConect_video;
           thread -> start(); 
    return 0;
}
void tela_monitoramentos::frame_update() //将字节数组加载到控件的函数
{
    std::cout << "Received Signal" << std::endl;
    scene = new QGraphicsScene(this);
    ui->tela_pc->setScene(scene);
    ui->tela_pc->scene()->addPixmap(QPixmap::fromImage(QImage::fromData(reinterpret_cast<unsigned char*>(video_buffer), sizeof(video_buffer))));
}

头文件(tela_monitoramentos.h)

//Header
namespace Ui {
class tela_monitoramentos;
}

class tela_monitoramentos : public QDialog
{
    Q_OBJECT

public:
    explicit tela_monitoramentos(QWidget *parent = nullptr);
    ~tela_monitoramentos();

private slots:

    void frame_update(); //目标调用函数
    
    void on_btn_iniciar_video_clicked(); 


private:
    Ui::tela_monitoramentos *ui;
    QTimer* timer;
    void keyPressEvent(QKeyEvent *event);

protected:
    void showEvent(QShowEvent* event) override;

signals:
    void call_frameUpdate(); //自定义信号
};

注:直接通过按钮调用以下显示代码可正常工作:

scene = new QGraphicsScene(this);
ui->tela_pc->setScene(scene);
ui->tela_pc->scene()->addPixmap(QPixmap::fromImage(QImage::fromData(reinterpret_cast<unsigned char*>(video_buffer), 
                                sizeof(video_buffer))));

问题原因与修复方案

1. 核心问题:线程内指针未初始化

ThreadConect_video类中的chatInstance指针没有指向任何有效的tela_monitoramentos实例,直接emit chatInstance->call_frameUpdate()会触发空指针调用,信号根本无法发出。

2. 次要问题:未声明成员变量scene

tela_monitoramentos类的私有成员中没有定义QGraphicsScene* scene;,直接在frame_update中使用会导致未定义行为。

修正后的代码

调整main_func与线程类

// 修改main_func,接收主窗口实例作为参数
int main_func(tela_monitoramentos* instance){ 
           class ThreadConect_video : public QThread { 
           private:
               tela_monitoramentos* chatInstance; 

           public:
               // 构造函数初始化指针
               explicit ThreadConect_video(tela_monitoramentos* parentInstance) : chatInstance(parentInstance) {} 

               void run() override {
                   // 使用isInterruptionRequested替代死循环,方便安全终止线程
                   while(!isInterruptionRequested()) { 
                      /*
                      #
                      # 接收缓冲区内容的代码
                      #
                      */
                        std::cout << "触发更新图像的信号" << std::endl;
                        if(chatInstance){
                            emit chatInstance->call_frameUpdate();                        
                        }
                        msleep(1000); // 使用Qt的msleep替代usleep,更符合Qt线程规范
                    }
               };
           };

           ThreadConect_video *thread = new ThreadConect_video(instance);
           thread->setParent(instance); // 设置父对象,由主窗口自动管理内存
           thread->start(); 
    return 0;
}

// 修改按钮点击事件,传入当前窗口实例
void tela_monitoramentos::on_btn_iniciar_video_clicked()
{
    std::cout << "Calling main function" << std::endl;
    main_func(this); 
}

补充scene成员变量

在头文件的private区域添加:

QGraphicsScene* scene;

优化frame_update函数(可选)

避免每次更新都创建新的QGraphicsScene,减少资源开销:

void tela_monitoramentos::frame_update()
{
    std::cout << "Received Signal" << std::endl;
    if(!scene){
        scene = new QGraphicsScene(this);
        ui->tela_pc->setScene(scene);
    } else {
        scene->clear(); // 清除旧图像内容
    }
    scene->addPixmap(QPixmap::fromImage(QImage::fromData(reinterpret_cast<unsigned char*>(video_buffer), sizeof(video_buffer))));
    ui->tela_pc->update(); // 强制刷新视图
}

额外说明

  • Qt跨线程信号槽默认会自动排队,确保槽函数在主线程执行(UI操作必须在主线程),无需额外处理线程切换逻辑。
  • 终止线程时,建议调用thread->requestInterruption()和thread->wait(),避免强制终止导致资源泄漏。

内容的提问来源于stack exchange,提问作者iumonyty

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 15:53:20