QMovie所在部件Resize时的正确重建方法及技术疑问
承载QMovie的部件调整大小时的重建方案及相关疑问解答
问题描述
当承载QMovie的部件被调整大小时,重建QMovie的“正确”方式是什么?现有实现代码如下:
现有实现代码
class Gif : public QPushButton { Q_OBJECT public: QMovie* movie = nullptr; QTimer *timer = new QTimer(this); int widget_width = 0; int widget_height = 0; Gif(QWidget* parent = 0) : QPushButton(parent) { } void paintEvent(QPaintEvent* p) { // Check if the widget has been resized, if so // delete the QLabel/QMovie and recreate them. if (widget_width) { if (widget_width != width()) { QLabel* label = this->findChild<QLabel*>("label"); label->deleteLater(); movie->deleteLater(); movie = nullptr; } } // Load the gif into the QMovie/QLabel. if (!movie) { auto StyleSheet = styleSheet(); QVector<QString> matches; QRegularExpression re(R"(image:\s*url\((.*)\);)"); QRegularExpressionMatch m = re.match(StyleSheet); for (int i = 0; i <= m.lastCapturedIndex(); i++) matches.append(m.captured(i)); movie = new QMovie(matches[1]); if (!movie->isValid()) qDebug() << "failed to create the QMovie."; QLabel* label = new QLabel(this); label->setObjectName("label"); widget_width = width(); widget_height = height(); label->setGeometry(0, 0, widget_width, widget_height); label->setMovie(movie); label->show(); movie->setScaledSize(QSize().scaled(widget_width, widget_height, Qt::IgnoreAspectRatio)); movie->setSpeed(150); movie->start(); } // Pause for 2 seconds after getting into the // last frame. if (movie->currentFrameNumber() == (movie->frameCount() -1)) { movie->stop(); connect(timer, SIGNAL(timeout()), this, SLOT(resume())); timer->start(2000); } } public slots: void resume() { movie->start(); } };
疑问解答
1. 调用deleteLater()后将movie赋值为nullptr是否安全,会不会导致内存泄漏或未定义行为?
- 赋值
nullptr是安全的:deleteLater()只是向Qt事件队列发送对象销毁请求,对象在当前事件循环结束前仍存在,但后续代码中movie被置为nullptr,能避免悬空指针访问的问题,不会触发未定义行为。 - 不会内存泄漏:
deleteLater()会确保对象在合适时机被Qt事件循环销毁,内存会正常释放,不存在泄漏问题。 - 代码隐患:当前代码中
findChild<QLabel*>("label")可能返回nullptr(比如第一次执行paintEvent时还未创建label),直接调用label->deleteLater()会导致程序崩溃,建议先判断label是否非空再执行销毁操作。
2. 有没有QMovie的替代方案?因为播放中大型GIF时它占用的CPU过高。
可以尝试以下几种方案降低CPU占用:
- Qt Multimedia框架:使用
QMediaPlayer搭配QVideoWidget播放GIF,该框架会利用硬件加速能力,大幅降低CPU消耗。需要确保Qt环境配置了对应的多媒体解码支持。 - 自行解码GIF帧:借助第三方库(如giflib、SDL_image)手动解码GIF的每帧图像,然后在部件的
paintEvent中直接绘制缩放后的帧。这种方式可以自主控制渲染逻辑、帧率和缓存策略,优化性能。 - 优化QMovie的使用:如果继续使用QMovie,可以提前缓存缩放后的帧。比如在部件resize时,将GIF的所有帧预缩放到目标尺寸并存储在
QPixmapCache中,播放时直接读取缓存的图像,避免重复缩放计算。
内容的提问来源于stack exchange,提问作者Cesar
相关产品推荐
相关产品推荐

