需求: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