VS2015编写的MFC上位机,波特率可调,可动态显示曲线,可显示三维
VS2015编写的MFC上位机,波特率可调,可动态显示曲线,可显示三维
近期做一个项目正好涉及MFC编写串口上位机,主要用于动态显示曲线和陀螺仪三维信息,想做飞思卡尔或者四旋翼的小伙伴可以借鉴一下,首先贴个结果图:
下面来简单讲解一下这个上位机的核心步骤:
1、首先新建一个串口通信的程序,网上的示例代码有很多,详细的教学文档下载:
http://download.csdn.net/detail/plutus_lee/4525446
2、自动搜索可用串口
新建一个Combo-box Control控件,ID为IDC_COMBO_COM,并输入可选择数据
在OnInitDialog()中调用MYUART_GetComNum()函数即可获得当前可用的串口号,并显示在IDC_COMBO_COM控件中
MYUART_GetComNum()函数如下:
bool CfuzhikejiDlg::MYUART_GetComNum(void)
{
long lReg;
HKEY hKey;
DWORD MaxValueLength;
DWORD dwValueNumber;
lReg = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DEVICEMAP\\SERIALCOMM"),
0, KEY_QUERY_VALUE, &hKey);
if (lReg != ERROR_SUCCESS) //成功时返回ERROR_SUCCESS,
{
//MessageBox(TEXT("未自动找到串口!\nOpen Registry Error!\n"));
return FALSE;
}
lReg = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL,
&dwValueNumber, &MaxValueLength, NULL, NULL, NULL);
if (lReg != ERROR_SUCCESS) //没有成功
{
//MessageBox(TEXT("未自动找到串口!\nGetting Info Error!\n"));
return FALSE;
}
TCHAR *pValueName, *pCOMNumber;
DWORD cchValueName, dwValueSize = 10;
for (int i = 0; i < dwValueNumber; i++)
{
cchValueName = MaxValueLength + 1;
dwValueSize = 10;
pValueName = (TCHAR*)VirtualAlloc(NULL, cchValueName, MEM_COMMIT, PAGE_READWRITE);
lReg = RegEnumValue(hKey, i, pValueName,
&cchValueName, NULL, NULL, NULL, NULL);
if ((lReg != ERROR_SUCCESS) && (lReg != ERROR_NO_MORE_ITEMS))
{
//MessageBox(TEXT("未自动找到串口!\nEnum Registry Error or No More Items!\n"));
return FALSE;
}
pCOMNumber = (TCHAR*)VirtualAlloc(NULL, 6, MEM_COMMIT, PAGE_READWRITE);
lReg = RegQueryValueEx(hKey, pValueName, NULL,
NULL, (LPBYTE)pCOMNumber, &dwValueSize);
if (lReg != ERROR_SUCCESS)
{
//MessageBox(TEXT("未自动找到串口!\nCan not get the name of the port"));
return FALSE;
}
CString str(pCOMNumber);
int len=str.GetLength();
str = str.Right(len - 3);
((CComboBox*)GetDlgItem(IDC_COMBO_COM))->SetCurSel(atoi(str)-1);//把获取的值加入到ComBox控件中
VirtualFree(pValueName, 0, MEM_RELEASE);
VirtualFree(pCOMNumber, 0, MEM_RELEASE);
}
return TRUE;
}
说明:
pCOMNumber即为可用的COM口号,如果在设备管理器里面有COM3口可用,那么CString str(pCOMNumber)执行后,str的值为“COM3”
2、更改波特率等参数
新建Combo-box Control控件,ID分别为IDC_COMBO_BOTELV、IDC_COMBO_JIAOYANWEI、IDC_COMBO_SHUJUWEI 、IDC_COMBO_TINGZHIWEI,并输入可选择数据如下:
在OnInitDialog()中设置初始值
((CComboBox*)GetDlgItem(IDC_COMBO_BOTELV))->SetCurSel(0);
((CComboBox*)GetDlgItem(IDC_COMBO_JIAOYANWEI))->SetCurSel(2);
((CComboBox*)GetDlgItem(IDC_COMBO_SHUJUWEI))->SetCurSel(3);
((CComboBox*)GetDlgItem(IDC_COMBO_TINGZHIWEI))->SetCurSel(0);
添加“打开串口按钮”,添加点击事件如下:
void CfuzhikejiDlg::OnBnClickedButtonOpencom()
{
// TODO: 在此添加控件通知处理程序代码
if (m_cComm.get_PortOpen()) //如果发现串口本来是打开的,则关闭串口
m_cComm.put_PortOpen(FALSE);
CString m_Combo_COM;
GetDlgItemText(IDC_COMBO_COM, m_Combo_COM);
int len = m_Combo_COM.GetLength();
m_Combo_COM = m_Combo_COM.Right(len - 3);
m_cComm.put_CommPort(atoi(m_Combo_COM)); //选择COM端口
m_cComm.put_InputMode(1); //输入方式为二进制方式
m_cComm.put_InBufferSize(1024); //设置输入缓冲区
m_cComm.put_OutBufferSize(1024); //设置输出缓冲区
CString str;
int m_Combo_BOTELV = GetDlgItemInt(IDC_COMBO_BOTELV);
str.Format(_T("%d,"), m_Combo_BOTELV);
CString m_Combo_JIAOYANWEI, m_Combo_SHUJUWEI, m_Combo_TINGZHIWEI;
GetDlgItemText(IDC_COMBO_JIAOYANWEI, m_Combo_JIAOYANWEI);
GetDlgItemText(IDC_COMBO_SHUJUWEI, m_Combo_SHUJUWEI);
GetDlgItemText(IDC_COMBO_TINGZHIWEI, m_Combo_TINGZHIWEI);
str = str + m_Combo_JIAOYANWEI+_T(",")+ m_Combo_SHUJUWEI+_T(",")+ m_Combo_TINGZHIWEI;
m_cComm.put_Settings(str);//波特率,无校验,个数据位,个停止位
//m_cComm.put_Settings(TEXT("9600,n,8,1"));//波特率,无校验,个数据位,个停止位
if (!m_cComm.get_PortOpen())
{
m_cComm.put_PortOpen(TRUE); //打开串口
m_cComm.put_RThreshold(16); //每当接收缓冲区有个字符则接收串口数据
m_cComm.put_InputLen(0); //设置当前缓冲区长度为0
m_cComm.get_Input(); //预读缓冲区以清除残留数据
AfxMessageBox(_T("串口打开成功!"));
}
else
AfxMessageBox("打开端口失败!", MB_ICONSTOP, 0);
}
红色标注部分为更改参数得代码,都是些简单的语句,就不做介绍了。
每次接收16个字节,最后两位为CRC16校验位,由单片机中发送的。
3、接收到数据的处理
void CfuzhikejiDlg::OnComm()
{
// TODO: 在此处添加消息处理程序代码
//从串口接收数据并显示在编辑框中
VARIANT variant_inp;
COleSafeArray safearray_inp;
long len, k;
byte rxdata[512]; //设置BYTE数组
CString strtemp;
unsigned short CRC16 = 0;
short temp[4];
short temp1[3];
float temp_y_axis[4];
if (m_cComm.get_CommEvent() == 2) //值为表示接收缓冲区内有字符
{
variant_inp = m_cComm.get_Input(); //读缓冲区消息
safearray_inp = variant_inp; //变量转换
len = safearray_inp.GetOneDimSize(); //得到有效的数据长度
for (k = 0; k < len; k++)
safearray_inp.GetElement(&k, rxdata + k);
CRC16 = CRC_CHECK(rxdata, len);//CRC16校验
if (CRC16 == 0&& View_Flag ==TRUE)
{
for (k = 0; k < 4; k++) //将数组转换为CString型变量,不包含校验位
{
temp[k] = (short)((rxdata[2 * k + 1] << 8 )| (rxdata[2 * k]));
temp_y_axis[k] = (float)temp[k];
m_plot.AddNewPoint(m_time, temp_y_axis[k], k);
}
m_time += 0.20f;
}
if (CRC16 == 0)
{
temp1[0] = (short)((rxdata[9] << 8) | (rxdata[8]));
temp1[1] = (short)((rxdata[11] << 8) | (rxdata[10]));
temp1[2] = (short)((rxdata[13] << 8) | (rxdata[12]));
m_OpenGL.m_xAngle = temp1[1] / 10;
m_OpenGL.m_yAngle = -temp1[2] / 10;
m_OpenGL.m_zAngle = temp1[0] / 10;
m_OpenGL.InvalidateRect(NULL, FALSE);
}
for (k = 0; k < len; k++) //将数组转换为CString型变量
{
if (k == len - 1)
{
char bt = *(char*)(rxdata + k); //字符型
strtemp.Format("%c", bt); //将字符送入临时变量strtemp存放
m_strRecvData += strtemp; //加入接收编辑框对应字符串
}
}
}
SetDlgItemText(IDC_EDIT_RECV, m_strRecvData);
//UpdateData(FALSE); //更新编辑框内容
m_strRecvData.Empty();
}
黄色背景处代码为:绘制动态曲线的添加点的代码,红色背景为显示陀螺仪三维欧拉角的代码。
16个8位数据储存内容为,第1-8个8位数据为4个16字节绘制动态曲线的数据,一共可绘制四条,第9-14个8位数据为3个16字节陀螺仪三维欧拉角的数据,对应翻滚角,俯仰角和偏航角。
4、绘制动态曲线
主要是参考这篇博文编的http://blog.csdn.net/nuaazdh/article/details/7857223
自己加入按住右键拖动,方向键左右移动,滚动鼠标中键放大缩小等功能。
void CPlot::OnMouseMove(UINT nFlags, CPoint point)
{
if (LBTNDOWN_FLAG)
{
LBTNMOWE_FLAG = TRUE;
m_midPoint = point;
OnPaint();//重绘
}
if (RBTNDOWN_FLAG)
{
m_RendPoint = point;
m_XLwLmt_Trace -= (m_RendPoint.x - m_RstartPoint.x)*m_vppXAxis;
m_XUpLmt_Trace -= (m_RendPoint.x - m_RstartPoint.x)*m_vppXAxis;
m_YLwLmt_Trace += (m_RendPoint.y - m_RstartPoint.y)*m_vppYAxis;
m_YUpLmt_Trace += (m_RendPoint.y - m_RstartPoint.y)*m_vppYAxis;
m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);
m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);
OnPaint();
m_RstartPoint = m_RendPoint;
}
}
void CPlot::OnLButtonUp(UINT nFlag,CPoint point)
{
LBTNDOWN_FLAG = FALSE;
LBTNMOWE_FLAG = FALSE;
m_endPoint = point;
ScaleProcess();// 缩放处理
OnPaint(); // 重绘
TRACE("Left Button Up.Point Coordinate:x=%d,y=%d.\n",point.x,point.y);
CStatic::OnLButtonUp(nFlag,point);
}
void CPlot::OnLButtonDblClk( UINT nFlags, CPoint point )
{
m_bAdjustable = TRUE;// 重新进行自调整
m_axisX.SetAxisRange(m_originXLwLmt,m_originXUpLmt);
m_axisY.SetAxisRange(m_originYLwLmt,m_originYUpLmt);
m_XLwLmt_Trace = m_originXLwLmt;
m_XUpLmt_Trace = m_originXUpLmt;
m_YLwLmt_Trace = m_originYLwLmt;
m_YUpLmt_Trace = m_originYUpLmt;
OnPaint(); // 重绘
CStatic::OnLButtonDblClk(nFlags,point);
}
BOOL CPlot::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
// TODO: Add your message handler code here and/or call default
float proportion=(m_rectPlot.right- m_rectPlot.left)/(m_rectPlot.bottom- m_rectPlot.top);
m_XLwLmt_Trace -= 2.0*zDelta / 120;
m_XUpLmt_Trace += 2.0*zDelta / 120;
m_YLwLmt_Trace -= 2.0* proportion*zDelta / 120;
m_YUpLmt_Trace += 2.0* proportion*zDelta / 120;
m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);
m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);
OnPaint();
//InvalidateRect(NULL, FALSE);//效果一样
return CStatic::OnMouseWheel(nFlags, zDelta, pt);
}
BOOL CPlot::PreTranslateMessage(MSG* pMsg)
{
// TODO: 在此添加专用代码和/或调用基类
float proportion = (m_rectPlot.right - m_rectPlot.left) / (m_rectPlot.bottom - m_rectPlot.top);
if (pMsg->message == WM_KEYDOWN)
{
switch (pMsg->wParam)
{
case VK_UP:
m_YLwLmt_Trace -= 2.0* proportion;
m_YUpLmt_Trace -= 2.0* proportion;
m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);
m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);
OnPaint();
return TRUE;
break;
case VK_DOWN:
m_YLwLmt_Trace += 2.0* proportion;
m_YUpLmt_Trace += 2.0* proportion;
m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);
m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);
OnPaint();
return TRUE;
break;
case VK_LEFT:
m_XLwLmt_Trace += 2.0;
m_XUpLmt_Trace += 2.0;
m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);
m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);
OnPaint();
return TRUE;
break;
case VK_RIGHT:
m_XLwLmt_Trace -= 2.0;
m_XUpLmt_Trace -= 2.0;
m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);
m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);
OnPaint();
return TRUE;
break;
default: MessageBox("Press the arrow keys only");
return TRUE;
break;
}
}
return FALSE;
}
void CPlot::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
m_RstartPoint = point;
RBTNDOWN_FLAG = TRUE;
CStatic::OnRButtonDown(nFlags, point);
}
void CPlot::OnRButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
RBTNDOWN_FLAG = FALSE;
CStatic::OnRButtonUp(nFlags, point);
}
5、OPENGL绘制三维图
参考绘制代码下载:http://download.csdn.net/download/qian365013263/2276152
我主要是基于以上的绘制方法改动得到自己的绘制结果的,因为上面是单文档程序需要我们转成对话框程序,转换并不难但是记得最后调用析构函数去除野指针:
重载函数如下:
OpenGLView::~OpenGLView()
{
if (::wglMakeCurrent(0, 0) == FALSE)
MessageBox("Could not make RC non-current");
if (::wglDeleteContext(m_hRC) == FALSE)
MessageBox("Could not delete RC");
if (m_pDC)
delete m_pDC;
m_pDC = NULL;
}
最后经过我的各种融合,总算是完成了这个工程,虽然不是所有代码都是自己编的,但是也没有看到相关方面的工程,姑且算个原创吧!
链接: http://pan.baidu.com/s/1bnINhxl 密码: w4z2
我的工程文件105M,为什么这么大啊,求解??
近期做一个项目正好涉及MFC编写串口上位机,主要用于动态显示曲线和陀螺仪三维信息,想做飞思卡尔或者四旋翼的小伙伴可以借鉴一下,首先贴个结果图:
下面来简单讲解一下这个上位机的核心步骤:
1、首先新建一个串口通信的程序,网上的示例代码有很多,详细的教学文档下载:
http://download.csdn.net/detail/plutus_lee/4525446
2、自动搜索可用串口
新建一个Combo-box Control控件,ID为IDC_COMBO_COM,并输入可选择数据
在OnInitDialog()中调用MYUART_GetComNum()函数即可获得当前可用的串口号,并显示在IDC_COMBO_COM控件中
MYUART_GetComNum()函数如下:
bool CfuzhikejiDlg::MYUART_GetComNum(void){long lReg;HKEY hKey;DWORD MaxValueLength;DWORD dwValueNumber;
lReg = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DEVICEMAP\\SERIALCOMM"),0, KEY_QUERY_VALUE, &hKey);
if (lReg != ERROR_SUCCESS) //成功时返回ERROR_SUCCESS,{//MessageBox(TEXT("未自动找到串口!\nOpen Registry Error!\n"));return FALSE;}
lReg = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL,&dwValueNumber, &MaxValueLength, NULL, NULL, NULL);
if (lReg != ERROR_SUCCESS) //没有成功{//MessageBox(TEXT("未自动找到串口!\nGetting Info Error!\n"));return FALSE;}
TCHAR *pValueName, *pCOMNumber;DWORD cchValueName, dwValueSize = 10;
for (int i = 0; i < dwValueNumber; i++){cchValueName = MaxValueLength + 1;dwValueSize = 10;pValueName = (TCHAR*)VirtualAlloc(NULL, cchValueName, MEM_COMMIT, PAGE_READWRITE);lReg = RegEnumValue(hKey, i, pValueName,&cchValueName, NULL, NULL, NULL, NULL);
if ((lReg != ERROR_SUCCESS) && (lReg != ERROR_NO_MORE_ITEMS)){//MessageBox(TEXT("未自动找到串口!\nEnum Registry Error or No More Items!\n"));return FALSE;}
pCOMNumber = (TCHAR*)VirtualAlloc(NULL, 6, MEM_COMMIT, PAGE_READWRITE);lReg = RegQueryValueEx(hKey, pValueName, NULL,NULL, (LPBYTE)pCOMNumber, &dwValueSize);
if (lReg != ERROR_SUCCESS){//MessageBox(TEXT("未自动找到串口!\nCan not get the name of the port"));return FALSE;}
CString str(pCOMNumber);int len=str.GetLength();str = str.Right(len - 3);((CComboBox*)GetDlgItem(IDC_COMBO_COM))->SetCurSel(atoi(str)-1);//把获取的值加入到ComBox控件中VirtualFree(pValueName, 0, MEM_RELEASE);VirtualFree(pCOMNumber, 0, MEM_RELEASE);}
return TRUE;}
说明:
pCOMNumber即为可用的COM口号,如果在设备管理器里面有COM3口可用,那么CString str(pCOMNumber)执行后,str的值为“COM3”
2、更改波特率等参数
新建Combo-box Control控件,ID分别为IDC_COMBO_BOTELV、IDC_COMBO_JIAOYANWEI、IDC_COMBO_SHUJUWEI 、IDC_COMBO_TINGZHIWEI,并输入可选择数据如下:
在OnInitDialog()中设置初始值
((CComboBox*)GetDlgItem(IDC_COMBO_BOTELV))->SetCurSel(0);((CComboBox*)GetDlgItem(IDC_COMBO_JIAOYANWEI))->SetCurSel(2);((CComboBox*)GetDlgItem(IDC_COMBO_SHUJUWEI))->SetCurSel(3);((CComboBox*)GetDlgItem(IDC_COMBO_TINGZHIWEI))->SetCurSel(0);
添加“打开串口按钮”,添加点击事件如下:
void CfuzhikejiDlg::OnBnClickedButtonOpencom(){// TODO: 在此添加控件通知处理程序代码if (m_cComm.get_PortOpen()) //如果发现串口本来是打开的,则关闭串口m_cComm.put_PortOpen(FALSE);CString m_Combo_COM;GetDlgItemText(IDC_COMBO_COM, m_Combo_COM);int len = m_Combo_COM.GetLength();m_Combo_COM = m_Combo_COM.Right(len - 3);m_cComm.put_CommPort(atoi(m_Combo_COM)); //选择COM端口m_cComm.put_InputMode(1); //输入方式为二进制方式m_cComm.put_InBufferSize(1024); //设置输入缓冲区m_cComm.put_OutBufferSize(1024); //设置输出缓冲区CString str;int m_Combo_BOTELV = GetDlgItemInt(IDC_COMBO_BOTELV);str.Format(_T("%d,"), m_Combo_BOTELV);CString m_Combo_JIAOYANWEI, m_Combo_SHUJUWEI, m_Combo_TINGZHIWEI;GetDlgItemText(IDC_COMBO_JIAOYANWEI, m_Combo_JIAOYANWEI);GetDlgItemText(IDC_COMBO_SHUJUWEI, m_Combo_SHUJUWEI);GetDlgItemText(IDC_COMBO_TINGZHIWEI, m_Combo_TINGZHIWEI);str = str + m_Combo_JIAOYANWEI+_T(",")+ m_Combo_SHUJUWEI+_T(",")+ m_Combo_TINGZHIWEI;m_cComm.put_Settings(str);//波特率,无校验,个数据位,个停止位//m_cComm.put_Settings(TEXT("9600,n,8,1"));//波特率,无校验,个数据位,个停止位if (!m_cComm.get_PortOpen()){m_cComm.put_PortOpen(TRUE); //打开串口m_cComm.put_RThreshold(16); //每当接收缓冲区有个字符则接收串口数据m_cComm.put_InputLen(0); //设置当前缓冲区长度为0m_cComm.get_Input(); //预读缓冲区以清除残留数据AfxMessageBox(_T("串口打开成功!"));}elseAfxMessageBox("打开端口失败!", MB_ICONSTOP, 0);}
红色标注部分为更改参数得代码,都是些简单的语句,就不做介绍了。
每次接收16个字节,最后两位为CRC16校验位,由单片机中发送的。
3、接收到数据的处理
void CfuzhikejiDlg::OnComm(){// TODO: 在此处添加消息处理程序代码//从串口接收数据并显示在编辑框中VARIANT variant_inp;COleSafeArray safearray_inp;long len, k;byte rxdata[512]; //设置BYTE数组CString strtemp;unsigned short CRC16 = 0;short temp[4];short temp1[3];float temp_y_axis[4];if (m_cComm.get_CommEvent() == 2) //值为表示接收缓冲区内有字符{variant_inp = m_cComm.get_Input(); //读缓冲区消息safearray_inp = variant_inp; //变量转换len = safearray_inp.GetOneDimSize(); //得到有效的数据长度for (k = 0; k < len; k++)safearray_inp.GetElement(&k, rxdata + k);CRC16 = CRC_CHECK(rxdata, len);//CRC16校验if (CRC16 == 0&& View_Flag ==TRUE){for (k = 0; k < 4; k++) //将数组转换为CString型变量,不包含校验位{temp[k] = (short)((rxdata[2 * k + 1] << 8 )| (rxdata[2 * k]));temp_y_axis[k] = (float)temp[k];m_plot.AddNewPoint(m_time, temp_y_axis[k], k);}m_time += 0.20f;}if (CRC16 == 0){temp1[0] = (short)((rxdata[9] << 8) | (rxdata[8]));temp1[1] = (short)((rxdata[11] << 8) | (rxdata[10]));temp1[2] = (short)((rxdata[13] << 8) | (rxdata[12]));m_OpenGL.m_xAngle = temp1[1] / 10;m_OpenGL.m_yAngle = -temp1[2] / 10;m_OpenGL.m_zAngle = temp1[0] / 10;m_OpenGL.InvalidateRect(NULL, FALSE);}for (k = 0; k < len; k++) //将数组转换为CString型变量{if (k == len - 1){char bt = *(char*)(rxdata + k); //字符型strtemp.Format("%c", bt); //将字符送入临时变量strtemp存放m_strRecvData += strtemp; //加入接收编辑框对应字符串}}}SetDlgItemText(IDC_EDIT_RECV, m_strRecvData);//UpdateData(FALSE); //更新编辑框内容m_strRecvData.Empty();}
黄色背景处代码为:绘制动态曲线的添加点的代码,红色背景为显示陀螺仪三维欧拉角的代码。
16个8位数据储存内容为,第1-8个8位数据为4个16字节绘制动态曲线的数据,一共可绘制四条,第9-14个8位数据为3个16字节陀螺仪三维欧拉角的数据,对应翻滚角,俯仰角和偏航角。
4、绘制动态曲线
主要是参考这篇博文编的http://blog.csdn.net/nuaazdh/article/details/7857223
自己加入按住右键拖动,方向键左右移动,滚动鼠标中键放大缩小等功能。
void CPlot::OnMouseMove(UINT nFlags, CPoint point){if (LBTNDOWN_FLAG){LBTNMOWE_FLAG = TRUE;m_midPoint = point;OnPaint();//重绘}if (RBTNDOWN_FLAG){m_RendPoint = point;m_XLwLmt_Trace -= (m_RendPoint.x - m_RstartPoint.x)*m_vppXAxis;m_XUpLmt_Trace -= (m_RendPoint.x - m_RstartPoint.x)*m_vppXAxis;m_YLwLmt_Trace += (m_RendPoint.y - m_RstartPoint.y)*m_vppYAxis;m_YUpLmt_Trace += (m_RendPoint.y - m_RstartPoint.y)*m_vppYAxis;m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);OnPaint();m_RstartPoint = m_RendPoint;
}}void CPlot::OnLButtonUp(UINT nFlag,CPoint point){LBTNDOWN_FLAG = FALSE;LBTNMOWE_FLAG = FALSE;m_endPoint = point;ScaleProcess();// 缩放处理OnPaint(); // 重绘TRACE("Left Button Up.Point Coordinate:x=%d,y=%d.\n",point.x,point.y);CStatic::OnLButtonUp(nFlag,point);}
void CPlot::OnLButtonDblClk( UINT nFlags, CPoint point ){m_bAdjustable = TRUE;// 重新进行自调整m_axisX.SetAxisRange(m_originXLwLmt,m_originXUpLmt);m_axisY.SetAxisRange(m_originYLwLmt,m_originYUpLmt);m_XLwLmt_Trace = m_originXLwLmt;m_XUpLmt_Trace = m_originXUpLmt;m_YLwLmt_Trace = m_originYLwLmt;m_YUpLmt_Trace = m_originYUpLmt;OnPaint(); // 重绘CStatic::OnLButtonDblClk(nFlags,point);}BOOL CPlot::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt){// TODO: Add your message handler code here and/or call defaultfloat proportion=(m_rectPlot.right- m_rectPlot.left)/(m_rectPlot.bottom- m_rectPlot.top);m_XLwLmt_Trace -= 2.0*zDelta / 120;m_XUpLmt_Trace += 2.0*zDelta / 120;m_YLwLmt_Trace -= 2.0* proportion*zDelta / 120;m_YUpLmt_Trace += 2.0* proportion*zDelta / 120;m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);OnPaint();//InvalidateRect(NULL, FALSE);//效果一样return CStatic::OnMouseWheel(nFlags, zDelta, pt);}BOOL CPlot::PreTranslateMessage(MSG* pMsg){// TODO: 在此添加专用代码和/或调用基类float proportion = (m_rectPlot.right - m_rectPlot.left) / (m_rectPlot.bottom - m_rectPlot.top);if (pMsg->message == WM_KEYDOWN){switch (pMsg->wParam){case VK_UP: m_YLwLmt_Trace -= 2.0* proportion;m_YUpLmt_Trace -= 2.0* proportion;m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);OnPaint();return TRUE;break;case VK_DOWN: m_YLwLmt_Trace += 2.0* proportion;m_YUpLmt_Trace += 2.0* proportion;m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);OnPaint();return TRUE;break;case VK_LEFT: m_XLwLmt_Trace += 2.0;m_XUpLmt_Trace += 2.0;m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);OnPaint();return TRUE;break;case VK_RIGHT: m_XLwLmt_Trace -= 2.0;m_XUpLmt_Trace -= 2.0;m_axisX.SetAxisRange(m_XLwLmt_Trace, m_XUpLmt_Trace);m_axisY.SetAxisRange(m_YLwLmt_Trace, m_YUpLmt_Trace);OnPaint();return TRUE;break;default: MessageBox("Press the arrow keys only");return TRUE;break;}}return FALSE;}void CPlot::OnRButtonDown(UINT nFlags, CPoint point){// TODO: 在此添加消息处理程序代码和/或调用默认值m_RstartPoint = point;RBTNDOWN_FLAG = TRUE;CStatic::OnRButtonDown(nFlags, point);}
void CPlot::OnRButtonUp(UINT nFlags, CPoint point){// TODO: 在此添加消息处理程序代码和/或调用默认值RBTNDOWN_FLAG = FALSE;CStatic::OnRButtonUp(nFlags, point);}
5、OPENGL绘制三维图
参考绘制代码下载:http://download.csdn.net/download/qian365013263/2276152
我主要是基于以上的绘制方法改动得到自己的绘制结果的,因为上面是单文档程序需要我们转成对话框程序,转换并不难但是记得最后调用析构函数去除野指针:
重载函数如下:
OpenGLView::~OpenGLView(){if (::wglMakeCurrent(0, 0) == FALSE)MessageBox("Could not make RC non-current");if (::wglDeleteContext(m_hRC) == FALSE)MessageBox("Could not delete RC");if (m_pDC)delete m_pDC;m_pDC = NULL;}
最后经过我的各种融合,总算是完成了这个工程,虽然不是所有代码都是自己编的,但是也没有看到相关方面的工程,姑且算个原创吧!
链接: http://pan.baidu.com/s/1bnINhxl 密码: w4z2
我的工程文件105M,为什么这么大啊,求解??--------------------- 作者:博博有个大大大的Dream 来源:CSDN 原文:https://blog.csdn.net/qq_17783559/article/details/50516228 版权声明:本文为博主原创文章,转载请附上博文链接!
VS2015编写的MFC上位机,波特率可调,可动态显示曲线,可显示三维的更多相关文章
- VC++编写简单串口上位机程序
VC++编写简单串口上位机程序 转载: http://blog.sina.com.cn/s/articlelist_1809084904_0_1.html VC++编写简单串口上位机程序 串口通信 ...
- 我编写的EEPROM 上位机软件
进入模式: 上位机发送 消息 上位机EEPROM 按下进入模式 消息的ID号是:0x08111111 数据是: 00 01 ff 00 00 00 00 00 上位机显示 运行状态 :为进入模式 当我 ...
- VS2008基于对话框的MFC上位机串口通信(C++实现)简单例程
首先,在 vs2008 环境下创建 MFC 运用程序 设置项目名称为 ComTest(这个地方随意命名,根据个人习惯),点击确定后,点击下一步 出现如下界面 选择"基于对话框"模式 ...
- C#做一个简单的进行串口通信的上位机
C#做一个简单的进行串口通信的上位机 1.上位机与下位机 上位机相当于一个软件系统,可以用于接收数据.控制数据.即可以对接收到的数据直接发送操控命令来操作数据.上位机可以接收下位机的信号.下位机是 ...
- 2018最新mfc作为上位机接收硬件端USB或串口数据显示成图片 解决串口接收数据丢字节丢包问题
原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/9490616.html 本文用的是VS2013MFC写串口数据接收: 第一步:首先建立一个MFC ...
- QT编写上位机程序一定要初始化变量以及谨慎操作指针
背景: 在编写QT上位机界面时,界面在运行的时候经常出现卡死或者直接挂掉的怪现象. 正文: 上位机有个函数为check_receive():该函数的作用为定时调用循环检测USB是否有数据.若有,则将信 ...
- MFC开发上位机到底用Dialog结构还是文档结构?
最近要跟着导师一起开发一款大型上位机.MFC新人在考虑用对话框结构还是文档结构. 虽然说书上说大型结构的软件都需要文档结构,但是目前来看,对话框可以实现功能,并且对话框的程序更小一些,节省资源加载速度 ...
- C++ MFC实现基于RFID读写器的上位机软件
C++ MFC实现基于RFID读写器的上位机软件 该博客涉及的完整工程托管在https://github.com/Wsine/UpperMonitor,觉得好请给个Star (/▽\=) 运行和测试环 ...
- vc++MFC开发上位机程序
用vc++MFC开发过不少跟单片机通讯的上位机程序了.搞懂了MFC架构,开发还是很快的,与底层单片机程序通讯,可以用串口.usb.网络.短信形式.串口现在用的越来越少了,一般电脑跟单片机在一块,使用串 ...
随机推荐
- 原生js 对象深拷贝
经常需要copy一个对象,又怕拷贝有问题,那下面这段就很方便啦,不用担心copy只是一个引用了. /** @ values 需要copy的变量 */ function deepClone(values ...
- 前端开发面试题-HTML(转载)
本文由 本文的原作者markyun 收集总结了一些前端面试题,初学者阅后也要用心钻研其中的原理,重要知识需要系统学习.透彻学习,形成自己的知识链.万不可投机取巧,临时抱佛脚只求面试侥幸混过关是错误的! ...
- python自动化开发-6-常用模块-续1
json和pickle模块:用于序列化的模块. 序列化:我们把对象(变量)从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,在其他语言中也被称之为serializatio ...
- Related concepts of testing
根据是否知道源代码测试可以分为黑盒和白盒. 黑盒:功能测试. 白盒:知道源代码,要写测试代码. 根据测试的粒度. 方法测试: 单元测试: 集成测试: 系统测试: 根据测试的暴力程度. 压力测试:谷歌工 ...
- (网页)备注在HTML页面的放置的小技巧(title属性)
其实很简单,就是title这个属性:(字符多余的剪切,title显示完整的字符) 下面是代码: <ul> <li title="江南style.江南style.江南styl ...
- [20171120]11G关闭直接路径读.txt
[20171120]11G关闭直接路径读.txt --//今天做filesystemio_options参数测试时,遇到一个关于直接路径读的问题.--//如果看以前的博客介绍,设置"_ser ...
- FUSE 文件系统 example部分 源码注释 (libfuse 2.9.9)
本篇文章主要是针对fuse-2.9.9 Example 部分 给出的源码,结合官方文档,以及网上的资料给出注释,希望能给正在学习的你们一点帮助. Hello.c /* FUSE: Filesystem ...
- 什么是ORM?为啥要是用ORM?
了解orm,先了解以下概念: 什么是“持久化” 持久(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘).持久化的主要应用是将内存中的数据存储在关系型的数据库中 ...
- MySQL面试题之死锁
什么是死锁?锁等待?如何优化这类问题?通过数据库哪些表可以监控? 死锁是指两个或多个事务在同一资源上互相占用,并请求加锁时,而导致的恶性循环现象.当多个事务以不同顺序试图加锁同一资源时,就会产生死锁. ...
- React路由 + 绝对路径引用
路由: 哈希路由(在url地址后加 #name) // 实现页面监听 window.onhashchange = function(){ console.log(‘hash:’,window.lo ...