解決Qt重繪事件中進(jìn)行了耗時(shí)的圖片操作導(dǎo)致卡頓問題
先簡單描述一下我出現(xiàn)的問題,我是在寫一個(gè)聊天界面,然后對(duì)于圖片消息來說,一旦圖片比較大時(shí),滑動(dòng)聊天界面就會(huì)出現(xiàn)了明顯卡頓情況,原因是和我在寫這個(gè)ImageMessage時(shí)直接在paintEvent中就進(jìn)行了耗時(shí)的圖片操作,也是我對(duì)于重繪事件的不夠了解導(dǎo)致的
在c++ - Stabilize QWidget::paintEvent() calls frequency - Stack Overflow
QWidget Class | Qt Widgets | Qt 6.9.1中可以看到.大致告訴我們?cè)趐aintEvent中不要進(jìn)行一些其他的操作,他只負(fù)責(zé)繪制.

我這個(gè)MessageImage就是左下角這個(gè)長矩形,有點(diǎn)難度的地方在這個(gè)如何計(jì)算圖片放置的位置,需要用到父元素來計(jì)算,我在解決卡頓時(shí)把updateUi從paintEvent直接提出來就出現(xiàn)了父元素為NULL,因?yàn)槲沂褂肕essageImage沒有直接傳父元素給構(gòu)造函數(shù),而是先創(chuàng)建在放入layout中,也就導(dǎo)致了更新ui時(shí)出現(xiàn)父元素為空的情況,然后我采用的是新增一個(gè)字段表示是否完成ui更新,updateUI將state設(shè)置為false__updateUi在父元素為空時(shí)會(huì)直接返回沒有更新圖片和state,然后讓showEvent去再判斷是否成功了,沒成功再執(zhí)行 一次 updateUi,這樣就將原本卡頓的顯示解決了.
20250826
今天重新查看,發(fā)現(xiàn)有個(gè)問題resize后氣泡和圖片沒有更新,所以需要給resizeEvent中新增__updateui
class MessageImage : public QWidget {
Q_OBJECT
public:
MessageImage(const QString& fileId,const QByteArray& content, bool isLeft);
void updateUI(const QString& fileId, const QByteArray& content);
protected:
void paintEvent(QPaintEvent* event) override;
void showEvent(QShowEvent* event) override;
void resizeEvent(QResizeEvent* event) override;
private:
void __updateUi();
private:
QPushButton* image;
QString fileId;
QPixmap image_pixmap;
bool isLeft;
bool state; // 0 -- 未更新
};
//==========================================================================================
MessageImage::MessageImage(const QString& fileId, const QByteArray& content, bool isLeft)
:isLeft(isLeft),fileId(fileId),state(false)
{
this->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
this->setStyleSheet("QPushButton{border:none;} QWidget{background-color:red}");
image = new QPushButton(this);
if (content.isEmpty()) {
model::DataCenter* dataCenter = model::DataCenter::getInstance();
connect(dataCenter, &model::DataCenter::getSingleFileDone, this,&MessageImage::updateUI,Qt::UniqueConnection);
dataCenter->getSingleFileAsync(fileId);
}
else {
updateUI(fileId, content);
}
}
void MessageImage::updateUI(const QString& fileId, const QByteArray& content)
{
if (this->fileId.isEmpty() || content.isEmpty()) {
return;
}
this->fileId = fileId;
__scaledImageToWidth(content, image_pixmap);
this->state = false;
__updateUi();
this->update();
}
void MessageImage::showEvent(QShowEvent* event)
{
QWidget::showEvent(event);
if (!state) {
__updateUi();
}
}
void MessageImage::paintEvent(QPaintEvent* event)
{
Q_UNUSED(event);
QWidget::paintEvent(event);
}
void MessageImage::resizeEvent(QResizeEvent* event)
{
QWidget::resizeEvent(event);
__updateUi();
}
void __scaledImageToWidth(const QByteArray& body,__out QPixmap& pixmap) {
pixmap.loadFromData(body);
pixmap = pixmap.scaledToWidth(120, Qt::SmoothTransformation);
}
void MessageImage::__updateUi() {
QObject* obj = this->parent();
if (obj == nullptr || !obj->isWidgetType()) {
return;
}
QWidget* parent = dynamic_cast<QWidget*> (obj);
if (image_pixmap.isNull()) {
image_pixmap.load(":/resource/images/xiaoju.jpg");
}
QRect r = image_pixmap.rect();
qDebug() << "image rect " << r;
parent->setMinimumHeight(r.height() + 30);
image->setIconSize(QSize(r.width(), r.height()));
image->setIcon(QIcon(image_pixmap));
if (isLeft) {
image->setGeometry(0, 0, r.width(), r.height());
}
else {
image->setGeometry(parent->width() - r.width() - 65, 0, r.width(), r.height());
}
this->state = true;
}

浙公網(wǎng)安備 33010602011771號(hào)