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();
}
相关推荐
用户8055336980310 小时前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner10 小时前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz5 天前
QML Hello World 入门示例
qt
xcyxiner8 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner9 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner9 天前
DicomViewer (添加模型类)3
qt
xcyxiner10 天前
DicomViewer (目录调整) 2
qt
xcyxiner10 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
桥田智能12 天前
桥田智能 QT-650S:面向白车身焊装的 800kg 重载快换解决方案
开发语言·qt·系统架构
森G12 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt