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. 選擇“基於對話框”


VS2017 項目屬性參考

MFC 的使用:在靜態庫中使用 MFC

字符集:使用多字節字符集

3. 添加一個 “Picture 控件”


4. 爲控件添加一個變量 my_Draw

5. 將源文件包含進來,並在 My_ClassDlg.h 中包含 #include "My Draw.h"

 

6. 在 My_ClassDlg.h 頭文件中將剛纔聲明的 Picture  控件變量 CStatic my_Graw ; 改成  My_Draw my_Draw;

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

8. 編譯運行


360 我是醉了.......

 

雙擊鼠標左鍵定位, 定位後單擊鼠標左鍵選中,此時就可以拖拽....剩下的自己發揮!
示例下載 https://download.csdn.net/download/longzhishen/10520112

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章