Qt自定义图像显示控件(支持平移、缩放、横纵比自适应)

实现了基于Qt的图像查看器组件,主要包含两个核心类:ImageViewerWidget和ToolPanZoom。ImageViewerWidget作为图像显示控件,支持灰度图像和彩色图像显示,提供拖放文件、图像缩放和平移等功能。它通过转换矩阵数据为QImage实现可视化,并使用jet色彩映射增强显示效果。ToolPanZoom类实现了图像平移和缩放功能,通过鼠标事件处理实现交互式操作,并确保图像始终在可见区域内。关键技术点包括:1) 矩阵数据到QImage的转换算法;2) 基于变换矩阵的图像缩放和平移实现;3) 鼠标事件处理与坐标转换;4) 图像边界检查和限制逻辑。该组件可作为专业的图像处理工具的基础模块。

ImageViewerWidget.cpp

cpp 复制代码
#include "ImageViewerWidget.h"
#include <QPainter>
#include <QWheelEvent>
#include<QDebug>
#include <QMouseEvent>
#include<QHboxLayout>
#include <QtMath>
#include <QDragEnterEvent>
#include <QMimeData>
#include"Tools/ToolPanZoom.h"
#include<Tools/ToolManager.h>

ImageViewerWidget::ImageViewerWidget(QWidget *parent)
    : QWidget(parent),
      m_scale(1.0)
{    
    setMouseTracking(true);
		//m_imageWidget2->setFixedSize(m_imageWidget->width(), m_imageWidget->height());
		setAcceptDrops(true);
		installEventFilter(this);
		//m_pToolManager = new ToolManager(this);
		jetcolorinit(0, 0);

		m_imageWidget = new QWidget(this);
		m_imageWidget->installEventFilter(this);
}

void ImageViewerWidget::setToolManager(ToolManager* pToolManager)
{
	m_pToolManager = pToolManager;
	m_pToolManager->AddTool(new ToolPanZoom(), this);
	m_pToolManager->SetCurrentTool(EToolType::PanZoom);
}

ImageViewerWidget::~ImageViewerWidget()
{
	if (image_data)
	{
		delete[] image_data;
		image_data = nullptr;
	}
	delete m_imageWidget;
}

void ImageViewerWidget::setImage(const QImage& pixmap)
{
    m_pixmap = pixmap;
    resetZoom();
}

void ImageViewerWidget::setGray8Image(const QImage& pixmap)
{
	format = ImageDataFormat::IMAGE_8UC1;
	M_scale = 1.0;

	//数据
	image_Min = std::numeric_limits<float>::infinity();
	image_Max = -std::numeric_limits<float>::infinity();

	M_width = pixmap.width();//根据行进行设置
	M_height = pixmap.height();//根据列进行设置
	imageRatio = (qreal)M_width / M_height;
	m_pixmap = pixmap;
	resetZoom();
	update();
}

void ImageViewerWidget::jetcolorinit(float max, float min)
{
	int s;
	float component;
	if (max == 0 && min == 0)
		component = 1;
	else
		component = abs(max - min);
	//QColor(255, 101, 101)
	for (s = 0; s < max * 256; s++)
	{
		jet[s][0] = 255;
		jet[s][1] = 101;
		jet[s][2] = 101;

	}
	qDebug() << "max" << max << "min" << min << "component" << component << "max*255" << max * 255;
	for (s = 0; s < 32; s++) {
		jet[(int)(s * component + max * 256)][0] = 128 + 4 * s;
		jet[(int)s][1] = 0;
		jet[(int)s][2] = 0;

	}
	jet[(int)(32 * component + max * 256)][0] = 255;
	jet[(int)(32 * component + max * 256)][1] = 0;
	jet[(int)(32 * component + max * 256)][2] = 0;
	for (s = 0; s < 63; s++) {
		jet[(int)((33 + s) * component + max * 256)][0] = 255;
		jet[(int)((33 + s) * component + max * 256)][1] = 4 + 4 * s;
		jet[(int)((33 + s) * component + max * 256)][2] = 0;
	}
	jet[(int)(96 * component + max * 256)][0] = 254;
	jet[(int)(96 * component + max * 256)][1] = 255;
	jet[(int)(96 * component + max * 256)][2] = 2;
	for (s = 0; s < 62; s++) {
		jet[(int)((97 + s) * component + max * 256)][0] = 250 - 4 * s;
		jet[(int)((97 + s) * component + max * 256)][1] = 255;
		jet[(int)((97 + s) * component + max * 256)][2] = 6 + 4 * s;
	}
	jet[(int)(159 * component + max * 256)][0] = 1;
	jet[(int)(159 * component + max * 256)][1] = 255;
	jet[(int)(159 * component + max * 256)][2] = 254;
	for (s = 0; s < 64; s++) {
		jet[(int)((160 + s) * component + max * 256)][0] = 0;
		jet[(int)((160 + s) * component + max * 256)][1] = 252 - (s * 4);
		jet[(int)((160 + s) * component + max * 256)][2] = 255;
	}
	for (s = 0; s < 32; s++) {
		jet[(int)((224 + s) * component + max * 256)][0] = 0;
		jet[(int)((224 + s) * component + max * 256)][1] = 0;
		jet[(int)((224 + s) * component + max * 256)][2] = 252 - 4 * s;
	}
	for (int s = (255 * component + max * 256); s < 256; s++)
	{
		jet[s][0] = 0;
		jet[s][1] = 0;
		jet[s][2] = 128;
	}
}

void  ImageViewerWidget::convertMatToQImage(double** mat, int m_width, int m_height, float min, float max)
{

	qDebug() << "m_width" << m_width << "m_height" << m_height << "min" << min << max;
	m_pixmap = QImage(m_width, m_height, QImage::Format_RGB32);
	double vlie = (double)256 / (abs(max - min));
	m_pixmap.fill(255);
	// Set the color table (used to translate colour indexes to qRgb values)
	// Copy input MatM_range
	for (int i = 0; i < m_height; i++)
	{
		for (int j = 0; j < m_width; j++)
		{
			if (std::isnan(mat[i][j]))
			{
				m_pixmap.setPixelColor(j, i, QColor(255, 255, 255));
			}
			else
			{
				int num = abs((mat[i][j] - min) * vlie);
				if (num >= 255)
					num = 255;
				m_pixmap.setPixelColor(j, i, QColor(jet[255 - num][0],
					jet[255 - num][1], jet[255 - num][2]));
			}
		}
	}
	// Set the color table (used to translate colour indexes to qRgb values)
}

void ImageViewerWidget::setimagedata(double** mat1, int width, int height, float scale, QVector<QPoint>NANVEC)
{
	if (mat1 == nullptr)//一定要先判断是否为空,不为空再判断矩阵中是否有值
		return;

	QVector<double> local_vec;//
	for (int i = 0; i < NANVEC.size(); i++)
	{
		local_vec.push_back(mat1[NANVEC[i].x()][NANVEC[i].y()]);
		mat1[NANVEC[i].x()][NANVEC[i].y()] = NAN;
	}
	M_scale = scale;
	image_data = mat1;
	NAN_Vec = NANVEC;

	//数据
	image_Min = std::numeric_limits<float>::infinity();
	image_Max = -std::numeric_limits<float>::infinity();

	M_width = width;//根据行进行设置
	M_height = height;//根据列进行设置
	imageRatio = (qreal)M_width / M_height;

	resetZoom();

	//if (ratio_image > ratio_widget) {
	//	XY_unit_scale = (float)m_imageWidget->width() / M_width;
	//}
	//else {
	//	XY_unit_scale = (float)m_imageWidget->height() / M_height;
	//}
	////
	
	int i, j;
	float z;

	for (i = 1; i <= M_height; i++)
	{
		int index = 0;
		for (j = 1; j <= M_width; j++)
		{
			z = image_data[i - 1][j - 1] * Z_unit_scale;
			if (!std::isnan(z))
			{
				if (z > image_Max)
					image_Max = z;
				if (z < image_Min)
					image_Min = z;
			}
		}
	}

	convertMatToQImage(image_data, M_width, M_height, image_Min / Z_unit_scale, image_Max / Z_unit_scale);
	for (int i = 0; i < NANVEC.size(); i++)
	{
		mat1[NANVEC[i].x()][NANVEC[i].y()] = local_vec.at(i);
	}
	//emit Send_Jet_Range(image_Min, image_Max, graph3D->axisY()->labelFormat());

	update();
}

QImage ImageViewerWidget::image() const
{
    return m_pixmap;
}

QRectF ImageViewerWidget::getImageRect() const
{
	auto pt1 = imageToWindow(QPointF(0, 0));
	auto pt2 = imageToWindow(QPointF(M_width-1, M_height-1));
	QRectF result;
	result.setX(pt1.x());
	result.setY(pt1.y());
	result.setWidth(pt2.x() - pt1.x() + 1);
	result.setHeight(pt2.y() - pt1.y() + 1);
	return result;
}

QRectF ImageViewerWidget::getImageWidgetRect() const 
{
	return m_imageWidget->rect();
}

int ImageViewerWidget::getImageWidth() const
{
	return M_width;
}

int ImageViewerWidget::getImageHeight() const
{
	return M_height;
}

bool ImageViewerWidget::isimageValid() const
{
	if (M_width == 0 || M_height == 0)
		return false;
	return true;
}

void ImageViewerWidget::resetZoom()
{
    if (isimageValid()) 
		{
				m_transform.reset();
				m_transform.scale(m_scale, m_scale);
				m_transform_init = m_transform;
    }
}

double ImageViewerWidget::zoomFactor() const
{
    return m_scale * m_zoomFactor;
}

void ImageViewerWidget::onPaintEvent(QPaintEvent *event)
{
	Q_UNUSED(event);

	QPainter painter(m_imageWidget);
	painter.setRenderHint(QPainter::SmoothPixmapTransform);
	painter.fillRect(rect(), QColor(240, 240, 240));

	if (!m_pixmap.isNull())
	{
		if (format == ImageDataFormat::IMAGE_8UC1)
		{
			if (m_bHighlightSaturation)
			{
				QImage tmp = m_pixmap.convertToFormat(QImage::Format_ARGB32);
				
				for (int y = 0; y < M_height; ++y) 
				{
					const uchar* line = m_pixmap.constScanLine(y);  // 每行首地址[^3^]
					for (int x = 0; x < M_width; ++x) 
					{
						if (line[x] >= m_uSaturationThreshold)
						{
							tmp.setPixelColor(QPoint(x, y), Qt::red);
						}
					}
				}

				painter.setWorldTransform(m_transform);
				QRectF source(0.0, 0.0, M_width, M_height);
				painter.drawImage(0, 0, tmp, Qt::ColorOnly);
			}
			else
			{
				painter.setWorldTransform(m_transform);
				QRectF source(0.0, 0.0, M_width, M_height);
				painter.drawImage(0, 0, m_pixmap, Qt::ColorOnly);
			}
		}
		else if (format == ImageDataFormat::IMAGE_64FC1)
		{
			painter.setWorldTransform(m_transform);
			QRectF source(0.0, 0.0, M_width, M_height);
			painter.drawImage(0, 0, m_pixmap, Qt::ColorOnly);
		}		
	}
	else {
		QImage imag = QImage(100, 100, QImage::Format_RGB32);
		imag.fill(QColor(255, 255, 255));
		QPainter mypainter(this);
		mypainter.setRenderHint(QPainter::Antialiasing);
		QPen pen;
		pen.setColor(QColor(0, 0, 120));
		pen.setWidth(2);
		mypainter.setPen(pen);
		QRectF target(0, 0, this->width(), this->height());
		QRectF source(0.0, 0.0, 100, 100);
		mypainter.drawImage(target, imag, source, Qt::ColorOnly);
		return QWidget::paintEvent(event);
	}

	//QTransform tmpTrans;
	//tmpTrans.reset();
	//painter.setWorldTransform(tmpTrans);
	//painter.setPen(QPen(Qt::red, 2, Qt::DashLine));  // 红色虚线,宽度2px
	//painter.drawRect(rect().adjusted(1, 1, -1, -1));  // 向内缩进1px避免溢出

	return QWidget::paintEvent(event);
}

void ImageViewerWidget::mousePressEvent(QMouseEvent* event)
{
	if (!m_pixmap.isNull())
	{
		if (event->button() == Qt::RightButton)
		{
			//// 右键点击获取像素坐标
			//QPoint pixelPos = windowToImage(event->pos());
			//if (m_pixmap.rect().contains(pixelPos)) {
			//	emit pixelSelected(pixelPos);
			//}
		}
	}
}

void ImageViewerWidget::mouseMoveEvent(QMouseEvent* event)
{
}

void ImageViewerWidget::mouseReleaseEvent(QMouseEvent *event)
{
}

void ImageViewerWidget::wheelEvent(QWheelEvent *event)
{
}

QPoint ImageViewerWidget::windowToImage(const QPoint& windowPos) const
{
	QTransform invTransform = m_transform.inverted();
	return invTransform.map(windowPos);
}

QPointF ImageViewerWidget::windowToImage(const QPointF &windowPos) const
{
	QTransform invTransform = m_transform.inverted();
	return invTransform.map(windowPos);
}

QPointF ImageViewerWidget::imageToWindow(const QPointF& imagePos) const
{
	return m_transform.map(imagePos);
}

QPoint ImageViewerWidget::imageToWindow(const QPoint& imagePos) const
{
	return m_transform.map(imagePos);
}

void ImageViewerWidget::updateShow()
{
	update();
}

void ImageViewerWidget::setImageCursor(const QCursor& cursor)
{
	setCursor(cursor);
}

void ImageViewerWidget::resizeEvent(QResizeEvent* event)
{
	Q_UNUSED(event);
	if (!m_pixmap.isNull()) {
		resetZoom();
	}
}

bool ImageViewerWidget::eventFilter(QObject* watched, QEvent* event)
{
	auto toolType = EToolType::DefaultNull; 
	if (m_pToolManager && m_pToolManager->CurrentTool())
	{
		toolType = m_pToolManager->CurrentTool()->GetType();
	}
	if (!m_pixmap.isNull())
	{
		if (watched == m_imageWidget)
		{
			if (m_pToolManager)
			{
				switch (event->type())
				{
				case QEvent::MouseButtonPress:
					m_pToolManager->MouseDown(static_cast<QMouseEvent*>(event));
					break;
				case QEvent::MouseMove:
					m_pToolManager->MouseMove(static_cast<QMouseEvent*>(event));
					break;
				case QEvent::MouseButtonRelease:
					m_pToolManager->MouseUp(static_cast<QMouseEvent*>(event));
					break;
				case QEvent::Wheel:
					if (toolType != EToolType::PanZoom && m_pToolManager)
						m_pToolManager->SetCurrentTool(EToolType::PanZoom);

					m_pToolManager->MouseWheel(static_cast<QWheelEvent*>(event));

					if (toolType != EToolType::PanZoom && m_pToolManager)
						m_pToolManager->SetCurrentTool(toolType);
					break;
				}
			}
			this->onPaintEvent(static_cast<QPaintEvent*>(event));
		}
			
			switch (event->type())
			{
			case QEvent::DragEnter:  // 拖入时
			{
				isDropingFile = true;
				QDragEnterEvent* dragEvent = static_cast<QDragEnterEvent*>(event);
				if (dragEvent->mimeData()->hasUrls())  // 检查是否有文件
				{
					dragEvent->acceptProposedAction();  // 接受拖放
					return true;  // 事件已处理
				}
				break;
			}
			case QEvent::Drop:  // 放下时
			{
				QDropEvent* dropEvent = static_cast<QDropEvent*>(event);
				const QMimeData* mimeData = dropEvent->mimeData();

				if (mimeData->hasUrls())  // 检查是否有文件
				{
					QList<QUrl> urlList = mimeData->urls();
					for (const QUrl& url : urlList)
					{
						QString filePath = url.toLocalFile();  // 获取文件路径
						qDebug() << "Dropped file:" << filePath;
						//emit fileDropped(filePath);  // 发射信号
						QPixmap pixmap;
						try {
							pixmap.load(filePath);
							QImage image = pixmap.toImage().convertToFormat(QImage::Format_Grayscale8);
							setGray8Image(image);
							//convertToImageData(image);
							//setimagedata(image_data, image.width(), image.height(), 1.0, QVector<QPoint>());
							emit updateImageData(image_data, image.width(), image.height(), 1.0);
							resetImageWidget();
						}
						catch (const std::exception& e) {
							qCritical() << "Exception caught:" << e.what();
						}
					}
					dropEvent->acceptProposedAction();  // 接受拖放
					isDropingFile = false;
					return true;  // 事件已处理
				}
				break;
			}
			default:
				break;
			}
			this->onPaintEvent(static_cast<QPaintEvent*>(event));
		}
	return QWidget::eventFilter(watched, event);
}

bool ImageViewerWidget::isInImageWidget(QPoint pt)
{
	return m_imageWidget->rect().contains(pt);
}

void ImageViewerWidget::convertToImageData(QImage& image)
{
	const int img_width = image.width();
	const int img_height = image.height();
	const int totalPixels = img_width * img_height;
	if (image_data)
	{
		delete[] image_data;
		image_data = nullptr;
	}
	image_data = new double* [img_height];

	// 遍历像素并转换
	for (int y = 0; y < img_height; ++y) {
		image_data[y] = new double[img_width];
		const uchar* scanLine = image.constScanLine(y); // 获取一行像素数据
		for (int x = 0; x < img_width; ++x) {
			double pixelValue = static_cast<double>(scanLine[x]);
			image_data[y][x] = pixelValue;
		}
	}
}

void ImageViewerWidget::Set_Range_Max(float max, float Min)
{
	if (image_data == nullptr)
		return;
	jetcolorinit(max, Min);
	convertMatToQImage(image_data, M_width, M_height, image_Min, image_Max);
	//
	max = abs(max - Min);
	//qDebug()<<"Max"<<max<<"Min"<<Min;
	QLinearGradient gr;
	gr.setColorAt(0.0, QColor(0, 0, 255));
	gr.setColorAt(1 - Min, QColor(0, 0, 255));
	gr.setColorAt(1 - Min + max / 4, QColor(0, 255, 255));
	gr.setColorAt(1 - Min + (max / 4) * 2, QColor(0, 255, 0));
	gr.setColorAt(1 - Min + (max / 4) * 3, QColor(255, 255, 0));
	gr.setColorAt(1 - Min + max, QColor(255, 0, 0));
	gr.setColorAt(1 - Min + max + 0.01, QColor(255, 101, 101, 255));
	gr.setColorAt(1.0, QColor(255, 101, 101, 255));

	emit UpdateSurfaceColorMap(gr);
}

void ImageViewerWidget::resetImageWidget()
{
	if (isimageValid())
	{
		canvasRatio = (qreal)width() / height();

		if (imageRatio > canvasRatio) {
			// 以宽度为基准,图像宽占满canvas
			qreal height = std::round(width() / imageRatio);
			targetRect = QRectF(0, (this->height() - height) / 2, width(), height);
			m_scale = (double)width() / getImageWidth();
		}
		else {
			// 以高度为基准,图像高占满canvas
			qreal width = std::round(height() * imageRatio);
			targetRect = QRectF((this->width() - width) / 2, 0, width, height());
			m_scale = (double)height() / getImageHeight();
		}

		m_imageWidget->setGeometry(targetRect.x(),targetRect.y(),targetRect.width(), targetRect.height());

		resetZoom();
		update();
	}
}

ToolPanZoom.cpp

cpp 复制代码
#include "ToolPanZoom.h"
#include <QMouseEvent>
#include <QWheelEvent>
#include <QMessageBox>
#include "ToolManager.h"
#include <QtMath>
#include<QDebug>
#include "ImageViewerWidget.h"

ToolPanZoom::ToolPanZoom(ToolManager* pCmdMgr/* = nullptr*/)
	: ITool(pCmdMgr),
	m_isDragging(false)
{
	type = EToolType::DrawMask;
	m_zoomTimer.start();
}

bool ToolPanZoom::IsEnable()
{
  if (nullptr == m_pImageViewerWidget)
  {
		ImageViewerWidget* pWidget = qobject_cast<ImageViewerWidget*>(m_pHookWidget);
    if (pWidget)
    {
      m_pImageViewerWidget = pWidget;
    }
    else
      return false;
  }
  return true;
}

void ToolPanZoom::MouseDown(QMouseEvent* event)
{
		if (IsEnable() && m_pImageViewerWidget->isInImageWidget(event->pos()))
    {
			if (event->button() == Qt::LeftButton) {
				m_lastDragPos = event->pos();
				m_isDragging = true;
        m_pImageViewerWidget->setImageCursor(Qt::ClosedHandCursor);
			}
    }
}

void ToolPanZoom::MouseMove(QMouseEvent* event)
{
    if (IsEnable() && m_pImageViewerWidget->isInImageWidget(event->pos()))
    {
        if (m_pImageViewerWidget->isViewLocked())
        {
            return;
        }

				if (m_isDragging) 
        {
					qDebug() << "mouse move in";
					// 计算移动距离
					QPoint delta = event->pos() - m_lastDragPos;
					m_lastDragPos = event->pos();

					// 获取当前变换后的图像边界
					QRectF imageRect = m_pImageViewerWidget->getImageRect();
					qDebug() << "max" << imageRect.x() << " " << imageRect.y();


					QRectF widgetRect = m_pImageViewerWidget->getImageWidgetRect();

					// 计算平移后的位置
					qreal dx = delta.x() / m_pImageViewerWidget->zoomFactor();
					qreal dy = delta.y() / m_pImageViewerWidget->zoomFactor();

					// 检查平移后是否会显示图像内部空白
					QRectF translatedRect = imageRect.translated(dx, dy);

					// 限制平移范围
					if (translatedRect.left() > widgetRect.left()) {
						dx = widgetRect.left() - imageRect.left();
						dx /= m_pImageViewerWidget->zoomFactor();
					}
					if (translatedRect.right() < widgetRect.right()) {
						dx = widgetRect.right() - imageRect.right();
						dx /= m_pImageViewerWidget->zoomFactor();
					}
					if (translatedRect.top() > widgetRect.top()) {
						dy = widgetRect.top() - imageRect.top();
						dy /= m_pImageViewerWidget->zoomFactor();
					}
					if (translatedRect.bottom() < widgetRect.bottom()) {
						dy = widgetRect.bottom() - imageRect.bottom();
						dy /= m_pImageViewerWidget->zoomFactor();
					}

					// 应用限制后的平移
					m_pImageViewerWidget->m_transform.translate(dx, dy);
          m_pImageViewerWidget->updateShow();
					qDebug() << "mouse move out";
				}
    }
}

void ToolPanZoom::MouseUp(QMouseEvent* event)
{
	if (event->button() == Qt::LeftButton && m_isDragging) 
  {
		m_isDragging = false;
    m_pImageViewerWidget->setImageCursor(Qt::ArrowCursor);
	}
}

void ToolPanZoom::MouseWheel(QWheelEvent* event)
{
	if (IsEnable() && m_pImageViewerWidget->isInImageWidget(event->pos()))
	{
		if (m_zoomTimer.elapsed() > 30) {
			m_zoomTimer.restart();

			// 获取鼠标位置作为缩放中心
			QPointF mousePos = event->position();

			// 计算缩放因子
			double angle = event->angleDelta().y();
			double factor = qPow(1.0015, angle);

			scaleImage(factor, mousePos);
		}
	}
}

void ToolPanZoom::KeyDown(QKeyEvent* event)
{
	/*switch (event->key())
	{
	case Qt::Key_Space:
			break;
	default:
			break;
	}*/
}

void ToolPanZoom::scaleImage(double factor, const QPointF& center)
{
	// 限制缩放范围
	double newZoomFactor = m_pImageViewerWidget->m_zoomFactor * factor;
	if (newZoomFactor < 1.0)
		newZoomFactor = 1.0;
	if (newZoomFactor > 100) {
		return;
	}
	m_pImageViewerWidget->m_zoomFactor = newZoomFactor;

	double finalZoom = m_pImageViewerWidget->zoomFactor();

	// 获取当前图像和窗口的矩形
	QRectF widgetRect = m_pImageViewerWidget->getImageWidgetRect();

	if (!center.isNull()) {
		// 计算当前鼠标位置的图片坐标
		QPointF imagePos = m_pImageViewerWidget->windowToImage(center.toPoint());


		// 重置变换矩阵并应用新缩放
		m_pImageViewerWidget->m_transform.reset();
		m_pImageViewerWidget->m_transform.scale(m_pImageViewerWidget->zoomFactor(), m_pImageViewerWidget->zoomFactor());

		// 计算缩放后鼠标应该对应的窗口坐标
		QPointF targetWindowPos = center;

		// 计算当前鼠标实际会对应的窗口坐标
		QPointF actualWindowPos = m_pImageViewerWidget->m_transform.map(imagePos);

		// 计算需要调整的平移量
		QPointF delta = targetWindowPos - actualWindowPos;
		if(newZoomFactor > 1.0)
			m_pImageViewerWidget->m_transform.translate(delta.x() / finalZoom, delta.y() / finalZoom);
		// 检查缩放后图像边界是否在widget内部
		//QRectF transformedRect = m_pImageViewerWidget->m_transform.mapRect(imageRect);
		QRectF transformedRect = m_pImageViewerWidget->getImageRect();

		qreal dx = 0, dy = 0;

		if (transformedRect.left() > widgetRect.left()) {
			dx = widgetRect.left() - transformedRect.left();
		}
		if (transformedRect.right() < widgetRect.right()) {
			dx = widgetRect.right() - transformedRect.right();
		}
		if (transformedRect.top() > widgetRect.top()) {
			dy = widgetRect.top() - transformedRect.top();
		}
		if (transformedRect.bottom() < widgetRect.bottom()) {
			dy = widgetRect.bottom() - transformedRect.bottom();
		}

		m_pImageViewerWidget->m_transform.translate(dx / finalZoom, dy / finalZoom);
	}

	m_pImageViewerWidget->updateShow();
}
相关推荐
不断努力的根号七3 小时前
qt框架,使用webEngine如何调试前端
开发语言·前端·qt
范纹杉想快点毕业11 小时前
基于C语言的Zynq SOC FPGA嵌入式裸机设计和开发教程
c语言·开发语言·数据库·嵌入式硬件·qt·fpga开发·嵌入式实时数据库
程序员编程指南12 小时前
Qt容器类:QList、QMap等的高效使用
c语言·开发语言·c++·qt
程序员编程指南13 小时前
Qt 元对象系统(Meta-Object System)解析
c语言·开发语言·c++·qt
XXYBMOOO13 小时前
使用全局变量访问 Qt UI 组件的方法文档
c++·qt·ui
kaikaile199516 小时前
基于Qt的仿QQ聊天系统设计
开发语言·qt
钱彬 (Qian Bin)17 小时前
《使用Qt Quick从零构建AI螺丝瑕疵检测系统》——4. 前后端联动:打通QML与C++的任督二脉
c++·qt·教程·qml·qt quick·qt 6.9.1·工业瑕疵检测
进击ing小白18 小时前
Qt WebEngine Widgets的使用
开发语言·qt
Logcater1 天前
Linux和Windows基于V4L2和TCP的QT监控
linux·c++·qt·嵌入式·camera·v4l2