之前接触过MFC,但是,那是很久之前的事了,起码有一年多,而且之前的也是非常皮毛的...
这次是狠下心来要好好学学MFC,因为以后要用到....
第一次实现的是一个MiniDraw小程序,实现画直线、椭圆、矩形、根据鼠标移动画线、多边形还有撤销上一操作
问题一:拖动画直线------绘图模式!
其实拖动画直线的原理在于,每次拖动都是画线两次,一次是使用和背景颜色一样的画笔画,即达到擦除的效果,另外一次则是画出当前鼠标停留处与起点之间的直线。我在里面使用的是R2_XORPEN这种模式,其实也可以用R2_NOT,但是在鼠标移动的时候,当图元相交时,会出现空白这种情况...因为是采用与背景颜色相反嘛...
这里碰到的问题是设置绘图模式。CDC::SetROP2 这个函数是用来设置绘图模式的,就是这个设置不同,所以会得出不懂得效果,这里记下各种模式:
绘图模式nDrawMode的取值
符号常量
|
作用
|
运算结果
|
R2_BLACK |
黑色
| pixel = black |
R2_WHITE |
白色
| pixel = white |
R2_NOP |
不变
| pixel = scCol |
R2_NOT |
反色
| pixel = ~scCol |
R2_COPYPEN |
覆盖
| pixel = pbCol |
R2_NOTCOPYPEN |
反色覆盖
| pixel = ~pbCol |
R2_MERGEPENNOT |
反色或
| pixel = ~scCol | pbCol |
R2_MERGENOTPEN |
或反色
| pixel = scCol | ~pbCol |
R2_MASKNOTPEN |
与反色
| pixel = scCol & ~pbCol |
R2_MERGEPEN |
或
| pixel = scCol | pbCol |
R2_NOTMERGEPEN |
或非
| pixel = ~(scCol | pbCol) |
R2_MASKPEN |
与
| pixel = scCol & pbCol |
R2_NOTMASKPEN |
与非
| pixel = ~(scCol & pbCol) |
R2_XORPEN |
异或
| pixel = scCol ^ pbCol |
R2_NOTXORPEN |
异或非
| pixel = ~(scCol ^ pbCol) |
其中,R2_COPYPEN(覆盖)为缺省绘图模式,R2_XORPEN(异或)较常用。
问题二:实现画出鼠标移动路径(即自由画线)-----封装!
一开始,对于这个,我想到的是使用vector来存储鼠标的点,然后,如果有多条线的话,那么就设置一个标志点分开比如(-1,-1)这种坐标点。这种想法我实现了,但是,别人给的建议是把这个也封装,这样子才和OOD的思想吻合。最后,我也把这种图元封装。其实,从空间上来说,两者开销差不多,可以说是相等,因为前者使用特殊坐标存储结束标志,后者使用了指针指向这个对象。但是,确实是后者简便一些,因为这样可以使得所有的图元都是继承于一个基类,然后使用这个基类指针指向各个图元对象,从而调用画图命令。后者更有条理
(当然,这是相对于编程语言来说的),而且,后者的代码量要少一些,可读性也强一些
问题三:内存泄漏----虚析构函数!
使用基类指针指向派生类时,delete的时候小心内存泄漏。基类的析构函数最好是设成虚析构函数。这里涉及到两个概念:
动态绑定:动态绑定是指在执行期间(非编译期)判断所引用对象的实际类型,根据其实际的类型调用其相应的方法
静态绑定:所谓静态绑定是指在程序编译过程中,把函数(方法或者过程)调用与响应调用所需的代码结合的过程称之为静态绑定。
这是摘自百科的定义,其实,针对我自己的程序,说得白话一点就是:
不用虚,则静态绑定,根据指针类型决定调用函数
用虚,则动态绑定,根据指向的类型调用函数
一下面用一个别人的例子说明:
#include <iostream>
using namespace std;
class Base
{
public:
Base( void )
{
cout << "Base::Base( )" << endl;
}
virtual ~Base( void ) //基类有虚析构函数时
{
cout << "Base::~Base( )" << endl;
}
};
class Derived : public Base
{
public:
Derived( void )
{
m_pData = new int;
cout << "Derived::Derived( )" << endl;
}
~Derived( void )
{
delete m_pData;
m_pData = NULL;
cout << "Derived::~Derived( )" << endl;
}
private:
int* m_pData;
};
int main( void )
{
Derived* pD = new Derived;
Base* pB = pD;
//通过基类的指针去删除派生类的对象,而基类有虚析构函数时
delete pB;
pB = NULL;
system( "PAUSE" );
return EXIT_SUCCESS;
}
/*-------派生类的析构函数被调用,派生类的对象被回收
Base::Base( )
Derived::Derived( )
Derived::~Derived( )
Base::~Base( )
请按任意键继续. . .
---------------------------------*/
所以,基类一定要注意使用虚析构函数!!!
问题四:结束的标志---画多边形
做之前,运行过两个别人的demo,我发现,存在的问题都是,画多边形的时候,停不下来,只是多个点的一直在连线,第一个只能选取画其他图元的时候能结束画一个多边形,而第二个也是这样能退出,但是,如果点击撤销,就会崩掉....
所以,算是前车之鉴,我设置了鼠标右键作为一个多边形结束的标志
问题五:自身的一些问题!
对于写代码的效率,我还需要提高啊....以前就是一直存在这个问题,今后要改一改,就像赖床和一觉睡到大中午的坏习惯一样,必须改!再者,我需要看一些C++的书,毕竟很久没有写C++了,所以需要一点点捡回来...写博客也是为了做一个记录