vc++ GDI+实现以鼠标为中心缩放图片(并且可以拖动)

2024-06-04 05:48

本文主要是介绍vc++ GDI+实现以鼠标为中心缩放图片(并且可以拖动),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

按以下步骤操作,即可实现。

1. 首先创建一个基于对话框的MFC程序,然后把下面两个文件分别保存为.h文件和 .cpp文件

//InitGdiplus.h
#pragma once

#include <GdiPlus.h>
using namespace Gdiplus;

class CInitGdiplus
{
public:
    CInitGdiplus(void);
    ~CInitGdiplus(void);

private:
    ULONG_PTR m_GdiplusToken;
    GdiplusStartupInput gdiplusStartupInput;
};
 

---------------------------------------------------------------------------------------------------------------------

//InitGdiplus.cpp
#include "StdAfx.h"
#include "InitGdiplus.h"


CInitGdiplus::CInitGdiplus(void)
{
    GdiplusStartup(&m_GdiplusToken, &gdiplusStartupInput, NULL);
}


CInitGdiplus::~CInitGdiplus(void)
{
    GdiplusShutdown(m_GdiplusToken);
}

 

2. 然后在stdafx.h中包含上述头文件,在YourApp类中添加一个 CInitGdiplus m_InitGdiplus; 成员变量,完成GDI+的初始化;

  • 在有Dlg类中添加如下成员变量

 

REAL m_zoom;  //缩放系数

CRect m_Rect; //对话框的矩形区域

REAL m_imgX; //图片左上角X轴偏移量
REAL m_imgY; //图片左上角Y轴偏移量

PointF m_PtStart;    //按下鼠标左键,记录当前的m_imgX,m_imgY
PointF m_mouseDown;  //按下鼠标左键时,鼠标在图片控件中的位置;
bool m_mousepressed; //记录是否按下了鼠标左键

3. 初始化成员变量:

m_zoom = 1.0f;

m_imgX = 0.0f;
m_imgY = 0.0f;
m_PtStart.X = 0.0f;
m_PtStart.Y = 0.0f;

m_mousepressed = false;
 

4. 在OnInitDialog()中添加

GetClientRect(m_Rect); //在你的实际应用中,可能需要把这行添加到对话框的OnSize()中
 

5. 添加下面两个成员函数

//双缓冲绘图
void CTestPic2Dlg::Invalidate()
{
    
        HDC hdc = ::GetDC(m_hWnd);
        CDC dc;
        dc.Attach(hdc);
        CDC memDC;
        CBitmap MemBitmap;
        // 设备描述表初始化
        memDC.CreateCompatibleDC(NULL);
        // 建立与屏幕显示兼容的内存显示设备
        MemBitmap.CreateCompatibleBitmap(&dc, m_Rect.Width(), m_Rect.Height());
        // 选取空白位图
        memDC.SelectObject(MemBitmap);
        memDC.FillSolidRect(0, 0, m_Rect.Width(), m_Rect.Height(), RGB(255,255,255));
        //画图
        Draw(&memDC);
        //拷贝到控件DC
        dc.BitBlt(0, 0, m_Rect.Width(), m_Rect.Height(), &memDC, 0, 0, SRCCOPY);
        MemBitmap.DeleteObject();
        memDC.DeleteDC();
        dc.Detach();
        ::ReleaseDC(m_hWnd,hdc);
}

void CTestPic2Dlg::Draw(CDC *pDC)
{
    Image img(_T("003.jpg")); //注意,请设置你自己的图片
    Graphics graph(pDC->GetSafeHdc());
    graph.SetInterpolationMode(InterpolationModeHighQualityBilinear); //设置缩放质量
    graph.ScaleTransform(m_zoom, m_zoom);                             //缩放
    graph.DrawImage(&img, m_imgX, m_imgY);                            //m_imgX,m_imgY是原图应该偏移的量
}
 

6. 在OnPaint中添加Invalidate(); 完成初始化显示

7. 分别给对话框添加下面四个消息响应

  1. WM_MOUSEMOVE
  2. WM_MOUSEWHEEL
  3. WM_LBUTTONDOWN
  4. WM_LBUTTONUP

8. 

void CTestPic2Dlg::OnMouseMove(UINT nFlags, CPoint point)
{
    if(nFlags & MK_LBUTTON)
    {
        REAL deltaX = point.x - m_mouseDown.X; //x轴方向偏移
        REAL deltaY = point.y - m_mouseDown.Y; //y轴方向偏移

        m_imgX =(m_PtStart.X + (deltaX/m_zoom)); //在原始图像中X坐标偏移,这里计算的是在原始图片中的位移,原因在上面已经说明,全局的仿射变换会影响实际的位移
        m_imgY =(m_PtStart.Y + (deltaY/m_zoom)); //在原始图像中Y坐标偏移
        Invalidate();                            //重绘
    }
    CDialogEx::OnMouseMove(nFlags, point);
}

BOOL CTestPic2Dlg::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
    REAL oldzoom = m_zoom; //保存当前的缩放系数,用于计算当前滚动时的坐标
    CPoint ppt = pt;
    CRect rect;
    if (zDelta == 120)
    {
        m_zoom += 0.4f;
    }
    if (zDelta == -120)
    {
        m_zoom = m_zoom - 0.4f;
    }

    GetWindowRect(rect); //注意这里的区域是窗口相对于整个屏幕的,因为cpoint pt这个点是相对于屏幕的

    ppt.x -= rect.left; //计算该点在对话框中的位置
    ppt.y -= rect.top;

    int x = ppt.x - m_Rect.left;
    int y = ppt.y - m_Rect.top;

    REAL oldimagex = (x / oldzoom); //缩放前鼠标在原图中的位置
    REAL oldimagey = (y / oldzoom);

    REAL newimagex = (x / m_zoom); //缩放后鼠标在原图中的位置
    REAL newimagey = (y / m_zoom);

    m_imgX = newimagex - oldimagex + m_imgX; //计算原图应该的偏移
    m_imgY = newimagey - oldimagey + m_imgY;

    Invalidate(); //绘图
    return CDialogEx::OnMouseWheel(nFlags, zDelta, pt);
}

void CTestPic2Dlg::OnLButtonDown(UINT nFlags, CPoint point)
{
    if(nFlags & MK_LBUTTON)
    {
        if(!m_mousepressed)
        {
            m_mousepressed = true;
            m_mouseDown.X = point.x;
            m_mouseDown.Y = point.y;
            m_PtStart.X = m_imgX;
            m_PtStart.Y = m_imgY;
        }
        
    }

    CDialogEx::OnLButtonDown(nFlags, point);
}

void CTestPic2Dlg::OnLButtonUp(UINT nFlags, CPoint point)
{
    m_mousepressed = false;
    CDialogEx::OnLButtonUp(nFlags, point);
}
 

这样就实现了以鼠标为中心缩放图片

这篇关于vc++ GDI+实现以鼠标为中心缩放图片(并且可以拖动)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1029232

相关文章

Redis实现分布式锁全过程

《Redis实现分布式锁全过程》文章介绍Redis实现分布式锁的方法,包括使用SETNX和EXPIRE命令确保互斥性与防死锁,Redisson客户端提供的便捷接口,以及Redlock算法通过多节点共识... 目录Redis实现分布式锁1. 分布式锁的基本原理2. 使用 Redis 实现分布式锁2.1 获取锁

Linux实现查看某一端口是否开放

《Linux实现查看某一端口是否开放》文章介绍了三种检查端口6379是否开放的方法:通过lsof查看进程占用,用netstat区分TCP/UDP监听状态,以及用telnet测试远程连接可达性... 目录1、使用lsof 命令来查看端口是否开放2、使用netstat 命令来查看端口是否开放3、使用telnet

使用SpringBoot+InfluxDB实现高效数据存储与查询

《使用SpringBoot+InfluxDB实现高效数据存储与查询》InfluxDB是一个开源的时间序列数据库,特别适合处理带有时间戳的监控数据、指标数据等,下面详细介绍如何在SpringBoot项目... 目录1、项目介绍2、 InfluxDB 介绍3、Spring Boot 配置 InfluxDB4、I

基于Java和FFmpeg实现视频压缩和剪辑功能

《基于Java和FFmpeg实现视频压缩和剪辑功能》在视频处理开发中,压缩和剪辑是常见的需求,本文将介绍如何使用Java结合FFmpeg实现视频压缩和剪辑功能,同时去除数据库操作,仅专注于视频处理,需... 目录引言1. 环境准备1.1 项目依赖1.2 安装 FFmpeg2. 视频压缩功能实现2.1 主要功

使用Python实现无损放大图片功能

《使用Python实现无损放大图片功能》本文介绍了如何使用Python的Pillow库进行无损图片放大,区分了JPEG和PNG格式在放大过程中的特点,并给出了示例代码,JPEG格式可能受压缩影响,需先... 目录一、什么是无损放大?二、实现方法步骤1:读取图片步骤2:无损放大图片步骤3:保存图片三、示php

使用Python实现一个简易计算器的新手指南

《使用Python实现一个简易计算器的新手指南》计算器是编程入门的经典项目,它涵盖了变量、输入输出、条件判断等核心编程概念,通过这个小项目,可以快速掌握Python的基础语法,并为后续更复杂的项目打下... 目录准备工作基础概念解析分步实现计算器第一步:获取用户输入第二步:实现基本运算第三步:显示计算结果进

Python多线程实现大文件快速下载的代码实现

《Python多线程实现大文件快速下载的代码实现》在互联网时代,文件下载是日常操作之一,尤其是大文件,然而,网络条件不稳定或带宽有限时,下载速度会变得很慢,本文将介绍如何使用Python实现多线程下载... 目录引言一、多线程下载原理二、python实现多线程下载代码说明:三、实战案例四、注意事项五、总结引

Python利用PySpark和Kafka实现流处理引擎构建指南

《Python利用PySpark和Kafka实现流处理引擎构建指南》本文将深入解剖基于Python的实时处理黄金组合:Kafka(分布式消息队列)与PySpark(分布式计算引擎)的化学反应,并构建一... 目录引言:数据洪流时代的生存法则第一章 Kafka:数据世界的中央神经系统消息引擎核心设计哲学高吞吐

C++ STL-string类底层实现过程

《C++STL-string类底层实现过程》本文实现了一个简易的string类,涵盖动态数组存储、深拷贝机制、迭代器支持、容量调整、字符串修改、运算符重载等功能,模拟标准string核心特性,重点强... 目录实现框架一、默认成员函数1.默认构造函数2.构造函数3.拷贝构造函数(重点)4.赋值运算符重载函数

Java调用Python脚本实现HelloWorld的示例详解

《Java调用Python脚本实现HelloWorld的示例详解》作为程序员,我们经常会遇到需要在Java项目中调用Python脚本的场景,下面我们来看看如何从基础到进阶,一步步实现Java与Pyth... 目录一、环境准备二、基础调用:使用 Runtime.exec()2.1 实现步骤2.2 代码解析三、