画板的实现非常有趣,首先要新建一张HBITMAP来保存原来的绘制内容,然后需要创建一个可拉伸的输入框,供用户输入文字。必要时还得提供UnDo功能,供用户取消上一次绘制的功能。
利用业余时间,我制作了一个画板程序,包含了以下几个功能:
1. 可动态拉伸及移动位置的编辑框,供用户输入文字。
2. 可画直线,圆圈,箭头,线段及线条。
3. 可使用CTRL+Z组合键,撤销上一次的绘制。
此画板还有些地方需要进行完善,它们是:
1. 绘制时是刷新全部绘制区域,最好是刷新当前绘制区域。
2. 输入的文字,没有实现动态绘制到画板的功能,留给读者自己去实现。
3. 创建的绘制区域,是直接在主窗口上进行绘制的,理想的情况应该是新建一个子窗口,进行绘制。因为主窗口的边框的长和宽,影响到了输入框位置的计算。
以下是一些实现的技术细节:
1. 类CCanvas将每一次的绘制内容,都保存到了一个CBitmap中,方便下一次的绘制。GDI绘制的圆圈和线条有锯齿,不好看。所以先我用GDI+进行了绘制,绘制完成后才将GDI+的Bitmap转换为GDI的CBitmap。当然,也是为了加快窗口的绘制速度。
// Turn GDI+ bitmap to GDI bitmap to let draw old faster. m_bmpOld.get()->GetHBITMAP((ARGB)Color::Transparent, &m_bmpCache.m_hBitmap);
2. 模板CCanvasWndImpl,负责在主窗口上面,创建一个CCanvas绘制对象,并截获主窗口的鼠标消息,进行绘制。这里我也许应该创建一个子窗口,因为主窗口是有边框的,动态计算画布的位置时,需要将边框的长和宽考虑在内。
3. 模板CResizeCtrlImpl,负责拦截CEdit控件的鼠标消息,然后在CEdit周围画虚线及拉伸点。供用户进行拉伸及移动操作。
CEdit首先继承CResizeCtrlImpl:
class CBitmapEdit : public CWindowImpl<CBitmapEdit>, public CResizeCtrlImpl<CBitmapEdit>, public CDoubleBufferImpl<CBitmapEdit>
然后在DoPait方法中调用CResizeCtrlImpl类中的DrawResizeControl(Graphics& g)方法,即可画出虚线边框及拉伸点。
// Draw resize control. void DrawResizeControl(Graphics& g) { if (!m_bEnable) { return; } T* pT = static_cast<T*>(this); pT->GetClientRect(&m_rcClient); m_rcClient.DeflateRect(m_nBorder, m_nBorder, m_nBorder, m_nBorder); // Draw border with dash style. Pen pen(m_clrBorder, (REAL)m_nBorder); pen.SetDashStyle(DashStyleDash); pen.SetAlignment(PenAlignmentInset); g.DrawRectangle(&pen, m_rcClient); // Draw dragging rectangle. SolidBrush br(Color::AliceBlue); for (UINT nIndex = 0; nIndex < m_szBlocks.size(); ++nIndex) { g.FillRectangle(&br, m_szBlocks[nIndex]); } }
最后,就如文章开头所说,该程序还有一些没有实现的地方和缺陷。希望朋友们不要介意。
编译该程序前,您需要安装WTL9.0开发包。下载地址:http://download.csdn.net/detail/renstarone/6958327
源代码下载地址:http://download.csdn.net/detail/renstarone/6958583