如何在Qt Widgets中实现类似PreserveAspectFit的图片等比自适应显示
Qt Widgets 实现等比自适应图片显示方案
Qt Widgets 没有原生内置的专门图片组件直接提供和QML Image 对等的fillMode、自动适配等能力,但可以通过两种低成本的方式实现完全相同的效果。
方案1:自定义ImageWidget(推荐,轻量无额外依赖)
直接继承QWidget,几十行代码就能实现和QML Image.PreserveAspectFit 完全一致的效果,支持自动响应窗口大小变化,性能开销极低。
头文件 imagewidget.h
#ifndef IMAGEWIDGET_H #define IMAGEWIDGET_H #include <QWidget> #include <QPixmap> class ImageWidget : public QWidget { Q_OBJECT public: explicit ImageWidget(QWidget *parent = nullptr); // 设置要显示的图片 void setPixmap(const QPixmap& pixmap); protected: void paintEvent(QPaintEvent *event) override; void resizeEvent(QResizeEvent *event) override; private: QPixmap m_pixmap; }; #endif // IMAGEWIDGET_H
实现文件 imagewidget.cpp
#include "imagewidget.h" #include <QPainter> ImageWidget::ImageWidget(QWidget *parent) : QWidget{parent} {} void ImageWidget::setPixmap(const QPixmap &pixmap) { m_pixmap = pixmap; update(); } void ImageWidget::paintEvent(QPaintEvent *event) { Q_UNUSED(event); if (m_pixmap.isNull()) return; QPainter painter(this); // 开启平滑变换,提升缩放后图片质量 painter.setRenderHint(QPainter::SmoothPixmapTransform); // 计算等比缩放后的图片尺寸,保持宽高比适配控件大小,不裁切 QRect drawRect = m_pixmap.rect(); drawRect.scale(rect(), Qt::KeepAspectRatio); // 图片居中显示 drawRect.moveCenter(rect().center()); painter.drawPixmap(drawRect, m_pixmap); } void ImageWidget::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); // 控件尺寸变化时触发重绘,自动调整图片大小 update(); }
使用示例
你可以像普通QWidget一样把它放入任意布局中,用法和QML的Image组件基本一致:
ImageWidget *imgWidget = new ImageWidget(this); imgWidget->setPixmap(QPixmap("/path/to/your/image")); // 加入父控件布局后即可自动适配父控件大小 ui->verticalLayout->addWidget(imgWidget);
如果需要实现QML里的其他填充模式,只需要修改drawRect.scale的第二个参数即可:
Qt::KeepAspectRatio等价于Image.PreserveAspectFit:等比缩放完整显示图片,无裁切Qt::KeepAspectRatioByExpanding等价于Image.PreserveAspectCrop:等比缩放填满控件,超出部分裁切Qt::IgnoreAspectRatio等价于Image.Stretch:拉伸填充满控件,不保持宽高比
方案2:基于QGraphicsView实现(无需自定义控件)
如果你不想自定义组件,也可以用Qt自带的Graphics View框架快速实现,适合需要额外图片交互(缩放、拖拽标注)的场景:
QGraphicsView *view = new QGraphicsView(this); view->setStyleSheet("border: none;"); // 去掉默认边框 QGraphicsScene *scene = new QGraphicsScene(this); QGraphicsPixmapItem *item = scene->addPixmap(QPixmap("/path/to/your/image")); item->setTransformationMode(Qt::SmoothTransformation); view->setScene(scene); // 首次适配 view->fitInView(item, Qt::KeepAspectRatio); // 给view安装事件过滤器,大小变化时重新适配即可 bool eventFilter(QObject *obj, QEvent *event) override { if (obj == view && event->type() == QEvent::Resize) { view->fitInView(item, Qt::KeepAspectRatio); } return QWidget::eventFilter(obj, event); }
该方案的缺点是Graphics View框架重量更高,仅做简单图片显示时性能不如自定义Widget方案。
内容的提问来源于stack exchange,提问作者LightSith
相关产品推荐
相关产品推荐

