xref: /MusicPlayer2/MusicPlayer2/DrawCommon.h (revision bdab36f8b39bc8fbd10db7970e6ea1bfffbbdfed)
1 //这个类用于定义用于绘图的函数
2 #pragma once
3 
4 enum class Alignment    //对齐方式
5 {
6     LEFT,
7     RIGHT,
8     AUTO,   // 用于歌词对齐选项,原来的居中,支持卡拉OK显示
9     CENTER
10 };
11 
12 enum ImageType
13 {
14     IT_JPG,
15     IT_PNG,
16     IT_GIF,
17     IT_BMP
18 };
19 
20 class DrawAreaGuard;
21 
22 class CDrawCommon
23 {
24 public:
25 
26     //拉伸模式
27     enum class StretchMode
28     {
29         STRETCH,		//拉伸,会改变比例
30         FILL,			//填充,不改变比例,会裁剪长边
31         FIT			//适应,不会改变比例,不裁剪
32     };
33 
34     //用于在DrawScrollText函数调用时使用的一些需要在函数调用完毕后继续存在的变量
35     struct ScrollInfo
36     {
37         int shift_cnt{};		//移动的次数
38         bool shift_dir{};		//移动的方向,右移为false,左移为true
39         int freez{};			//当该变量大于0时,文本不滚动,直到小于等于0为止
40         bool dir_changed{ false };	//如果方向发生了变化,则为true
41         CString last_string;        //上一次绘制的文本
42 
43         void Reset();
44     };
45 
46     friend class DrawAreaGuard;
47 
48     CDrawCommon();
49     virtual ~CDrawCommon(); // 基类析构方法需要是虚方法
50 
51     virtual void Create(CDC* pDC, CFont* pFont = nullptr);
52     void Create(CDC* pDC, Gdiplus::Graphics* pGraphics, CFont* pFont = nullptr);
53     CFont* SetFont(CFont* pFont);       // 设置绘制文本的字体(返回原来的字体)
GetFont()54     CFont* GetFont() { return m_pfont; }
55     void SetDC(CDC* pDC);		//设置绘图的DC
GetDC()56     CDC* GetDC()
57     {
58         return m_pDC;
59     }
60 
GetGraphics()61     Gdiplus::Graphics* GetGraphics()
62     {
63         return m_pGraphics;
64     }
65 
66     //在指定的矩形区域内绘制有颜色的文本
67     //rect: 文本的矩形区域
68     //lpszString: 要绘制的文本
69     //color: 文本的颜色
70     //align: 文本的对齐方式(默认值:左对齐)
71     //no_clip_area: 如果为true,则不在输出文字时限制绘图区域
72     //multi_line: 是否多行显示
73     //default_right_align: 如果文本的宽度大于矩形区域,是否右对齐
74     void DrawWindowText(CRect rect, LPCTSTR lpszString, COLORREF color, Alignment align = Alignment::LEFT, bool no_clip_area = false, bool multi_line = false, bool default_right_align = false);
75 
76     //在指定的矩形区域内绘制分割颜色的文本
77     //rect: 文本的矩形区域
78     //lpszString: 要绘制的文本
79     //color1: 分割位置左边的文本颜色
80     //color2: 分割位置右边的文本颜色
81     //split: 颜色分割位置,取值为0~1000(用于歌词动态显示)
82     //align: 文本对齐方式
83     //no_clip_area: 如果为true,则不在输出文字时限制绘图区域
84     void DrawWindowText(CRect rect, LPCTSTR lpszString, COLORREF color1, COLORREF color2, int split, Alignment align = Alignment::LEFT, bool no_clip_area = false);
85 
86     //在控件上绘制滚动的文本(当长度不够时),pixel指定此函数调用一次移动的像素值,如果reset为true,则滚动到初始位置
87     //rect: 文本的矩形区域
88     //lpszString: 要绘制的文本
89     //color: 文本的颜色
90     //pixel: 此函数调用一次滚动的像素值,值越小滚动越慢
91     //center: true时文本居中,false时左对齐
92     //scroll_info: 用来保存一些当前文本滚动的状态信息
93     //reset: 如果reset为true,则重置scroll_info,并滚动到初始位置
94     void DrawScrollText(CRect rect, LPCTSTR lpszString, COLORREF color, double pixel, bool center, ScrollInfo& scroll_info, bool reset = false, bool no_clip_area = false);
95 
96     //函数功能和DrawScrollText一样,只是这个函数只会从左到右滚动,不会更换方向
97     void DrawScrollText2(CRect rect, LPCTSTR lpszString, COLORREF color, double pixel, bool center, ScrollInfo& scroll_info, bool reset = false);
98 
99 public:
100     //绘制一个位图(使用GDI)
101     void DrawBitmap(CBitmap& bitmap, CPoint start_point, CSize size, StretchMode stretch_mode, bool no_clip_area = false);
102     void DrawBitmap(UINT bitmap_id, CPoint start_point, CSize size, StretchMode stretch_mode, bool no_clip_area = false);
103     void DrawBitmap(HBITMAP hbitmap, CPoint start_point, CSize size, StretchMode stretch_mode, bool no_clip_area = false);
104 
105     //绘制一个图像(使用GDI+)
106     void DrawImage(const CImage& image, CPoint start_point, CSize size, StretchMode stretch_mode, bool no_clip_area = false);
107     void DrawImage(Gdiplus::Image* pImage, CPoint start_point, CSize size, StretchMode stretch_mode, bool no_clip_area = false);
108 
109     void DrawIcon(HICON hIcon, CPoint start_point, CSize size);
110     void DrawIcon(HICON hIcon, CRect rect);
111     void DrawIcon(HICON hIcon, CRect rect, int icon_size);
112 
113     void FillRect(CRect rect, COLORREF color, bool no_clip_area = false);
114     void FillAlphaRect(CRect rect, COLORREF color, BYTE alpha, bool no_clip_area = false);		//填充一个半透明的矩形(参照http://blog.csdn.net/lee353086/article/details/38311421
115 
116     void DrawRectTopFrame(CRect rect, COLORREF color, int pilex = 1);
117     void DrawRectOutLine(CRect rect, COLORREF color, int width, bool dot_line);
118     void DrawRectFrame(CRect rect, COLORREF color, int width, BYTE alpha = 255);        //绘制一个矩形边框
119 	void DrawLine(CPoint point1, CPoint point2, COLORREF color, int width, bool dot_line);
120 
121     void DrawRoundRect(CRect rect, COLORREF color, int radius, BYTE alpha = 255);       //绘制圆角矩形(使用GDI+)
122     void DrawRoundRect(Gdiplus::Rect rect, Gdiplus::Color color, int radius);       //绘制圆角矩形(使用GDI+)
123 
124     void DrawEllipse(CRect rect, COLORREF color, BYTE alpha = 255);     //绘制椭圆(使用GDI+)
125     void DrawEllipse(Gdiplus::Rect rect, Gdiplus::Color color);         //绘制椭圆(使用GDI+)
126 
127     CSize GetTextExtent(LPCTSTR str);
128 
129     ////将图片拉伸到指定尺寸(https://blog.csdn.net/sichuanpb/article/details/22986877)
130     //static bool BitmapStretch(CImage *pImage, CImage *ResultImage, CSize size);
131 
132     //将图片拉伸到指定尺寸
133     static void ImageResize(const CImage& img_src, CImage& img_dest, CSize size);
134 
135     //重设图片的大小,不改变图片比例,size为更改后图片长边的大小,单位为像素。type指定输出的文件格式
136     static void ImageResize(const CImage& img_src, const wstring& path_dest, int size, ImageType type);
137     static void ImageResize(const wstring& path_src, const wstring& path_dest, int size, ImageType type);
138 
139     //复制一个bitmap (http://wupei.j2megame.org/archives/86)
140     //(这两个函数未测试成功,复制的图片为全黑色,原因暂时未知,后面再调查)
141     static HBITMAP CopyBitmap(HBITMAP hSourceHbitmap);
142     static void CopyBitmap(CBitmap& dest, CBitmap& src);
143 
144     //将一个Bitmap保存到文件
145     static void SaveBitmap(HBITMAP bitmap, LPCTSTR path);
146 
147     void ImageDrawAreaConvert(CSize image_size, CPoint& start_point, CSize& size, StretchMode stretch_mode);
148 
149     //计算一个矩形中正方形图标的矩形区域
150     static CRect CalculateCenterIconRect(CRect rect, int icon_size);
151 
152 protected:
153     CDC* m_pDC{};		//用于绘图的CDC类的指针
154     CFont* m_pfont{};
155     Gdiplus::Graphics* m_pGraphics{};
156     bool m_auto_destory_graphics{};     //是否自动析构Graphics对象,如果Graphics对象是内部创建的,则为true,如果是从外面传过来的,则为false
157 };
158 
159 
160 //用于双缓冲绘图的类
161 class CDrawDoubleBuffer
162 {
163 public:
CDrawDoubleBuffer(CDC * pDC,CRect rect)164     CDrawDoubleBuffer(CDC* pDC, CRect rect)
165         : m_pDC(pDC), m_rect(rect)
166     {
167         m_memDC.CreateCompatibleDC(NULL);
168         m_memBitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
169         m_pOldBit = m_memDC.SelectObject(&m_memBitmap);
170     }
171 
~CDrawDoubleBuffer()172     ~CDrawDoubleBuffer()
173     {
174         m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(), &m_memDC, 0, 0, SRCCOPY);
175         m_memDC.SelectObject(m_pOldBit);
176         m_memBitmap.DeleteObject();
177         m_memDC.DeleteDC();
178     }
179 
GetMemDC()180     CDC* GetMemDC()
181     {
182         return &m_memDC;
183     }
184 
185 private:
186     CDC* m_pDC;
187     CDC m_memDC;
188     CBitmap m_memBitmap;
189     CBitmap* m_pOldBit;
190     CRect m_rect;
191 };
192 
193 
194 //用于在UI中设置绘图区域。
195 //在需要设置绘图区域时,创建此类的一个局部对象,它会在构造时设置绘图区域,并在析构时恢复上次绘图区域
196 class DrawAreaGuard
197 {
198 public:
199     DrawAreaGuard(const DrawAreaGuard&) = delete;
200     DrawAreaGuard(CDrawCommon* drawer, CRect rect, bool gdi_only = false, bool enable = true)
m_drawer(drawer)201         : m_drawer(drawer), m_gdi_only(gdi_only), m_enable(enable)
202     {
203         if (m_drawer != nullptr && m_enable)
204             old_rect = SetDrawArea(rect, gdi_only);
205     }
206 
~DrawAreaGuard()207     ~DrawAreaGuard()
208     {
209         if (m_drawer != nullptr && m_enable)
210             SetDrawArea(old_rect, m_gdi_only);
211     }
212 
213 private:
214     //设置绘图区域,并返回上次的绘图区域
215     CRect SetDrawArea(CRect rect, bool gdi_only);
216 
217     //恢复绘图区域
218     void ResetDrawArea(bool gdi_only);
219 
220 private:
221     CDrawCommon* m_drawer{};
222     bool m_enable{ true };
223     bool m_gdi_only{};
224     CRect old_rect;
225 };
226 
227