上一次我们实现了把我们要的图片添加到CTreeCtrl控件里去,并显示图片的缩略图,现在开始我们要讲比较重要的部分--绘图区。为了实现能编辑图片的功能,绘图区应该具有如下功能。

1.  添加删除图片。

2.  放大缩小绘图区。

3.  选中一张图片,移动一张图片。

4.  绘制图片

5.  给图片添加点击事件

为了更好的实现这些功能,我模仿了cocos2d的内存管理机制以及节点结构,写了一个静态库VALib,它使用GID+渲染图片,以及实现观察者模式来监听鼠标事件。源码可一从这里下载。当然,你也可以使用cocos2d 来实现绘图区的功能。这里我使用我自己写的VALib 库来实现。

下面开始上码。

首先我们需要先继承VALib库里的VASprite类,来写一个符合我们自己需求的Image类

.h文件

#pragma once
#pragma comment(lib, "../debug/valib.lib")
#include "valib.h"
#include "SelectHandler.h"
#include "RectPlacement.h"US_VA_NS
class VaImage :public VASprite , public SelectHandler ,public CRectPlacement::TRect
{
private:bool m_TouchFlag;bool m_selectFlag;VAPoint* m_lastPoing;void init();
public:VaImage(const char* m_name);~VaImage(void);/************************************************************************//* 使用一个图片创建一个VASprite/* fileName: 图片路径/************************************************************************/static VaImage* FromFile(const WCHAR* filename);bool intersectPoint(VAPoint* pt);/************************************************************************//* 重写registerTouchDispatcher函数,使图片吞并touch事件,图片下方的图片不响应touch事件                                                                     *//************************************************************************/virtual void registerTouchDispatcher();virtual bool vaTouchBegan(VATouch* m_pTouch, VAEvent* m_pEvent);virtual void vaTouchMoved(VATouch* m_pTouch, VAEvent* m_pEvent);virtual void vaTouchEnded(VATouch* m_pTouch, VAEvent* m_pEvent);virtual void vaTouchCancelled(VATouch* m_pTouch, VAEvent* m_pEvent);virtual bool select(CPoint* pt);virtual void unselect();virtual void draw();
};

.cpp文件

#include "StdAfx.h"
#include "VaImage.h"
#include <regex>US_VA_NSVaImage::VaImage(const char* m_name):VASprite(m_name)
, m_TouchFlag(false)
, m_selectFlag(false)
, m_lastPoing(NULL)
{init();
}VaImage::~VaImage(void)
{
}VaImage* VaImage::FromFile( const WCHAR* filename )
{Bitmap* bitmap = Bitmap::FromFile( filename );//截取文件名CString tempName = filename;int m_index = tempName.Find(L"\\");while ( m_index!=-1 ){tempName = tempName.Right(tempName.GetLength()-(m_index+1));m_index = tempName.Find(L"\\");}USES_CONVERSION;const char *name = W2A(tempName.GetBuffer(tempName.GetLength()));//LPSTR)(LPCTSTR)tempName;//新建VAImage并贴上图片VaImage* vaImage = new VaImage(name);vaImage->setBitmap(bitmap);return vaImage;
}void VaImage::init()
{registryDispatch();
}bool VaImage::intersectPoint( VAPoint* pt )
{VARect rect  = getRect();VAPoint m_pt = VAPoint(pt->x, pt->y);return rect.containsPoint(m_pt);
}void VaImage::registerTouchDispatcher()
{registerWithTouchDispatcher(NULL, true);
}bool VaImage::vaTouchBegan( VATouch* m_pTouch, VAEvent* m_pEvent )
{VAPoint* pt = new VAPoint(*(m_pTouch->getLocation()));if(intersectPoint(pt)){m_TouchFlag = true;if(m_lastPoing != NULL){//setPosition(new VAPoint( getPosition()->x + (pt->x - m_lastPoing->x), getPosition()->y + (pt->y - m_lastPoing->y) ));}m_lastPoing = pt;pt->release();return true;}pt->release();return false;
}void VaImage::vaTouchMoved( VATouch* m_pTouch, VAEvent* m_pEvent )
{if(m_TouchFlag){VAPoint* pt = new VAPoint(*(m_pTouch->getLocation()));VAPoint tempPT = VAPoint( getPosition().x + (pt->x - m_lastPoing->x), getPosition().y + (pt->y - m_lastPoing->y) );setPosition(tempPT);m_lastPoing = pt;tempPT.release();pt->release();}
}void VaImage::vaTouchEnded( VATouch* m_pTouch, VAEvent* m_pEvent )
{m_TouchFlag = false;
}void VaImage::vaTouchCancelled( VATouch* m_pTouch, VAEvent* m_pEvent )
{}bool VaImage::select( CPoint* pt )
{VAPoint m_pt = VAPoint(pt->x, pt->y);if(intersectPoint(&m_pt)){m_selectFlag = true;m_pt.release();return true;}m_pt.release();unselect();return false;
}void VaImage::unselect()
{m_selectFlag = false;
}void VaImage::draw()
{VASprite::draw();//绘制边框if(m_selectFlag){VADirector* director = VADirector::sharedDirector();vertex vertex = cloneVertex();int minX = min(min(min(vertex.leftTop.X, vertex.rightTop.X), vertex.rightBottom.X), vertex.leftBottmo.X);int minY = min(min(min(vertex.leftTop.Y, vertex.rightTop.Y), vertex.rightBottom.Y), vertex.leftBottmo.Y);int maxX = max(max(max(vertex.leftTop.X, vertex.rightTop.X), vertex.rightBottom.X), vertex.leftBottmo.X);int maxY = max(max(max(vertex.leftTop.Y, vertex.rightTop.Y), vertex.rightBottom.Y), vertex.leftBottmo.Y);VARect rect  = getRect();Gdiplus::Rect r(rect.getMinX(), rect.getMinY(), rect.getMaxX()-rect.getMinX(), rect.getMaxY()-rect.getMinY());director->DrawBorder(&r);}
}

完后我们需要继承CWnd来创建一个自定义组件ImageView

.h文件

#pragma once
#include "valib.h"
#pragma comment(lib, "../debug/valib.lib")
#include "stdafx.h"
#include "ImgsTool.h"
#include "VaImage.h"// ImageView
US_VA_NS//使用valib命名空间typedef std::vector<VaImage*> VaImageArray;
class ImageView : public CWnd
{DECLARE_DYNAMIC(ImageView)
private:VADirector* m_vaDirector;VATouchDispatcher* m_vaTouchDispatcher;SelectDispatcher* m_pSelectDispatcher;Bitmap* m_canva;Bitmap* m_bgImg;float m_scale;VaImageArray imgList;float m_tagArrange;bool m_drawTage;
public:VAScene* m_scene;ImageView();virtual ~ImageView();void saveImg(CString filePath, CString type, Bitmap* bitmap = NULL);void savePlis(CString filePath, CString ImageType);void addImage(const WCHAR* filename);void setAutoArrange(float isArrange);void autoArrange();
protected:DECLARE_MESSAGE_MAP()virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);void init();void drawBackground();void update();void draw(CDC* pDC);int GetEncoderClsid(const WCHAR* format, CLSID *pClsid);
};

.cpp 文件

// ImageView.cpp : implementation file
//
#include "stdafx.h"
#include "ImgsTool.h"
#include "ImageView.h"
#include <algorithm>
#include "PublishPlist.h"// ImageView
US_VA_NS//使用valib命名空间
IMPLEMENT_DYNAMIC(ImageView, CWnd)
enum{viewInterval,
};
ImageView::ImageView()
{}ImageView::~ImageView()
{
}BEGIN_MESSAGE_MAP(ImageView, CWnd)
END_MESSAGE_MAP()
// ImageView message handlersLRESULT ImageView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{// TODO: Add your specialized code here and/or call the base classVATouch* pTouch = new VATouch();CPoint pt = (CPoint)lParam;pTouch->setTouchInfo((float)pt.x, (float)pt.y);switch (message){case WM_CREATE:init();break;case WM_PAINT:if(m_drawTage){update();}break;case WM_TIMER:Invalidate(FALSE);break;case WM_LBUTTONDOWN:m_pSelectDispatcher->callAllHandler(&pt);m_vaTouchDispatcher->touchesBegan(pTouch, NULL);break;case WM_MOUSEMOVE:m_vaTouchDispatcher->touchesMoved(pTouch, NULL);break;case WM_LBUTTONUP:m_vaTouchDispatcher->touchesEnded(pTouch, NULL);break;
//  case WM_COMMAND://接收控件发送来的消息的
//      break;}return CWnd::WindowProc(message, wParam, lParam);
}void ImageView::init()
{m_tagArrange = true;CRect rect;this->GetClientRect(rect);m_bgImg = new Bitmap(rect.Width(), rect.Height());drawBackground();//绘制背景m_canva = new Bitmap(rect.Width(), rect. Height());//创建画布m_pSelectDispatcher = ToolsCenter::getInstance()->getSelectDispatcher();m_vaDirector = VADirector::sharedDirector();m_vaDirector->init(this->m_hWnd);m_vaTouchDispatcher = m_vaDirector->getTouchDispatcher();m_scene = new VAScene();SetTimer(viewInterval, 5, NULL);Invalidate(FALSE);
}void ImageView::drawBackground()
{CRect rect;this->GetClientRect(rect);int size = 20;Graphics* bgG = Graphics::FromImage(m_bgImg);Bitmap* m_bgtexture = new Bitmap(size,size);Graphics* txG = Graphics::FromImage(m_bgtexture);txG->FillRectangle(&SolidBrush(Color(255,255,255)), 0, 0, size, size);txG->FillRectangle(&SolidBrush(Color(192,192,192)), size/2, 0, size/2 , size/2);txG->FillRectangle(&SolidBrush(Color(192,192,192)), 0, size/2, size/2 , size/2);bgG->FillRectangle(&TextureBrush(m_bgtexture), rect.left, rect.top, rect.right, rect.bottom);//saveImg(m_bgImg);
}
//更新窗口
void ImageView::update()
{CDC* dc = this->GetDC();draw(dc);
}
//绘制窗口
void ImageView::draw(CDC* pDC)
{CDC MemDC;             //首先定义一个显示设备对象CBitmap MemBitmap;    //定义一个位图对象CRect rect;this->GetClientRect(rect);MemDC.CreateCompatibleDC(NULL);//随后建立与屏幕显示兼容的内存显示设备MemBitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height()); //建立一个与屏幕显示兼容的位图,至于位图的大小嘛,可以用窗口的大小//将位图选入到内存显示设备中//只有选入了位图的内存显示设备才有地方绘图,画到指定的位图上CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap);Graphics* memG = Graphics::FromHDC(MemDC);Rect destinationRect(0, 0, rect.Width(), rect.Height());memG->DrawImage(m_bgImg, destinationRect, 0, 0, rect.Width(), rect.Height(), Gdiplus::UnitPixel);m_canva = new Bitmap(rect.Width(), rect.Height());Graphics* canvaG = Graphics::FromImage(m_canva);//m_scene->update();VADirector::sharedDirector()->initDraw(memG);m_scene->draw();//绘制valib的场景里的各个图片memG->DrawImage(m_canva, destinationRect, 0, 0, rect.Width(), rect.Height(), Gdiplus::UnitPixel);delete canvaG;delete m_canva;//绘图后将内存中的图拷贝到屏幕上进行显示pDC->BitBlt(0,0, rect.Width(), rect.Height(), &MemDC,0, 0,SRCCOPY);//绘图完成后清理临时对象MemBitmap.DeleteObject();delete memG;MemDC.DeleteDC();ReleaseDC(pDC);
}void ImageView::saveImg(CString filePath, CString type,  Bitmap* bitmap /*= NULL*/)
{//m_drawTage = false;CRect rect;this->GetClientRect(rect);Gdiplus::Bitmap* _canva = new Bitmap(rect.Width(), rect.Height());Gdiplus::Graphics* canvaG = Gdiplus::Graphics::FromImage(_canva);Rect destinationRect(10, 0, rect.Width(), rect.Height());   VADirector::sharedDirector()->initDraw(canvaG);m_scene->draw();Bitmap* _bitmap;if(!bitmap)_bitmap = _canva;else_bitmap = bitmap;CLSID encoderClsid;this->GetParent();CString t = type.Right(type.GetLength()-1);if(t == "jpg") t = "jpeg";GetEncoderClsid(L"image/" + t, &encoderClsid);_bitmap->Save(filePath+type, &encoderClsid, NULL);
}void ImageView::addImage(const WCHAR* filename){VaImage* img = VaImage::FromFile(filename);m_scene->addChild(img);imgList.push_back(img);if(m_tagArrange){autoArrange();}
}void ImageView::savePlis( CString filePath, CString ImageType)
{filePath += ".plist";const wchar_t* ffd = filePath.GetBuffer(filePath.GetLength());USES_CONVERSION;const char* file = W2A(ffd);const char* _type = W2A(ImageType.GetBuffer(ImageType.GetLength()));PublishPlist* plist = new PublishPlist(file,_type, "100, 100");for(int i = 0; i< (int)imgList.size(); i++){VaImage* img = imgList.at(i);plist->addItem( img->getName(), int(img->getPosition().x), int(img->getPosition().y), int(img->getSize().width), int(img->getSize().height) );}plist->publish();
}void ImageView::setAutoArrange( float isArrange )
{m_tagArrange = isArrange;
}void ImageView::autoArrange(){//排序,由大小std::sort(imgList.begin(), imgList.end(), CRectPlacement::TRect::Greaters);CRectPlacement crp = CRectPlacement(imgList.front()->getSize().width, imgList.front()->getSize().height);for(int i = 0; i< (int)imgList.size(); i++){CRectPlacement::TRect r(0, 0, imgList.at(i)->getSize().width, imgList.at(i)->getSize().height);bool bPlaced = false;bPlaced = crp.AddAtEmptySpotAutoGrow(&r, 100000, 100000);imgList.at(i)->setPosition(VAPoint(r.x, r.y));}
}/*获取Image编码
* format: image/png, image/jpeg, image/gif
* pClsid: CLSID
*/
int ImageView::GetEncoderClsid( const WCHAR* format, CLSID *pClsid )
{UINT num = 0; //number of image encoder;UINT size = 0;   //size of the image encoder array in bytes;ImageCodecInfo *pImageCodecInfo = NULL;GetImageEncodersSize(&num, &size);if(size ==0)return -1;   //FailurepImageCodecInfo = (ImageCodecInfo *)(malloc(size));if(pImageCodecInfo==NULL)return -1;GetImageEncoders(num, size, pImageCodecInfo);for(UINT j=0; j< num; ++j){if(wcscmp(pImageCodecInfo[j].MimeType, format)==0){*pClsid = pImageCodecInfo[j].Clsid;free(pImageCodecInfo);return j;}}free(pImageCodecInfo);return -1;
}

这样我们就可以正常显示我们的图片了!

工具的完整代码可以从这里下载

转载于:https://www.cnblogs.com/dyllove98/p/3249251.html

游戏开发工具之纹理打包器-3.使用GDI+绘图相关推荐

  1. 纹理打包器 TexturePacker

    纹理打包器 TexturePacker 序 TexturePacker介绍 TexturePacker简单使用 准备工作 添加精灵和生成 纹理贴图集json 序 在前端调用图片时,可能会使用到雪碧图( ...

  2. Android 游戏开发工具大升级

    不同的硬件厂商为 Android 用户带来了不同尺寸和体验的设备,因此,我们也一直努力地帮助开发者们将游戏呈现到尽多的 Android 设备并使得开发过程更加高效轻松.本文将向您介绍众多新的 Andr ...

  3. 高端游戏开发工具:Unity Pro 2019 Mac版

    Unity Pro 2019 for Mac是专业的游戏开发工具,unity pro 2019 mac版具备最先进的游戏引擎之一,新版本提供了模块化组件系统.着色器可视化编程工具.可视乎开发环境.渲染 ...

  4. 【转】部分游戏开发工具

    2019独角兽企业重金招聘Python工程师标准>>> GPL许可证        GPL通用性公开许可证(General Public License,简称GPL).在字典中的含义 ...

  5. 部分游戏开发工具(转载)

      GPL许可证 GPL通用性公开许可证(General Public License,简称GPL).在字典中的含义是非洲大羚羊,我们可以常常看到非常个性化的羊头,想必很多人已经非常熟悉.象征 GNU ...

  6. Unity3D ——强大的跨平台3D游戏开发工具教程

    http://unity3d.9ria.com/?p=22 众所周知,Unity3D是一个能够实现轻松创作的多平台的游戏开发工具,是一个全面整合的专业游戏引擎.在现有的版本中,其强大的游戏制作功能已经 ...

  7. Action Game Maker 游戏开发工具介绍

    游戏开发者的论坛(66rpg):http://bbs.66rpg.com/forum-agm-1.html 在上面的论坛看一款游戏开发工具,使开发比较便利,主要能开发2d游戏(RPG,ARPG,RTG ...

  8. 2022 年顶级游戏开发工具

    2,000 亿美元. 这样一个可以追溯到 20 世纪 50 年代的产业现今产值已逾 2,000 亿美元,据估计,间接收入可达 1,000 亿美元.新冠疫情对于蓬勃发展中的游戏业确有益处,因为新老玩家都 ...

  9. Linux游戏开发工具收集

    转载自 xoxoxo 最终编辑 xyk34 FMOD FMOD 是一个非常容易使用的跨平台声音引擎,能够在 WINDOWS,WINDOWS CE,LINUX,MACINTOSH,GAMECUBE,PL ...

最新文章

  1. 强强联合!Papers with Code携手arXiv,上传论文、提交代码一步到位
  2. 《精通Unix下C语言与项目实践》读书笔记(16)
  3. 入门4:PHP 语法基础1
  4. 计算机网络第三章-数据链路层
  5. BZOJ 4734 UOJ #269 如何优雅地求和 (多项式)
  6. boost::iostreams::back_inserter用法的测试程序
  7. HDU - 4784 Dinner Coming Soon(bfs+动态规划+优先队列)
  8. 浏览器实验中的故障排除
  9. 为什么交叉熵(cross-entropy)可以用于计算代价?
  10. 已创建仓库后 github提交流程
  11. 一个可变布局列表,有9种布局item大小,每个item可拖拽切换位置
  12. 面向意图的SDN北向接口
  13. BatchPreparedStatementSetter,用法
  14. foremost 原理和使用
  15. 中国互联网络发展状况统计报告计算机,中国互联网络发展状况统计报告-计算机网络信息中心.DOC...
  16. mpa和pis_有关压力单位pis
  17. 云虚拟主机☀️利用FileZilla,使用FTP协议给阿里云虚拟主机上传、下载文件
  18. MDK 5.25 J-link V9 烧写程序失败
  19. 压缩pdf大小的方法?怎样压缩pdf大小?pdf文档怎么压缩?pdf文件太大怎么压缩?pdf文件太大怎么压缩成小内存?如何降低pdf文件大小?怎么把pdf文件压缩到指定大小?压缩pdf的简单方法
  20. 快手、抖音、微视类短视频SDK接入教程,7步就能搞定

热门文章

  1. 黄斑区隆起原因诊断过程+黄斑反复水肿问题
  2. 谷胱甘肽口服、舌下含服、NAC对照实验
  3. Make sure you've included captcha.urls as explained in the INSTALLATION
  4. 4.4 高斯消元法的矩阵表示
  5. Ubuntu使用技巧(二)
  6. springboot页面乱码问题
  7. Maven仓库搭建(二):GitHub、又拍云、七牛云存储
  8. GMQ集团推出全球创新型金融衍生品交易平台
  9. angular i18n 国际化 多语言
  10. Android知识点剖析系列:深入了解layout_weight属性