📄 chartrx.cpp
字号:
if (x_AxisLabel.rt.right > x_label_left)
{
n_x_TickOneLabel ++;
return FALSE;
}
x_label_left = x_AxisLabel.rt.left;
}
// 判断重叠结束
}
else
{
if ((nLabels - 1) < index) // 如果标签个数小于要求的索引值,不画这个
return TRUE;
CString str1;
LPPOINTDATA pPoint = xLabelPoints.GetPoint(index);
str1.Format(x_LabelFormat, pPoint->x);
x_AxisLabel.GetStringSize(pMemDC->m_hDC, str1, str1.GetLength(), &size);
int top = rt_Back.Height() - x_AxisTitle.rt.Height() - size.cy;
int left = x_Mark - size.cx/2;
x_AxisLabel.rt = CRect(left, top, left + size.cx, top + size.cy);
x_AxisLabel.ShowText(pMemDC->m_hDC, str1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
return TRUE;
}
BOOL CChartRx::DrawYLabel(CString str, int x_Mark, int y_Mark)
{
if (str.GetLength() > y_AxisLabel.text.GetLength())
{
// 默认的,可以放"1234.567这么长,8字节,如果长了,需要重新计算位置,再画一次
y_AxisLabel.text = str; // 保存最长的一个
return FALSE;
}
SIZE size;
y_AxisLabel.GetStringSize(pMemDC->m_hDC, y_AxisLabel.text, y_AxisLabel.text.GetLength(), &size);
int top = y_Mark - size.cy/2;
int left = y_AxisTitle.rt.Width();
y_AxisLabel.rt = CRect(left, top, left + size.cx, top + size.cy);
y_AxisLabel.ShowText(pMemDC->m_hDC, str, DT_RIGHT | DT_VCENTER | DT_SINGLELINE);
return TRUE;
}
void CChartRx::DrawPlot()
{
BOOL ret;
if (shouldReDrawChart) // 标记重新画背景的位置:initChart(),
{
ret = DrawChart(); // 画plot以外的背景
if (!ret)
{
double x1 = x_minSel;
double x2 = x_maxSel;
double y1 = y_maxSel;
double y2 = y_minSel;
InitChart(); // 重新计算大小
x_minSel = x1;
x_maxSel = x2;
y_maxSel = y1;
y_minSel = y2;
ret = DrawChart();
}
if (nChartType == 1) // 画plot区域,折线图
DrawLineChart();
if (nChartType == 2) // 画plot区域,直方图
DrawChartHistogram();
DrawUserPoint();
}
shouldReDrawChart = FALSE;
}
// 从数据转换为图上的象素偏移,0为x轴,1为y轴
// 画坐标轴的时候使用
double CChartRx::GetPixFromValue(int nAxis, double value)
{
double pix = 0;
if (nAxis == 0)
{
if (value > x_maxSel)
value = x_maxSel;
if (value < x_minSel)
value = x_minSel;
pix = rt_Plot.Width() * (value - x_minSel) / (x_maxSel - x_minSel) + rt_Plot.left;
}
else
{
if (value > y_maxSel)
value = y_maxSel;
if (value < y_minSel)
value = y_minSel;
pix = rt_Plot.top + rt_Plot.Height() * (y_maxSel - value) / (y_maxSel - y_minSel);
}
return pix;
}
// 从图上的象素偏移转换为数据,0为x轴,1为y轴
double CChartRx::GetValueFormPix(int nAxis, double pix)
{
double value = 0;
if (nAxis == 0)
{
if (pix < rt_Plot.left)
pix = rt_Plot.left;
if (pix > rt_Plot.right)
pix = rt_Plot.right;
value = (x_maxSel - x_minSel) * (pix - rt_Plot.left) / rt_Plot.Width() + x_minSel;
}
else
{
if (pix < rt_Plot.top)
pix = rt_Plot.top;
if (pix > rt_Plot.bottom)
pix = rt_Plot.bottom;
value = y_maxSel - (y_maxSel - y_minSel) * (pix - rt_Plot.top) / rt_Plot.Height();
}
return value;
}
void CChartRx::OnMouseMove(UINT nFlags, CPoint point)
{
shouldReDrawChart = TRUE;
// 关于放大的部分
if (isMagnifying)
{
shouldReDrawChart = FALSE;
CRect rt = rt_Back;
InflateRect(&rt, -2, -2);
ClientToScreen(&rt);
::ClipCursor(&rt);
}
else
ClipCursor(NULL);
ptCur = point;
// 关于拖动的部分
if (isDraging)
{
::SetCursor(hCurHand);
// int x_off = point.x - ptDown.x;
// int y_off = point.y - ptDown.y;
//
// // 改变用户指点点标签的坐标,即移动点;
// LPPOINTDATA pPoint;
// for (int i=0; i<userPoints.GetPointCount(); i++)
// {
// pPoint = userPoints.GetPoint(i);
// pPoint->x = (int)pPoint->x + x_off;
// pPoint->y = (int)pPoint->y + y_off;
// }
double x_OffData = (x_maxSel - x_minSel) * (point.x - ptDown.x) / rt_Plot.Width();
double y_OffData = (y_maxSel - y_minSel) * (point.y - ptDown.y) / rt_Plot.Height();
x_minSel -= x_OffData;
x_maxSel -= x_OffData;
y_minSel += y_OffData;
y_maxSel += y_OffData;
ptDown = point;
// 12-16 add
CRect rt = rt_Back;
InflateRect(&rt, -2, -2);
ClientToScreen(&rt);
::ClipCursor(&rt);
//
InvalidateRect(rt_Back);
return;
}
else
{
// 只要不是在拖动,或者缩放图表就不需要重画,但是窗口大小改变时候,有问题,
// 会引发这句,刷新失败,
shouldReDrawChart = FALSE;
ClipCursor(NULL);
}
// 如果光标在绘画区,就画提示
if (rt_Plot.PtInRect(point))
DrawTip(point.x, point.y);
else
{
TipLabel.rt.bottom = TipLabel.rt.top;
TipLabel.rt.right = TipLabel.rt.left;
InvalidateRect(rt_Back);
}
if (bShowTip)
HCURSOR old = ::SetCursor(hCurCross);
CWnd::OnMouseMove(nFlags, point);
}
void CChartRx::OnLButtonDown(UINT nFlags, CPoint point)
{
this->SetFocus();
if (!bCanMagnify) // 不可以放大,不处理
return;
isMagnifying = TRUE;
ptDown = point;
shouldReDrawChart = TRUE;
CStatic::OnLButtonDown(nFlags, point);
}
void CChartRx::OnLButtonUp(UINT nFlags, CPoint point)
{
if (!bCanMagnify) // 不可以放大,不处理
return;
if (((point.x - ptDown.x) < 5) || ((point.y - ptDown.y)) < 5)
{
isMagnifying = FALSE;
this->Invalidate();
CStatic::OnLButtonUp(nFlags, point);
return;
}
double x0 = GetValueFormPix(0, ptDown.x);
double x1 = GetValueFormPix(0, point.x);
double y1 = GetValueFormPix(1, ptDown.y);
double y0 = GetValueFormPix(1, point.y);
// CString temp;
// temp.Format(x_LabelFormat +"," + y_LabelFormat, GetValueFormPix(0, point.x), GetValueFormPix(1, point.y));
// temp.Format("%d %d", point.x, point.y);
// MessageBox(temp);
x_minSel = x0;
x_maxSel = x1;
y_minSel = y0;
y_maxSel = y1;
userPoints.Clear(); // 清除用户标记的点
isMagnify = TRUE;
isMagnifying = FALSE;
shouldReDrawChart = TRUE;
x_LabelFormat = AddFormat(x_LabelFormat, x_max - x_min, x_maxSel-x_minSel);
this->Invalidate();
CStatic::OnLButtonUp(nFlags, point);
isMagnify = FALSE;
isMagnified = TRUE;
// 这行需要注释掉,否则放大有问题的!
// shouldReDrawChart = FALSE;
}
void CChartRx::OnLButtonDblClk(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
x_minSel = x_min;
x_maxSel = x_max;
y_maxSel = y_max;
y_minSel = y_min;
isMagnified = FALSE;
x_LabelFormat = x_LabelFormatSel;
y_LabelFormat = y_LabelFormatSel;
n_x_TickOneLabel = n_x_TickOneLabelSel; // 几个大刻度一个标签
n_y_TickOneLabel = n_y_TickOneLabelSel;
userPoints.Clear(); // 清除用户标记的点
shouldReDrawChart = TRUE;
this->Invalidate();
this->SetFocus();
CStatic::OnLButtonDblClk(nFlags, point);
}
void CChartRx::OnRButtonDown(UINT nFlags, CPoint point)
{
ptDown = point;
isDraging = TRUE;
::SetCursor(hCurHand);
shouldReDrawChart = TRUE;
CStatic::OnRButtonDown(nFlags, point);
}
void CChartRx::OnRButtonUp(UINT nFlags, CPoint point)
{
isDraging = FALSE;
// shouldReDrawChart = FALSE;
CStatic::OnRButtonUp(nFlags, point);
}
void CChartRx::DrawTip(int x, int y)
{
CRect rt = TipLabel.rt;
CString temp = "X=" + AddFormat(x_LabelFormat) + " Y=" + AddFormat(y_LabelFormat);
TipLabel.text.Format(temp, GetValueFormPix(0, x), GetValueFormPix(1, y));
SIZE size;
TipLabel.GetStringSize(pMemDC->m_hDC, &size);
if (x > rt_Back.Width()/2)
{
TipLabel.rt.right = x - 5;
TipLabel.rt.left = TipLabel.rt.right - size.cx;
}
else
{
TipLabel.rt.left = x + 5;
TipLabel.rt.right = TipLabel.rt.left + size.cx;
}
if (y > rt_Back.Height()/2)
{
TipLabel.rt.bottom = y - 5;
TipLabel.rt.top = TipLabel.rt.bottom - size.cy;
}
else
{
TipLabel.rt.top = y + 5;
TipLabel.rt.bottom = TipLabel.rt.top + size.cy;
}
if (rt.left > TipLabel.rt.left)
rt.left = TipLabel.rt.left;
if (rt.top > TipLabel.rt.top)
rt.top = TipLabel.rt.top;
if (rt.bottom < TipLabel.rt.bottom)
rt.bottom = TipLabel.rt.bottom;
if (rt.right < TipLabel.rt.right)
rt.right = TipLabel.rt.right;
if (isMagnifying)
this->InvalidateRect(rt_Back);
else
this->InvalidateRect(rt);
}
void CChartRx::DrawScreen(CPaintDC *pDC)
{
// 从背景图直接拷贝数据,减少了画背景的时间
// pTempDC->SelectObject(m_pScreen);
pMemDC->SelectObject(m_pBackGround);
// pTempDC->BitBlt(0, 0, rt_Back.Width(), rt_Back.Height(), pMemDC, 0, 0, SRCCOPY);
pDC->BitBlt(0, 0, rt_Back.Width(), rt_Back.Height(), pMemDC, 0, 0, SRCCOPY);
CPen pen;
pen.CreatePen(PS_SOLID, 1, crForeGround);
if (isMagnifying) // 画矩形
{
pDC->SelectObject(pen);
CRect rt(ptDown, ptCur);
pDC->MoveTo(ptDown);
pDC->LineTo(ptDown.x, ptCur.y);
pDC->LineTo(ptCur);
pDC->LineTo(ptCur.x, ptDown.y);
pDC->LineTo(ptDown);
}
else if(isDraging)
{
}
else
{
if (bShowTip)
TipLabel.ShowText(pDC->m_hDC, TipLabel.text, DT_CENTER | DT_SINGLELINE | DT_VCENTER); //
}
}
void CChartRx::SaveBmpEx(LPCTSTR lpFileName)
{
crBackGround = RGB(250, 250, 250);
TitleLabel.SetColor(RGB(0, 0, 0));
x_AxisTitle.SetColor(RGB(0, 0, 0)); // 128
y_AxisTitle.SetColor(RGB(0, 0, 0));
x_AxisLabel.SetColor(RGB(0, 0, 0));
y_AxisLabel.SetColor(RGB(0, 0, 0));
uptLine.SetStyle(1, PS_SOLID, RGB(0, 0, 0));
userPointsLabel.SetColor(RGB(0, 0, 0));
// 表格基本线的画笔
x_Axis.SetStyle(1, PS_SOLID, RGB(0, 80, 0)); // x轴
y_Axis.SetStyle(1, PS_SOLID, RGB(0, 80, 0)); // y轴
h_Grid.SetStyle(1, PS_DOT, RGB(0, 80, 0)); // 横格线
v_Grid.SetStyle(1, PS_DOT, RGB(0, 80, 0)); // 竖格线
x_Degree.SetStyle(1, PS_SOLID, RGB(0, 80, 0)); // x轴上刻度
y_Degree.SetStyle(1, PS_SOLID, RGB(0, 80, 0)); // y轴上刻度
SetRedraw(FALSE); // 控制屏幕不刷新
shouldReDrawChart = TRUE; // 在内存中重新画一遍
DrawPlot();
SaveBmp(lpFileName);
crBackGround = RGB(0, 60, 0);
TitleLabel.SetColor(RGB(255, 255, 0));
x_AxisTitle.SetColor(RGB(255, 255, 0)); // 128
y_AxisTitle.SetColor(RGB(255, 255, 0));
x_AxisLabel.SetColor(RGB(255, 255, 0));
y_AxisLabel.SetColor(RGB(255, 255, 0));
uptLine.SetStyle(1, PS_SOLID, RGB(255, 255, 0));
userPointsLabel.SetColor(RGB(255, 255, 0));
// 表格基本线的画笔
x_Axis.SetStyle(1, PS_SOLID, RGB(0, 192, 0)); // x轴
y_Axis.SetStyle(1, PS_SOLID, RGB(0, 192, 0)); // y轴
h_Grid.SetStyle(1, PS_DOT, RGB(0, 192, 0)); // 横格线
v_Grid.SetStyle(1, PS_DOT, RGB(0, 192, 0)); // 竖格线
x_Degree.SetStyle(1, PS_SOLID, RGB(0, 192, 0)); // x轴上刻度
y_Degree.SetStyle(1, PS_SOLID, RGB(0, 192, 0)); // y轴上刻度
shouldReDrawChart = TRUE;
DrawPlot();
SetRedraw(TRUE); // 控制屏幕不刷新
}
BOOL CChartRx::SaveBmp(LPCTSTR lpFileName)
{
int iBits; // 当前分辨率下每象素所占字节数
WORD wBitCount; // 位图中每象素所占字节数
DWORD dwPaletteSize = 0; // 定义调色板大小,
DWORD dwBmBitsSize = 0; // 位图中像素字节大小
DWORD dwDIBSize = 0; // 位图文件大小
DWORD dwWritten = 0; // 写入文件字节数
BITMAP Bitmap; // 位图属性结构
BITMAPFILEHEADER bmfHdr; // 位图文件头结构
BITMAPINFOHEADER bi; // 位图信息头结构
LPBITMAPINFOHEADER lpbi; //指向位图信息头结构
HANDLE fh = NULL; // 定义文件,
HANDLE hDib = NULL; //分配内存句柄,
HANDLE hPal = NULL; //调色板句柄
HANDLE hOldPal = NULL;
//计算位图文件每个像素所占字节数
pMemDC->SelectObject(m_pBackGround);
iBits = GetDeviceCaps(pMemDC->m_hDC, BITSPIXEL) * GetDeviceCaps(pMemDC->m_hDC, PLANES);
if (iBits <= 1)
wBitCount = 1;
else if (iBits <= 4)
wBitCount = 4;
else if (iBits <= 8)
wBitCount = 8;
else
wBitCount = 24;
//wBitCount = 4;
HBITMAP hBitmap = HBITMAP(*m_pBackGround);
::GetObject(hBitmap, sizeof(Bitmap), (LPSTR)&Bitmap);
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = Bitmap.bmWidth;
bi.biHeight = Bitmap.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = wBitCount;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrImportant = 0;
bi.biClrUsed = 0;
dwBmBitsSize = ((Bitmap.bmWidth * wBitCount + 31) / 32) * 4 * Bitmap.bmHeight;
//为位图内容分配内存
hDib = ::GlobalAlloc(GHND, dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER));
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
*lpbi = bi;
// 处理调色板
hPal = ::GetStockObject(DEFAULT_PALETTE);
if (hPal)
{
hOldPal = ::SelectPalette(pMemDC->m_hDC, (HPALETTE)hPal, FALSE);
}
// 获取该调色板下新的像素值
::GetDIBits(pMemDC->m_hDC, hBitmap, 0, (UINT) Bitmap.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER)
+dwPaletteSize, (BITMAPINFO *)lpbi, DIB_RGB_COLORS);
//恢复调色板
if (hOldPal)
{
::SelectPalette(pMemDC->m_hDC, (HPALETTE)hOldPal, TRUE);
::RealizePalette(pMemDC->m_hDC);
}
//创建位图文件
fh = ::CreateFile(lpFileName, GENERIC_WRITE,0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (fh == INVALID_HANDLE_VALUE)
return FALSE;
// 设置位图文件头
bmfHdr.bfType = 0x4D42; // "BM"
dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize;
bmfHdr.bfSize = dwDIBSize;
bmfHdr.bfReserved1 = 0;
bmfHdr.bfReserved2 = 0;
bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize;
// 写入位图文件头
::WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
// 写入位图文件其余内容
::WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL);
//清除
::GlobalUnlock(hDib); // 解锁
::GlobalFree(hDib); // 释放文件数据存储区域
::CloseHandle(fh); // 关闭文件
return TRUE;
}
void CChartRx::SetSerialCount(int count)
{
// 一个线,或者说一个通道是一组数对,一个数对为一个点坐标,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -