Qt 多线程中使用 UI 控件导致程序崩溃的解决方法
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 控件只能在主线程中使用。
解决方案:
-
将操作 UI 控件的代码移至槽函数中执行:
将
ui->ImageLab->setPixmap(pix);代码移至信号Signal_setPixmap(m_pix)的槽函数中执行,确保在主线程中更新 UI 控件。 -
使用 Qt 的线程间通信机制(如信号槽)来更新 UI 控件:
可以使用
QMetaObject::invokeMethod函数在子线程中安全地更新 UI 控件。 -
使用互斥锁(
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 控件导致程序崩溃的问题。
相关链接
原文地址: https://www.cveoy.top/t/topic/oTBa 著作权归作者所有。请勿转载和采集!