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
相关产品推荐
相关产品推荐

