实例详解:MFC坐标轴实现

需求:MFC坐标轴实现-----最好有步骤啊,刚刚才接触C++和MFC啊。MFC怎样在特定区域建立坐标轴,x轴自适应,y轴有固定范围,最好有网格。

解决思路:VC 内存绘图,不闪屏,具体代码如下:

// 先上传代码,在.h 文件中:

#pragma once  
  
#include <afxtempl.h>  
  
#define TEXT_AREA_WIDTH     (60)            ///< 文字区宽度,单位 像素  
#define X_AXIS_GRAD         (600)           ///< X 轴刻度值  
#define Y_AXIS_GRAD         (50)            ///< X 轴刻度值  
  
  
class My_Draw  : public CStatic  
{  
    // 构造/析构 函数  
public:  
        My_Draw();  
        virtual ~My_Draw();  
public:  
    struct  
    {  
        unsigned char Show_Max_Grid                 :1;         // 是否显示大网格  
        unsigned char Show_Min_Grid                 :1;         // 是否显示小网格  
        unsigned char Draw_Enable                   :1;         // 放大/缩小使能位  
        unsigned char Draw_Line_Choice              :1;         // 线被选择  
        unsigned char LButton_Down_Flag             :1;         // 鼠标左键按下标志  
        unsigned char LButton_Up_Flag               :1;         // 鼠标左键弹起标志  
        unsigned char LButton_Double_Down_Flag      :1;         // 鼠标左键双击按下标志  
    }Bool_Flag;  
  
    unsigned int TextAreaWidth;  
    int xAxisGrad,yAxisGrad;  
    unsigned short xMaxGrad,xMinGrad;  
    unsigned short yMaxGrad,yMinGrad;  
  
    int Limit_Min,Limit_Max;  
  
    POINT Mouse_Current_Point;                      // 鼠标当前坐标  
    POINT Button_Down_Point;                        // 记录鼠标左键按下时的坐标  
    POINT LButton_Double_Down_Point;                // 记录鼠标左键双击按下的坐标  
    POINT Old_LButton_Double_Down_Point;  
  
    // 画笔列表  
    CPen* pBrack;       // 黑色画笔  
    CPen* pBlue;        // 蓝色画笔  
    CPen* pYellow;      // 黄色画笔  
    CPen* pGren;        // 绿色画笔  
    CPen* pPink;        // 紫色画笔  
    CPen* pRed;         // 红色画笔  
    CPen* pGray;        // 灰色画笔  
  
    CRect Draw_Size;  
    CDC memDC;  
    CBitmap memBitmap;        
    CBitmap* pOldBmp;  
  
    unsigned short SheetMaxH;  
  
    CWnd *pWnd;  
  
    void Draw();  
    void Drawing(CDC *pDC);       // 绘制图表  
    void Draw_xAxis(CDC *pDC);  
    void Draw_yAxis(CDC *pDC);  
    void Draw_Cross_Cursor(CDC *pDC);  
  
    void My_Draw::SaveBmpToFile();  
protected:  
      
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);  
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);  
    afx_msg void OnLButtonUp(UINT nFlags, CPoint point);  
    afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);  
    DECLARE_MESSAGE_MAP()  
}; 

// .CPP 文件中:

#include "stdafx.h"  
#include "Draw_Static_Text.h"  
#include "conio.h"  
#include "direct.h"  
  
#ifdef _DEBUG  
#define new DEBUG_NEW  
#endif  
  
// 构造函数  
My_Draw::My_Draw()  
{  
    Bool_Flag.Show_Max_Grid = false;  
    Bool_Flag.Show_Min_Grid = false;  
    Bool_Flag.Draw_Enable = false;  
    Bool_Flag.Draw_Line_Choice = false;  
    Bool_Flag.LButton_Down_Flag = false;  
    Bool_Flag.LButton_Up_Flag = false;  
    Bool_Flag.LButton_Double_Down_Flag = false;  
  
    TextAreaWidth = TEXT_AREA_WIDTH;  
    xAxisGrad = X_AXIS_GRAD;  
    yAxisGrad = Y_AXIS_GRAD;  
  
    pBrack = new CPen();        // 黑色画笔  
    pBlue = new CPen();         // 蓝色画笔  
    pYellow = new CPen();       // 黄色画笔  
    pGren = new CPen();         // 绿色画笔  
    pRed = new CPen();          // 红色画笔  
    pPink = new CPen();         // 紫色画笔  
    pGray = new CPen();         // 灰色画笔  
  
    pBrack->CreatePen(PS_SOLID,1,RGB(0,0,0));  
    pBlue->CreatePen(PS_SOLID,1,RGB(0,0,255));  
    pYellow->CreatePen(PS_SOLID,1,RGB(155,125,0));  
    pGren->CreatePen(PS_SOLID,1,RGB(0,255,0));  
    pRed->CreatePen(PS_SOLID,1,RGB(255,0,0));  
    pPink->CreatePen(PS_SOLID,1,RGB(255,0,255));  
    pGray->CreatePen(PS_DOT,1,RGB(145,105,105));  
  
  
#ifdef _DEBUG  
    AllocConsole();  
    _cprintf("Debuging....\r\n");  
#endif  
}  
  
  
// 析构函数  
My_Draw::~My_Draw()  
{  
    delete pBrack;        // 黑色画笔  
    delete pBlue;         // 蓝色画笔  
    delete pYellow;       // 黄色画笔  
    delete pGren;         // 绿色画笔  
    delete pRed;          // 红色画笔  
    delete pPink;         // 紫色画笔  
    delete pGray;         // 灰色画笔  
}  
  
BEGIN_MESSAGE_MAP(My_Draw, CStatic)  
    ON_WM_LBUTTONDOWN()  
    ON_WM_MOUSEMOVE()  
    ON_WM_LBUTTONUP()  
    ON_WM_LBUTTONDBLCLK()  
END_MESSAGE_MAP()  
  
  
void My_Draw::SaveBmpToFile()       // 保存图表为 Bmp 图片  
{  
    CFileDialog dlg(false,NULL,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,  
        "位图文件(*.bmp)|*.bmp|",NULL);  
  
    if (dlg.DoModal()!= IDOK) return;  
    CString filename = dlg.GetFileName() + ".bmp";  
  
    // 获取绘制坐标的文本框  
    this->GetClientRect(&Draw_Size);    // 获取窗口大小  
    CDC *pDC = this->GetDC();     // 获取 dc  
    this->Invalidate();  
 this->UpdateWindow();  
  
    //内存绘图  
    memDC.CreateCompatibleDC(pDC);  
    memBitmap.CreateCompatibleBitmap(pDC,Draw_Size.right,Draw_Size.bottom);  
    pOldBmp = memDC.SelectObject(&memBitmap);  
    memDC.BitBlt(Draw_Size.left,Draw_Size.top,Draw_Size.right,Draw_Size.bottom,pDC,0,0,SRCCOPY);  
    Drawing(&memDC);       // 绘制坐标  
  
    BITMAP bmp;  
    memBitmap.GetBitmap(&bmp);                                               // 获得位图信息  
    FILE *fp;  
    fopen_s(&fp,filename, "w+b");  
    BITMAPINFOHEADER bih = {0};                                              // 位图信息头  
    bih.biBitCount = bmp.bmBitsPixel;                                        // 每个像素字节大小  
    bih.biCompression = BI_RGB;  
    bih.biHeight = bmp.bmHeight;                                             // 高度  
    bih.biPlanes = 1;  
    bih.biSize = sizeof(BITMAPINFOHEADER);  
    bih.biSizeImage = bmp.bmWidthBytes * bmp.bmHeight;                       // 图像数据大小  
    bih.biWidth = bmp.bmWidth;                                               // 宽度  
    BITMAPFILEHEADER bfh = {0};                                              // 位图文件头  
    bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);     // 到位图数据的偏移量  
    bfh.bfSize = bfh.bfOffBits + bmp.bmWidthBytes * bmp.bmHeight;            // 文件总的大小  
    bfh.bfType = (WORD)0x4d42;  
    fwrite(&bfh, 1, sizeof(BITMAPFILEHEADER), fp);                           // 写入位图文件头  
    fwrite(&bih, 1, sizeof(BITMAPINFOHEADER), fp);                           // 写入位图信息头  
    byte * p = new byte[bmp.bmWidthBytes * bmp.bmHeight];                    // 申请内存保存位图数据  
    GetDIBits(memDC.m_hDC, (HBITMAP) memBitmap.m_hObject, 0, Draw_Size.Height(), p,  (LPBITMAPINFO) &bih, DIB_RGB_COLORS);                                    //获取位图数据  
    fwrite(p, 1, bmp.bmWidthBytes * bmp.bmHeight, fp);                       // 写入位图数据  
    delete [] p;  
    fclose(fp);  
  
    memDC.SelectObject(pOldBmp);  
    memDC.DeleteDC();                                                       // 释放 Dc  
    memBitmap.DeleteObject();  
}  
  
  
void My_Draw::Draw()  
{  
    this->Invalidate();  
 this->UpdateWindow();  
    this->GetClientRect(&Draw_Size);    // 获取窗口大小  
    CDC *pDC = this->GetDC();     // 获取 dc  
    //内存绘图  
    memDC.CreateCompatibleDC(pDC);  
    memBitmap.CreateCompatibleBitmap(pDC,Draw_Size.right,Draw_Size.bottom);  
    pOldBmp = memDC.SelectObject(&memBitmap);  
    memDC.BitBlt(Draw_Size.left,Draw_Size.top,Draw_Size.right,Draw_Size.bottom,pDC,0,0,SRCCOPY);  
    Drawing(&memDC);       // 绘制坐标  
    pDC->BitBlt(Draw_Size.left,Draw_Size.top,Draw_Size.right,Draw_Size.bottom,&memDC,0,0,SRCCOPY);  
  
    memDC.SelectObject(pOldBmp);  
    memDC.DeleteDC();  
    memBitmap.DeleteObject();  
  
    ReleaseDC(pDC);  
}  
  
  
void My_Draw::Drawing(CDC *pDC)  
{  
    pDC->SelectObject(pBrack);                         // 选择当前画笔颜色  
    pDC->Rectangle(0,0,Draw_Size.Width(),Draw_Size.Height());       // 设定绘制范围  
  
    //绘出文字  
      
 pDC->SetTextColor(RGB(0,25,255));  
 pDC->SetBkMode(TRANSPARENT);  
 pDC->TextOutA(5,180,"");  
 pDC->TextOutA(5,200,"");  
 pDC->TextOutA(5,220,"");  
 pDC->TextOutA(5,240,"");  
 pDC->TextOutA(11,260,"|");  
 pDC->TextOutA(5,280,"");  
 pDC->TextOutA(5,300,"");  
 pDC->TextOutA(3,320,"(V)");  
      
 pDC->TextOutA(Draw_Size.Width()/2-40,Draw_Size.Height()-20,"行    程--单位 (%)");  
  
    SheetMaxH = Draw_Size.Height()-TextAreaWidth;  
  
    Draw_xAxis(pDC);  
    Draw_yAxis(pDC);  
    Draw_Cross_Cursor(pDC);  
  
    ReleaseDC(pDC);  
}  
  
  
void My_Draw::Draw_xAxis(CDC *pDC)  
{  
    CString StrScale;           // 转换刻度字符串存放点  
    unsigned short drawCount;   // 画王格计数  
    unsigned short temp;  
    unsigned int girdSize;  
      
    //绘制x轴坐标  
 pDC->MoveTo(TextAreaWidth,SheetMaxH);  
 pDC->LineTo(Draw_Size.Width(),SheetMaxH);  
 //绘制箭头  
 pDC->LineTo(Draw_Size.Width()-10,SheetMaxH-5);  
 pDC->MoveTo(Draw_Size.Width(),SheetMaxH);  
 pDC->LineTo(Draw_Size.Width()-10,SheetMaxH+5);  
  
    //绘制x轴刻度  
 drawCount = 0;  
 if(xAxisGrad > Draw_Size.Width())  
 {  
  xAxisGrad/=10;  
  girdSize = 10;  
 }  
 else  
  girdSize = 1;  
  
 xMaxGrad = int((Draw_Size.Width() - TextAreaWidth) / xAxisGrad);  
 for(int i=TextAreaWidth; i<=Draw_Size.Width(); i+=xMaxGrad)  
 {  
  pDC->SelectObject(pBrack);  
  pDC->MoveTo(i,SheetMaxH);  
  if(xMaxGrad<2)  
   temp = xMaxGrad*100;  
  else  
   temp = xMaxGrad*10;  
  if((i-TextAreaWidth)%temp==0)  
  {  
   pDC->LineTo(i,SheetMaxH+10);                            // 整数刻度,绘制长刻度  
  
   //输出对应的文本  
   if(drawCount < 100)  
   {  
    //pDC->SelectObject(font1);                         //选择当前字体  
    StrScale.Format(" %d", drawCount*girdSize);  
    pDC->SetTextColor(RGB(25, 155, 12));  
    pDC->TextOutA(i-10, SheetMaxH+10, StrScale);          //修正文本显示坐标  3位数内,显示方式  
  
                if(Bool_Flag.Show_Max_Grid)  
                {  
                    pDC->SelectObject(pGray);                       //使用虚线灰色画笔  
                    pDC->MoveTo(i,SheetMaxH);  
                    pDC->LineTo(i,20);  
                }  
   }  
   else  
   {  
    StrScale.Format(" %d", drawCount*girdSize);  
    pDC->TextOutA(i-12, SheetMaxH+10, StrScale);          //修正文本显示坐标  4位数内,显示方式  
  
                if(Bool_Flag.Show_Max_Grid)  
                {  
                    pDC->SelectObject(pGray);                       //使用虚线灰色画笔  
                    pDC->MoveTo(i, SheetMaxH);  
                    pDC->LineTo(i, 20);  
                }  
   }  
  }  
  else  
  {  
   pDC->LineTo(i,SheetMaxH+5);                             //小数刻度,绘制短刻度  
  }  
  drawCount++;  
 }  
  
    ReleaseDC(pDC);  
}  
  
  
void My_Draw::Draw_yAxis(CDC *pDC)  
{  
    unsigned int drawCount;  
 CString StrScale;     //转换刻度字符串存放点  
      
    drawCount = 0;  
    //绘制y轴坐标  
 pDC->MoveTo(TextAreaWidth, SheetMaxH);  
 pDC->LineTo(TextAreaWidth, 10);  
 //绘制箭头  
 pDC->LineTo(TextAreaWidth-5, 20);  
 pDC->MoveTo(TextAreaWidth, 10);  
 pDC->LineTo(TextAreaWidth+5, 20);  
  
 yMaxGrad = int(SheetMaxH / yAxisGrad);  
 for(int i=SheetMaxH; i>=20; i-=yMaxGrad)  
 {  
        pDC->SelectObject(pBrack);  
  StrScale.Format("%d", drawCount / 10);  
  pDC->MoveTo(TextAreaWidth, i);  
  
  if(drawCount % 10==0)  
  {  
   pDC->LineTo(TextAreaWidth-10, i);                        //整数刻度,绘制长刻度  
              
            if(Bool_Flag.Show_Max_Grid)  
            {  
                pDC->SelectObject(pGray);                           //使用实线灰色画笔  
                pDC->MoveTo(TextAreaWidth, i);  
                pDC->LineTo(Draw_Size.Width()-10, i);  
            }  
  
   pDC->SetTextColor(RGB(255, 0, 0));  
   pDC->TextOutA(TextAreaWidth-25, i-6, StrScale+"V");       //输出对应的文本  
  }  
  else  
  {  
   pDC->LineTo(TextAreaWidth-5, i);                         //小数刻度,绘制短刻度  
  }  
  drawCount++;  
 }  
      
    ReleaseDC(pDC);  
}  
  
  
void My_Draw::Draw_Cross_Cursor(CDC *pDC)  
{  
    int m_intVoltage;  
    int m_intAngle;  
      
    // 十字光标和显示坐标信息  
    if(Bool_Flag.LButton_Double_Down_Flag)  
    {  
        if((LButton_Double_Down_Point.x > TextAreaWidth)  
            &&(LButton_Double_Down_Point.x < Draw_Size.Width())  
            &&(LButton_Double_Down_Point.y > 20)  
            &&(LButton_Double_Down_Point.y < SheetMaxH))  
        {  
            if(Bool_Flag.Draw_Line_Choice)  
                pDC->SelectObject(pGren);  
            else  
                pDC->SelectObject(pRed);  
  
            pDC->MoveTo(LButton_Double_Down_Point.x, 1);  
            pDC->LineTo(LButton_Double_Down_Point.x, SheetMaxH-1);  
  
            pDC->MoveTo(TextAreaWidth+1, LButton_Double_Down_Point.y);  
            pDC->LineTo(Draw_Size.Width()-1,LButton_Double_Down_Point.y);  
  
            Old_LButton_Double_Down_Point = LButton_Double_Down_Point;  
  
            m_intVoltage = yAxisGrad;  
            m_intVoltage = (SheetMaxH - LButton_Double_Down_Point.y)/m_intVoltage;  
            m_intVoltage /= 10;  
            m_intAngle = xAxisGrad;  
            m_intAngle = (LButton_Double_Down_Point.x - TextAreaWidth)/m_intAngle;  
#ifdef _DEBUG  
            _cprintf("Voltage = %0.2f,Angle = %0.2f\r\n",xAxisGrad,m_intAngle);  
#endif  
            UpdateData(FALSE);  
        }  
    }  
  
    if(Bool_Flag.LButton_Down_Flag)  
    {  
        pDC->SelectObject(pBrack);  
        pDC->MoveTo(Button_Down_Point);  
        pDC->LineTo(Mouse_Current_Point.x,Button_Down_Point.y);  
  
        pDC->MoveTo(Mouse_Current_Point.x,Button_Down_Point.y);  
        pDC->LineTo(Mouse_Current_Point);  
  
        pDC->MoveTo(Mouse_Current_Point);  
        pDC->LineTo(Button_Down_Point.x,Mouse_Current_Point.y);  
  
        pDC->MoveTo(Button_Down_Point.x,Mouse_Current_Point.y);  
        pDC->LineTo(Button_Down_Point);  
  
    }  
    ReleaseDC(pDC);  
}  
  
  
void My_Draw::OnMouseMove(UINT nFlags, CPoint point)  
{  
    // TODO: 在此添加消息处理程序代码和/或调用默认值  
    Mouse_Current_Point = point;  
  
    if(Bool_Flag.Draw_Line_Choice)  
    {  
        Limit_Min = point.x - 5;  
        Limit_Max = point.x + 5;  
        LButton_Double_Down_Point = point;  
    }  
  
  
    if((Bool_Flag.LButton_Down_Flag)  
    ||(Bool_Flag.LButton_Up_Flag))  
        Draw();  
      
    CStatic::OnMouseMove(nFlags, point);  
}  
  
  
void My_Draw::OnLButtonDown(UINT nFlags, CPoint point)  
{  
    // TODO: 在此添加消息处理程序代码和/或调用默认值  
    if((Bool_Flag.LButton_Double_Down_Flag)  
        &&(point.x >= Limit_Min)  
        &&(point.x <= Limit_Max))  
    {  
        if(Bool_Flag.Draw_Line_Choice)  
            Bool_Flag.Draw_Line_Choice = FALSE;  
        else  
            Bool_Flag.Draw_Line_Choice = TRUE;  
      
        LButton_Double_Down_Point = point;  
    }  
    else  
    {  
        if((Bool_Flag.LButton_Down_Flag == FALSE)  
            &&(Bool_Flag.Draw_Line_Choice == FALSE))  
        {  
            Bool_Flag.LButton_Down_Flag = true;  
            Button_Down_Point = point;  
        }  
    }  
    Draw();  
  
    CStatic::OnLButtonDown(nFlags, point);  
}  
  
   
  
   
  
void My_Draw::OnLButtonUp(UINT nFlags, CPoint point)  
{  
    // TODO: 在此添加消息处理程序代码和/或调用默认值  
    if(Bool_Flag.LButton_Down_Flag)  
    {  
        Bool_Flag.LButton_Up_Flag = true;  
        Bool_Flag.LButton_Down_Flag = FALSE;  
        Draw();  
    }  
  
    CStatic::OnLButtonUp(nFlags, point);  
}  
  
  
void My_Draw::OnLButtonDblClk(UINT nFlags, CPoint point)  
{  
    // TODO: 在此添加消息处理程序代码和/或调用默认值  
  
    LButton_Double_Down_Point = point;  
  
    Limit_Min = LButton_Double_Down_Point.x - 5;  
    Limit_Max = LButton_Double_Down_Point.x + 5;  
  
    Bool_Flag.LButton_Double_Down_Flag = TRUE;  
    Draw();  
  
    CStatic::OnLButtonDblClk(nFlags, point);  
}  

程序运行效果图

现在说明一下

1.  新建一个 MFC 应用程序

2. 选择“基于对话框”

3. 添加一个 “Picture 控件”

4. 为控件添加一个变量 my_Graw

5. 将源文件包含进来,并在 My_ClassDlg.h 中包含 #include "My Draw.h"

6. 在 My_ClassDlg.h 头文件中将刚才声明的 Picture  控件变量 CStatic my_Graw ; 改成  My_Draw my_Graw;

7. 在 My_ClassDlg.cpp 文件 void CMy_ClassDlg::OnPaint() 尾部添加 my_Graw.Draw();

8. 编译运行

读者可根据自己的需要在响应的地方改下就好了。
示例下载 http://download.csdn.net/detail/longzhishen/7227255

猜你喜欢

转载自www.cnblogs.com/rainbow70626/p/8969748.html