导航程序调试1---MFC应用以及数据显示程序
-
问题
error C2664: "BuildCommDCBW": 不能将参数 1 从"char *"转换为"LPCWSTR"经常出现这样的错误?
对于上面的错误,主要是字符编码设置的问题,修改下面的选项即可:
http://bbs.csdn.net/topics/310076558 这篇帖子里面有解决方案.
不能想当然的,就做强制转换,不然可能会出错。下面的做法是错误的。
正确的解决方案:
类似下面这种:
当我们将上面的改为 支持多字符集的时候,我们需要将下面的 OpenEventW (xxxx) 改为:
-
MFC当中创建线程
参考文档: http://www.cnblogs.com/mx113/archive/2009/12/03/1616445.html 使用MFC中的AfxBeginThread创建多线程
用户界面线程和工作线程区别:继承主用户界面进程。
error C2248: "CObject::operator =": 无法访问 private 成员(在"CObject"类中声明)
参考资料: http://blog.csdn.net/cxf7394373/article/details/12389507 这种对控件操作的对象最好都声明成指针
多线程中,数据传递:通过消息机制实现。
下面这个解释和android当中控件必须在子线程当中的解释几乎一致。
不要在线程函数体内操作MFC控件,因为每个线程都有自己的线程模块状态映射表,在一个线程中操作另一个线程中创建的MFC对象,会带来意想不到的问题。更不要在线程函数里,直接调用UpdataData()函数更新用户界面,这会导致程序直接crash。而应该通过发送消息给主线程的方式,在主线程的消息响应函数里操作控件。
不过,我们虽然不能对控件进行操作,但是我们还是可以操作主界面的。
我们完全可以通过获取 AfxGetApp() -> m_pMainWnd -> GetDC(); 来与主窗体进行联系。
但是如何联系里面的控件? 目前还没有好的方法。不过,我觉得肯定是有方法的。
-
如何对MFC当中的EDIT控件进行操作。
这里我们需要通过EDIT控件的ID进行操作。通过其ID我们可以得到很多东西。
参考文章:http://blog.csdn.net/jiayanhui2877/article/details/7589756 MFC Edit控件操作
-
字节,字节,字节
一定要控制好,昨天闲来没事,改了一个字节,把 unsigned short 改为 unsigned int .折腾好久才搞定。后来,竟然是我自己程序出错。我也是无语了。
-
写了一个简单的界面显示:
左边是C++版本,真是丑。右边是C#版本。
遇到的问题颇多,下面说说整体结构。
程序在主线程,也就是 下面这个地方进行开辟2个新的线程进行数据处理:
上面的代码涉及到 EDIT控件的设置问题,我们可以联想到android当中eidtview的设置问题,其实还是蛮像的。
当我们在子线程中,想要获取到主线程的东西的话,比较麻烦,可以通过得到其上下文的方式来进行操作。
如上图的代码就是这样一回事。
当然,这里就涉及到数据通讯的问题。以及数据共享的问题。
还有就是主线程一般是用户界面线程,它有消息循环队列,而我们创建的工作线程中没有这种工作机制。
所以,一般我们想要更新主线程当中的控件的时候,我们一般通过消息队列去通知主线程,然后让主线程去绘制窗体。
毕竟,我们执行程序的时候,所有的东西都是"被实例化的"
继续接上面的开了两个线程之后,怎么办?
线程1:
虚拟总线初始化,等待用户输入,输入0K之后,我们进入到数据采集部分。
还有就是m_run 是由主线程提供的。
线程2:处理线程
处理线程,专门处理子线程1当中采集到的数据,这里我们用了循环数组来进行线程间的通讯。采集完之后,我们直接显示即可。
在用画笔绘制图形的过程中,我想强调一点,适当的sleep是必须的,因为绘制需要时间,不然上一个图形还没绘制完,新图形又过来了,
这样会造成界面的卡顿十分严重。
两个主要的程序代码:
Dlg.h
-
// DatasShowDlg.h : 头文件
-
//
-
-
#pragma once
-
#include "afxwin.h"
-
#include "VirtualSwitchPlus.h"
-
-
DWORD WINAPI DealThread(LPVOID pParam);
-
DWORD WINAPI ReceiverThread(LPVOID pParam);
-
-
extern char szbuffer[10][arrayBytes];
-
extern int recvcount;
-
extern bool m_run;
-
extern CRect* pictureWH;
-
-
extern string msgLable;
-
extern string busNum;
-
-
typedef struct Point //点转换为矩阵的x与y坐标。
-
{
-
unsigned short x;
-
unsigned short y;
-
unsigned char value;
-
unsigned char U;
-
} Point;
-
typedef struct Matrix //稀疏矩阵数据结构
-
{
-
int Num;
-
Point point[3000];
-
-
} Matrix;
-
-
static const int PointLength = 6; //一个point点的长度
-
static const int startoffset = 4; //头字节的长度
-
void DrawPoints(Matrix *marix,LPVOID pParam);
-
-
// CDatasShowDlg 对话框
-
class CDatasShowDlg : public CDialogEx
-
{
-
// 构造
-
public:
-
CDatasShowDlg(CWnd* pParent = NULL); // 标准构造函数
-
-
// 对话框数据
-
enum { IDD = IDD_DATASSHOW_DIALOG };
-
-
protected:
-
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
-
-
-
// 实现
-
protected:
-
HICON m_hIcon;
-
-
// 生成的消息映射函数
-
virtual BOOL OnInitDialog();
-
afx_msg void OnPaint();
-
afx_msg HCURSOR OnQueryDragIcon();
-
DECLARE_MESSAGE_MAP()
-
public:
-
CButton m_show;
-
CEdit m_msgLable;
-
CEdit m_busNum;
-
-
afx_msg void OnBnClickedOk();
-
-
-
CString m_msgLabelNum;
-
CString m_busNumValue;
-
};
Dlg.cpp
-
// DatasShowDlg.cpp : 实现文件
-
//
-
-
#include "stdafx.h"
-
#include "DatasShow.h"
-
#include "DatasShowDlg.h"
-
#include "afxdialogex.h"
-
-
-
#ifdef _DEBUG
-
#define new DEBUG_NEW
-
#endif
-
-
-
// CDatasShowDlg 对话框
-
char szbuffer[10][arrayBytes];
-
int recvcount;
-
bool m_run;
-
CRect* pictureWH = new CRect();
-
string msgLable;
-
string busNum;
-
-
CDatasShowDlg::CDatasShowDlg(CWnd* pParent /*=NULL*/)
-
: CDialogEx(CDatasShowDlg::IDD, pParent)
-
, m_msgLabelNum(_T(""))
-
, m_busNumValue(_T(""))
-
{
-
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
-
}
-
-
void CDatasShowDlg::DoDataExchange(CDataExchange* pDX)
-
{
-
CDialogEx::DoDataExchange(pDX);
-
DDX_Control(pDX, IDOK, m_show);
-
DDX_Control(pDX, IDC_EDIT1, m_msgLable);
-
DDX_Control(pDX, IDC_EDIT2, m_busNum);
-
//DDX_Control(pDX, IDC_PICTURE, m_picture);
-
DDX_Text(pDX, IDC_EDIT1, m_msgLabelNum);
-
DDX_Text(pDX, IDC_EDIT2, m_busNumValue);
-
}
-
-
BEGIN_MESSAGE_MAP(CDatasShowDlg, CDialogEx)
-
ON_WM_PAINT()
-
ON_WM_QUERYDRAGICON()
-
ON_BN_CLICKED(IDOK, &CDatasShowDlg::OnBnClickedOk)
-
END_MESSAGE_MAP()
-
-
-
// CDatasShowDlg 消息处理程序
-
-
BOOL CDatasShowDlg::OnInitDialog()
-
{
-
CDialogEx::OnInitDialog();
-
-
// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
-
// 执行此操作
-
SetIcon(m_hIcon, TRUE); // 设置大图标
-
SetIcon(m_hIcon, FALSE); // 设置小图标
-
-
// TODO: 在此添加额外的初始化代码
-
m_run = false;
-
recvcount = 0;
-
CRect rect;
-
/*m_picture.GetWindowRect(rect);*/
-
-
/*pictureWH = ▭ 下面的参数没什么卵用*/
-
AfxBeginThread((AFX_THREADPROC)DealThread,(LPVOID)GetSafeHwnd(),THREAD_BASE_PRIORITY_IDLE);
-
AfxBeginThread((AFX_THREADPROC)ReceiverThread,NULL,THREAD_BASE_PRIORITY_IDLE);
-
//对edit控件赋值
-
/*char label[20] = {0};
-
char busnum[20] = {0};*/
-
SetDlgItemText(IDC_EDIT1,"Path_GPS");
-
SetDlgItemText(IDC_EDIT2,"1");
-
-
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
-
}
-
-
// 如果向对话框添加最小化按钮,则需要下面的代码
-
// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
-
// 这将由框架自动完成。
-
-
-
DWORD WINAPI DealThread(LPVOID pParam)
-
{
-
-
//CRect* rect = (CRect*)pParam;
-
while(1)
-
{
-
if (m_run)
-
{
-
unsigned char str1[arrayBytes] = {0}; //获取数据
-
//开辟两个无符号类型,这里是加了锁机制处理,string 默认并不是无符号类型
-
-
for (int i = 0; i < arrayBytes; ++i)
-
{
-
str1[i] = szbuffer[(recvcount-1+10)%10][i];
-
}
-
Matrix *matrixH = new Matrix(); //记得释放
-
memset(matrixH,0,sizeof(Matrix));
-
matrixH->Num = str1[3]*16*16*16*16*16*16*16*16 + str1[2]*16*16*16*16 + str1[1]*16*16 + str1[0];
-
int obs1 = 0;
-
for (int i = 0; i < matrixH->Num; ++i)
-
{
-
matrixH->point[obs1].x = str1[startoffset + 1 + i*PointLength]*16*16 + str1[startoffset + 0 + i*PointLength];
-
matrixH->point[obs1].y = str1[startoffset + 3 + i*PointLength]*16*16 + str1[startoffset + 2 + i*PointLength];
-
matrixH->point[obs1].value = str1[startoffset + 4 + i*PointLength];
-
//matrixH->point[obs1].value = 50;
-
matrixH->point[obs1].U = str1[startoffset + 5 + i*PointLength];
-
obs1++; //注意清零
-
}
-
DrawPoints(matrixH,pParam);
-
-
-
delete matrixH;
-
}//end if
-
else
-
{
-
Sleep(1);
-
}
-
}
-
-
-
return 0;
-
}
-
-
void DrawPoints(Matrix *marix,LPVOID pParam)
-
{
-
//HWND hWnd = (HWND)pParam;
-
CRect rect;
-
AfxGetApp()->m_pMainWnd->GetWindowRect(rect);
-
int PicW = rect.Width();
-
int PicH = rect.Height() - 145;
-
//曲线轮廓显示
-
//以下是画在主线程中,我们需要画在picture控件中
-
CDC* pDC = AfxGetApp()->m_pMainWnd->GetDC(); //通过GetDc()获取的HDC直接与相关设备沟通, CDC* pDC = picture.GetDC();
-
-
CDC memDC;
-
CBitmap bmp; //本函数创建的DC,则是与内存中的一个表,面相关联。
-
memDC.CreateCompatibleDC(pDC); //该函数创建一个与指定设备兼容的内存设备上下文环境(DC)。
-
bmp.CreateCompatibleBitmap( pDC, PicW, PicH); //该函数创建与指定的设备环境相关的设备兼容的位图
-
memDC.SelectObject(bmp); //该函数选择一对象到指定的设备上下文环境中,该新对象替换先前的相同类型的对象
-
-
memDC.SelectStockObject(WHITE_BRUSH);//该语句把终端字体选入设备环境
-
memDC.SelectStockObject(WHITE_PEN);
-
-
pDC->SelectStockObject(WHITE_BRUSH);
-
pDC->SelectStockObject(WHITE_PEN);
-
-
int yGap = 10;
-
memDC.Ellipse( PicW/2-5, PicH-yGap-5, PicW/2+5, PicH-yGap+5); //小圆形,用来标识雷达
-
-
int n = 0;
-
int m = 0;
-
for (int i = 0; i < marix->Num; ++i)
-
{
-
n = marix->point[i].x;
-
m = marix->point[i].y;
-
if ((n > 0 && n < 350) && (m > 0 && m < 100))
-
{
-
n = n * PicH / 400;
-
m = m * PicW / 100;
-
memDC.SetPixel(m, n,RGB(255,255,255));
-
//memDC.Ellipse( m-5, n-yGap-5, m+5, n-yGap+5); //小圆形,用来标识雷达
-
}
-
}
-
-
pDC->StretchBlt(0,0,PicH,PicH,&memDC,0,0,PicH,PicH,SRCCOPY); //函数从源矩形中复制一个位图到目标矩形
-
bmp.DeleteObject(); //必要时按目标设备设置的模式进行图像的拉伸或压缩
-
-
/*目标区域左上角点的x坐标
-
目标区域左上角点的y坐标
-
目标区域的宽度
-
目标区域的高度
-
源贴图区域DC的指针
-
源贴图区域x坐标
-
源贴图区域y坐标
-
像素直接拷贝模式*/
-
memDC.DeleteDC();
-
AfxGetApp()->m_pMainWnd->ReleaseDC(pDC);
-
Sleep(50);
-
}
-
-
DWORD WINAPI ReceiverThread(LPVOID pParam)
-
{
-
VirtualSwitchPlusRecv *vspR;
-
while(1) //等待用户输入
-
{
-
if (m_run)
-
{
-
int BUSNUM = busNum[0] - '0';
-
vspR = new VirtualSwitchPlusRecv(BUSNUM);
-
break;
-
}
-
else
-
{
-
Sleep(1);
-
}
-
}
-
-
-
while (true)
-
{
-
vspR->SubMsg(msgLable); //数据必须这样接收,每次判断一次
-
for (int i = 0; i < 3000; ++i)
-
{
-
szbuffer[recvcount][i] = vspR->szbuffer[i];
-
}
-
int nRet = vspR->nRet;
-
-
if (nRet == SOCKET_ERROR)
-
{
-
cout << "Path_GPS not receive!" << endl;
-
}
-
if(nRet > 0) //主程序需要循环检测
-
{
-
cout << "flag0: "<<recvcount<<endl;
-
recvcount = (recvcount + 1) % 10;
-
}else{
-
recvcount = 0;
-
}
-
}
-
delete vspR;
-
}
-
-
void CDatasShowDlg::OnPaint()
-
{
-
if (IsIconic())
-
{
-
CPaintDC dc(this); // 用于绘制的设备上下文
-
-
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
-
-
// 使图标在工作区矩形中居中
-
int cxIcon = GetSystemMetrics(SM_CXICON);
-
int cyIcon = GetSystemMetrics(SM_CYICON);
-
CRect rect;
-
GetClientRect(&rect);
-
int x = (rect.Width() - cxIcon + 1) / 2;
-
int y = (rect.Height() - cyIcon + 1) / 2;
-
-
// 绘制图标
-
dc.DrawIcon(x, y, m_hIcon);
-
}
-
else
-
{
-
CDialogEx::OnPaint();
-
}
-
}
-
-
//当用户拖动最小化窗口时系统调用此函数取得光标
-
//显示。
-
HCURSOR CDatasShowDlg::OnQueryDragIcon()
-
{
-
return static_cast<HCURSOR>(m_hIcon);
-
}
-
-
-
-
void CDatasShowDlg::OnBnClickedOk()
-
{
-
// TODO: 在此添加控件通知处理程序代码
-
if (!m_run){
-
m_show.SetWindowText(_T("暂停"));
-
m_run = true;
-
char label[20] = {0};
-
char busnum[20] = {0};
-
GetDlgItemText(IDC_EDIT1,label,20);
-
GetDlgItemText(IDC_EDIT2,busnum,20);
-
-
busNum = busnum[0];
-
for (int i = 0; i < 20; ++i)
-
{
-
if (label[i] != 0)
-
{
-
msgLable += label[i];
-
}
-
}
-
}else{
-
m_show.SetWindowText(_T("显示"));
-
m_run = false;
-
}
-
-
}
-
-
MFC 的生存周期
参考资料:
http://blog.csdn.net/lesky/article/details/2470907 MFC应用程序的初始化过程
构造全局对象CWinApp è 调用WINMain中的AfxGetAPP
得到全局对象的pApp,然后调用 initInstance,并在里面完成注册,显示窗体。然后执行消息循环。
关于Mfc的好的帖子,值得一看: http://blog.csdn.net/lesky/article/details/2471039 MFC要点概括