Qt 多线程中使用 UI 控件导致程序崩溃的解决方法

以下代码展示了在 void CImageShowWidget::paintEvent(QPaintEvent* event) 函数中,使用 QtConcurrent::run 创建一个线程来更新图像,并通过信号 Signal_setPixmap(m_pix) 将更新后的图像传递给 UI 控件 ui->ImageLab,导致程序崩溃。

void CImageShowWidget::paintEvent(QPaintEvent* event)
{
    QWidget::paintEvent(event);
    if (m_pixmap.isNull())
    {
        return;
    }
	QtConcurrent::run([=]() 
	{
		g_mutex.lock();
		m_pix = m_pixmap.scaled(ui->ImageLab->size());
		QPainter pLine(&m_pix);
		pLine.setRenderHint(QPainter::Antialiasing);
		pLine.setRenderHint(QPainter::SmoothPixmapTransform);
		//绘制通道id到图上
		DrawChannelNum(pLine, m_channelID);

			emit Signal_setPixmap(m_pix);
		
		g_mutex.unlock();
	});
}

崩溃发生在信号 Signal_setPixmap(m_pix) 发出后,此函数槽函数为 ui->ImageLab->setPixmap(pix);

原因:

在多线程中直接使用 UI 控件(如 ui->ImageLab)会导致程序崩溃,因为 UI 控件只能在主线程中使用。

解决方案:

  1. 将操作 UI 控件的代码移至槽函数中执行:

    ui->ImageLab->setPixmap(pix); 代码移至信号 Signal_setPixmap(m_pix) 的槽函数中执行,确保在主线程中更新 UI 控件。

  2. 使用 Qt 的线程间通信机制(如信号槽)来更新 UI 控件:

    可以使用 QMetaObject::invokeMethod 函数在子线程中安全地更新 UI 控件。

  3. 使用互斥锁(g_mutex)来保护共享资源:

    使用互斥锁来保护 m_pix 等共享资源,避免多线程访问时出现数据竞争问题。

建议:

  • 避免在子线程中直接操作 UI 控件,使用 Qt 提供的线程安全机制来更新 UI 控件。
  • 使用互斥锁保护共享资源,确保数据的一致性。

代码示例(使用信号槽):

void CImageShowWidget::paintEvent(QPaintEvent* event)
{
    QWidget::paintEvent(event);
    if (m_pixmap.isNull())
    {
        return;
    }
	QtConcurrent::run([=]() 
	{
		g_mutex.lock();
		m_pix = m_pixmap.scaled(ui->ImageLab->size());
		QPainter pLine(&m_pix);
		pLine.setRenderHint(QPainter::Antialiasing);
		pLine.setRenderHint(QPainter::SmoothPixmapTransform);
		//绘制通道id到图上
		DrawChannelNum(pLine, m_channelID);
		g_mutex.unlock();
		// 在子线程中发送信号,通知主线程更新 UI 控件
		QMetaObject::invokeMethod(this, 'updateImage', Qt::QueuedConnection, Q_ARG(QPixmap, m_pix));
	});
}

// 槽函数,更新 UI 控件
void CImageShowWidget::updateImage(const QPixmap& pix)
{
    ui->ImageLab->setPixmap(pix);
}

注意:

  • Qt::QueuedConnection 确保信号在主线程的事件循环中被处理。
  • 使用 Q_ARG 指定参数类型。

通过以上解决方案,可以有效避免多线程中使用 UI 控件导致程序崩溃的问题。

相关链接

Qt 多线程中使用 UI 控件导致程序崩溃的解决方法

原文地址: https://www.cveoy.top/t/topic/oTBa 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录