zoukankan      html  css  js  c++  java
  • 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/

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

  • 相关阅读:
    Effective Java 第三版——72. 赞成使用标准异常
    Effective Java 第三版——71. 避免不必要地使用检查异常
    Effective Java 第三版——70. 对可恢复条件使用检查异常,对编程错误使用运行时异常
    Effective Java 第三版——69. 仅在发生异常的条件下使用异常
    Effective Java 第三版——68. 遵守普遍接受的命名约定
    Effective Java 第三版——67. 明智谨慎地进行优化
    Effective Java 第三版——66. 明智谨慎地使用本地方法
    Effective Java 第三版——65. 接口优于反射
    Effective Java 第三版——64. 通过对象的接口引用对象
    Effective Java 第三版——63. 注意字符串连接的性能
  • 原文地址:https://www.cnblogs.com/skyseraph/p/1865748.html
Copyright © 2011-2022 走看看