// 先上傳代碼
// .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