余思洁 发表于 3 天前

解决Qt重绘事件中进行了耗时的图片操作导致卡顿问题

先简单描述一下我出现的问题,我是在写一个聊天界面,然后对于图片消息来说,一旦图片比较大时,滑动聊天界面就会出现了明显卡顿情况,原因是和我在写这个ImageMessage时直接在paintEvent中就进行了耗时的图片操作,也是我对于重绘事件的不够了解导致的
在c++ - Stabilize QWidget::paintEvent() calls frequency - Stack Overflow
QWidget Class | Qt Widgets | Qt 6.9.1中可以看到.大致告诉我们在paintEvent中不要进行一些其他的操作,他只负责绘制.

我这个MessageImage就是左下角这个长矩形,有点难度的地方在这个如何计算图片放置的位置,需要用到父元素来计算,我在解决卡顿时把updateUi从paintEvent直接提出来就出现了父元素为NULL,因为我使用MessageImage没有直接传父元素给构造函数,而是先创建在放入layout中,也就导致了更新ui时出现父元素为空的情况,然后我采用的是新增一个字段表示是否完成ui更新,updateUI将state设置为false__updateUi在父元素为空时会直接返回没有更新图片和state,然后让showEvent去再判断是否成功了,没成功再执行 一次 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;
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 __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;
}
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 解决Qt重绘事件中进行了耗时的图片操作导致卡顿问题