• VC学习笔记:简单绘图


    VC学习笔记:简单绘图

    SkySeraph Oct.29th 2009  HQU

    Email-zgzhaobo@gmail.com  QQ-452728574

    Latest Modified Date:Oct.31th 2010 HQU 重新整理

    //说明:学习《孙鑫视频》第四课 笔记  2009.10.29HQU

    绘线及相关

    建立单文档工程,为View类(不能是MainFrame)添加消息函数OnLButtonDown、OnLButtonUp

    ①先增加成员变量m_ptOrigin,CPoint型,用来保存坐标原点,在View构造函数里把其赋值为0,在OnLButtonDown里m_pOrigin=point

    CMyView::OnLButtonUp(UINT nFlags,CPoint point)

    //法一:利用SDK全局函数/API函数  在View类OnLButtonUp中

    HDC hdc;//获取设备描述表

    hdc=::GetDC(m_hWnd);

    //利用全局函数而不是CWnd成员函数;m_hWnd是view窗口句柄,在CWnd派生出来的类中,都有一个数据成员保存了窗口句柄,

    //CDC类也有同样的功能 m_hWnd是一个保护的变量,是用来构造m_hWnd对象的CWnd指针的HWND。

    MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,NULL);//移动线条起点

    LineTo(hdc,point.x,point.y);//画线

    ::ReleaseDC(m_hWnd,hdc);//配对使用;在WM_PAINT中不能用

     

    //法二:利用CDC类  此类提供了一个数据成员m_hDC用来保存于CDC类相关的句柄,类似于m_hWnd

    CDC *pDC=GetDC();//定义CDC类指针

    pDC->MoveTo(m_ptOrigin);

    pDC->LineTo(point);

    ReleaseDC(pDC);

     

    //法三:利用CClientDC  ,创建的是视图窗口的DC对象,作图只能在视图的客服区内作图

    CClientDC dc(GetParent());  //=CClientDC dc(this);    //结束时会自释放DC

    //CClientDC构造函数CClientDC( CWnd* pWnd );中得知需要一个指针

    //类CClientDC派生于CDC,在构造时调用了Windows函数GetDC,在析构时调用了ReleaseDC。这意味着和CClientDC对象相关的设备上下文是窗口的客户区。

    dc.MoveTo(m_ptOrigin);  //CClientDC类型的变量dc是一个对象,采用点操作符来调用该对象的函数

    dc.LineTo(point);

     

    //法四:利用CWindowDC   //通过选择窗口对象的指针,可以创建各种窗口的DC甚至是整个屏幕窗口的DC对象,作图也只能在窗口的客服区内作图

    CWindowDC dc(GetDesktopWindow());//整个屏幕

    //CWindowDC dc(GetParent());//=CWindowDC dc(this); //视图客户区内作图,结束时会自释放DC

    //CWindowDC类是从CDC继承的。它在构造的时候调用Windows函数GetWindowDC,在销毁的时候调用ReleaseDC。

    dc.MoveTo(m_ptOrigin);

    dc.LineTo(point);

     

    //绘制彩色线条    使用画笔 可以选择/改变颜色,粗细,宽度等属性

    CPen pen(PS_DOT,1,RGB(0,255,0));

    CClientDC dc(this);

    CPen *pOldPen=dc.SelectObject(&pen);

    dc.MoveTo(m_ptOrigin);

    dc.LineTo(point);

    dc.SelectObject(pOldPen);

     

    CView::OnLButtonUp(nFlags,point);

    }

     

    画刷

    法一 简单画刷

    CBrush brush(RGB(255,0,0));  

    CClientDC dc(this);

    dc.FillRect(CRect(m_ptOrigin,point),&brush);

    //注:此处只是用指定的画刷填充一块区域,因此并不需要把话刷选入设备描述表中。设备描述表中存在一个默认的白色的画刷

    法二bitmap填充/位图画刷

    CBrush brush(RGB(255,0,0));

    CBitmap bitmap;

    bitmap.LoadBitmap(IDB_BITMAP1);

    CBrush brush(&bitmap);

     

    法三:透明画刷

    CClientDC dc(this);

    CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH)); // CBrush::FromHandle是静态成员函数  

    //FromHandle给出一个Windows HBRUSH对象句柄时,返回一个指向CBrush对象的指针。即将画刷的句柄转换为对象的指针。

    CBrush *pOldBrush=dc.SelectObject(pBrush);

    dc.Rectangle(CRect(m_ptOrigin,point));

    dc.SelectObject(pOldBrush);

    静态成员 原理说明 实例

    • 例子1.0

    #include "iostream"

    class Point

    {

    public:

    void output() {}

    static void init() {}  //静态函数,不属于某个具体的对象,即在未产生Point任何对象时,这个类已经存在于程序的代码区

    }

     

    void main()

    {

    /*法一

    Point pt; //构造对象

    pt.init();

    pt.output();

    */

    //法二

    Point::init();/

    Point::output();//错误

    }

    说明:法一正确;法二执行错误,原因:

    //静态成员函数和静态成员变量属于类本身,在类加载的时候,即为它们分配了空间,故可以用类名::函数名或类名:变量名来访问;

    //而非静态成员函数和非静态成员属于对象的方法和数据,也就是应该先产生类的对象,然后通过类的对象去引用。

    • 修改1.1:

    class Point

    {

    public:

    void output() {}

    static void init() {x=0;y=0;}

    private:

    int x,y;

    }

    void main()

    { Point::init();//错误:在静态成员函数中不能调用非静态成员

     }

    说明:在静态成员函数中不能调用非静态成员(静态成员函数和静态成员变量);反之在非静态成员函数中可以调用静态成员,可以在修改void output(){ init(); };检验

    内存模型:无论采取什么样的操作,程序代码都是在内存中执行的,只有在内存中占有一席之地,我们才能访问它。

     

     

    • 修改1.2

    在int x,y;前加static,编译无错,链接时出错

    说明:对于静态成员变量,必须对其进行初始化,且必须在类外进行此操作

    加上:int Point::x=0;int Point::y=0;   OK!

    任意画线,画扇形

    ①先增加消息处理函数OnMouseMove。

    ②再设定一个bool型变量(当鼠标左键按下为true,弹起为false):在View构造函数里m_bDraw=0,在OnLButtonDown里m_bDraw=TRUE&在OnLButtonUp里m_bDraw=FALSE

    ③任意画连续的线

    CClientDC dc(this); if(m_bDraw==TRUE)

    {  dc.MoveTo(m_ptOrigin);  dc.LineTo(point);  m_ptOld=point; }

    ④增加颜色的连续的线

    CPen pen(PS_SOLID,1,RGB(255,0,0));

    CPen *pOldPen=dc.SelectObject(&pen);   {……}

    dc.SelectObject(pOldPen);

    ⑤画扇形

    先增加一个CPoint型成员变量m_ptOld,在左键按下的时候赋其值给m_ptOld

    …{dc.MoveTo(m_ptOrigin);

    dc.LineTo(m_ptOld);

    dc.MoveTo(m_ptOrigin);

    dc.LineTo(point);

    m_ptOld=point; }…

    ⑥带边线的扇形:只需要把第三句dc.MoveTo(m_ptOrigin);改为dc.MoveTo(m_ptOld);既可。

    ⑦设置绘图模式的函数:dc.SetROP2(R2_BLACK);

    补充 知识点

    1. CWnd类定义了一个HWND类型的成员变量m_hWnd用于保存当前窗口的句柄,且该句柄具有public类型访问权限。由继承性原理,CWnd子类都拥有这一成员变量。
    1. 在单文档中view挡在MainFrame的前面。此时如果编写针对MainFrame的mouseClick事件,将不会有反应。

    在框架类当中收不到鼠标左键点击的消息原因:View类始终是覆盖在Frame类中上的。也就是说,所有操作,包括鼠标移动,鼠标单击等都只能由视图类来完成。

     

    CDC、HDC、pDC区别

    ① CDC *pDC 和 HDC hdc有什么不同, 类似的有CWnd *pWnd和HWnd?

     pDC是类指针,HDC是windows句柄  

    通过pDC获得hdc:  HDC hdc=pDC->GetSafeHdc();

    通过hdc获得pDC:  CDC *pDC=new CDC;  pDC->Attach(hdc); 

    ②hDC和CDC有本质区别 

    HDC是WINDOWS的一种数据类型,是设备描述句柄。而CDC是MFC里的一个类,它封装了几乎所有的关于HDC的操作。

    也可以这样说,HDC定义的变量指向一块内存,这内存用来描述一个设备的相关的内容,所以也可以认为HDC定义的是一个指针;

    而CDC类定义一个对象,这个对象拥有HDC定义的一个设备描述表,同时也包含与HDC相关的操作的函数。这与HPEN和CPen,POINT与CPoint之间的差别是一样的。

    CDC是对hDC的相关操作进行封装,例如CDC的一个TextOut函数隐去其错误检测,完全可以简化到这样程度CDC:TextOut( int x, int y, const CString& str )

    {

        TextOut( m_hDC, x, y, (LPCTSTR)str, str.GetLength() );

    m_hDC就是CDC的成员变量HDC m_hDC;

    CDC有一个operator HDC() const { return m_hDC; }  

    你可以把它当成一个HDC使用

    ③ this是dc输出目标窗口的指针,通过它可以得到窗口句柄,对象带参构造这有什么奇怪的呢?       

        CPaintDC        无效区dc,相当于BeginPaint,    EndPaint  

        CClientDC       客户区dc,相当于GetDC,         ReleaseDC  

        CWindowDC       整窗口dc, 相当于GetWindowDC,   ReleaseDC  

        CDC             任何dc,   相当于CreateDC,      DeleteDC

    HDC就是最原始的 DC 句柄,很多API的第一个参数就是一个HDC类型,比如

    HDC hDC = ::GetDC( m_hWnd);

    ::MoveToEx( hDC, 0,0, NULL );   

    ::LineTo( hDC, 0, 100, );

    ::ReleaseDC( m_hWnd, hDC );

    在MFC中,为了将API封装成一个类来操作,因此多出来了一个CDC。所以在MFC中,都是

    CDC dc = GetDC();

    dc.MoveTo( 0,0 );

    dc.LineTo( 0,100 );

    this->ReleaseDC( &dc );

    但这样还不够,因为 CDC还要你自己去释放,所有MFC中又多出来一个CClientDC, 这样你就可以这样了:

    CClientDC dc(this);

    dc.MoveTo( 0,0 );

    dc.LineTo( 0,100 );

    CClientDC的析构函数自己会释放自己。

    DC不是什么对象,就是设备上下文的简称。与CClientDC一样,还有CWindowDC,CPaintDC,只是它们的绘制范围不一样。 

    但弄到底,都只是HDC的一些封装而已,你可以在CDC类中直接引用 m_hDC,这就是那个原始的HDC句柄了。

    Author:         SKySeraph

    Email/GTalk: zgzhaobo@gmail.com    QQ:452728574

    From:         http://www.cnblogs.com/skyseraph/

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,请尊重作者的劳动成果。

  • 相关阅读:
    语言基础
    进制转换
    ado属性扩展
    ado数据模型和数据访问类,泛型集合
    完整的修改和删除
    完整的删除
    修改
    类库
    接口
    抽象类
  • 原文地址:https://www.cnblogs.com/skyseraph/p/1865748.html
Copyright © 2020-2023  润新知