导航程序调试1---MFC应用以及数据显示程序

  1. 问题

    error C2664: "BuildCommDCBW": 不能将参数 1 从"char *"转换为"LPCWSTR"经常出现这样的错误?

     

    对于上面的错误,主要是字符编码设置的问题,修改下面的选项即可:

    http://bbs.csdn.net/topics/310076558 这篇帖子里面有解决方案.

    不能想当然的,就做强制转换,不然可能会出错。下面的做法是错误的。

    正确的解决方案:

    类似下面这种:

     

    当我们将上面的改为 支持多字符集的时候,我们需要将下面的 OpenEventW (xxxx) 改为:

     

     

  2. 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(); 来与主窗体进行联系。

但是如何联系里面的控件? 目前还没有好的方法。不过,我觉得肯定是有方法的。

  1. 如何对MFC当中的EDIT控件进行操作。

    这里我们需要通过EDIT控件的ID进行操作。通过其ID我们可以得到很多东西。

    参考文章:http://blog.csdn.net/jiayanhui2877/article/details/7589756 MFC Edit控件操作

  2. 字节,字节,字节

    一定要控制好,昨天闲来没事,改了一个字节,把 unsigned short 改为 unsigned int .折腾好久才搞定。后来,竟然是我自己程序出错。我也是无语了。

  3. 写了一个简单的界面显示:

    左边是C++版本,真是丑。右边是C#版本。

    遇到的问题颇多,下面说说整体结构。

     

    程序在主线程,也就是 下面这个地方进行开辟2个新的线程进行数据处理:

    上面的代码涉及到 EDIT控件的设置问题,我们可以联想到android当中eidtview的设置问题,其实还是蛮像的。

    当我们在子线程中,想要获取到主线程的东西的话,比较麻烦,可以通过得到其上下文的方式来进行操作。

    如上图的代码就是这样一回事。

    当然,这里就涉及到数据通讯的问题。以及数据共享的问题。

    还有就是主线程一般是用户界面线程,它有消息循环队列,而我们创建的工作线程中没有这种工作机制。

    所以,一般我们想要更新主线程当中的控件的时候,我们一般通过消息队列去通知主线程,然后让主线程去绘制窗体。

    毕竟,我们执行程序的时候,所有的东西都是"被实例化的"

     

     

     

    继续接上面的开了两个线程之后,怎么办?

     

    线程1:

    虚拟总线初始化,等待用户输入,输入0K之后,我们进入到数据采集部分。

    还有就是m_run 是由主线程提供的。

     

     

    线程2:处理线程

    处理线程,专门处理子线程1当中采集到的数据,这里我们用了循环数组来进行线程间的通讯。采集完之后,我们直接显示即可。

    在用画笔绘制图形的过程中,我想强调一点,适当的sleep是必须的,因为绘制需要时间,不然上一个图形还没绘制完,新图形又过来了,

    这样会造成界面的卡顿十分严重。

     

    两个主要的程序代码:

    Dlg.h

    1. // DatasShowDlg.h : 头文件
    2. //
    3.  
    4. #pragma once
    5. #include "afxwin.h"
    6. #include "VirtualSwitchPlus.h"
    7.  
    8. DWORD WINAPI DealThread(LPVOID pParam);
    9. DWORD WINAPI ReceiverThread(LPVOID pParam);
    10.  
    11. extern char szbuffer[10][arrayBytes];
    12. extern int recvcount;
    13. extern bool m_run;
    14. extern CRect* pictureWH;
    15.  
    16. extern string msgLable;
    17. extern string busNum;
    18.  
    19. typedef struct Point //点转换为矩阵的x与y坐标。
    20. {
    21.    unsigned short x;
    22.    unsigned short y;
    23.    unsigned char value;
    24.    unsigned char U;
    25. } Point;
    26. typedef struct Matrix //稀疏矩阵数据结构
    27. {
    28.    int Num;
    29.    Point point[3000];
    30.  
    31. } Matrix;
    32.  
    33. static const int PointLength = 6; //一个point点的长度
    34. static const int startoffset = 4; //头字节的长度
    35. void DrawPoints(Matrix *marix,LPVOID pParam);
    36.  
    37. // CDatasShowDlg 对话框
    38. class CDatasShowDlg : public CDialogEx
    39. {
    40. // 构造
    41. public:
    42.    CDatasShowDlg(CWnd* pParent = NULL); // 标准构造函数
    43.  
    44. // 对话框数据
    45.    enum { IDD = IDD_DATASSHOW_DIALOG };
    46.  
    47.    protected:
    48.    virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
    49.  
    50.  
    51. // 实现
    52. protected:
    53.    HICON m_hIcon;
    54.  
    55.    // 生成的消息映射函数
    56.    virtual BOOL OnInitDialog();
    57.    afx_msg void OnPaint();
    58.    afx_msg HCURSOR OnQueryDragIcon();
    59.    DECLARE_MESSAGE_MAP()
    60. public:
    61.    CButton m_show;
    62.    CEdit m_msgLable;
    63.    CEdit m_busNum;
    64.  
    65.    afx_msg void OnBnClickedOk();
    66.  
    67.  
    68.    CString m_msgLabelNum;
    69.    CString m_busNumValue;
    70. };

     

     

    Dlg.cpp

    1. // DatasShowDlg.cpp : 实现文件
    2. //
    3.  
    4. #include "stdafx.h"
    5. #include "DatasShow.h"
    6. #include "DatasShowDlg.h"
    7. #include "afxdialogex.h"
    8.  
    9.  
    10. #ifdef _DEBUG
    11. #define new DEBUG_NEW
    12. #endif
    13.  
    14.  
    15. // CDatasShowDlg 对话框
    16. char szbuffer[10][arrayBytes];
    17. int recvcount;
    18. bool m_run;
    19. CRect* pictureWH = new CRect();
    20. string msgLable;
    21. string busNum;
    22.  
    23. CDatasShowDlg::CDatasShowDlg(CWnd* pParent /*=NULL*/)
    24.    : CDialogEx(CDatasShowDlg::IDD, pParent)
    25.    , m_msgLabelNum(_T(""))
    26.    , m_busNumValue(_T(""))
    27. {
    28.    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    29. }
    30.  
    31. void CDatasShowDlg::DoDataExchange(CDataExchange* pDX)
    32. {
    33.    CDialogEx::DoDataExchange(pDX);
    34.    DDX_Control(pDX, IDOK, m_show);
    35.    DDX_Control(pDX, IDC_EDIT1, m_msgLable);
    36.    DDX_Control(pDX, IDC_EDIT2, m_busNum);
    37.    //DDX_Control(pDX, IDC_PICTURE, m_picture);
    38.    DDX_Text(pDX, IDC_EDIT1, m_msgLabelNum);
    39.    DDX_Text(pDX, IDC_EDIT2, m_busNumValue);
    40. }
    41.  
    42. BEGIN_MESSAGE_MAP(CDatasShowDlg, CDialogEx)
    43.    ON_WM_PAINT()
    44.    ON_WM_QUERYDRAGICON()
    45.    ON_BN_CLICKED(IDOK, &CDatasShowDlg::OnBnClickedOk)
    46. END_MESSAGE_MAP()
    47.  
    48.  
    49. // CDatasShowDlg 消息处理程序
    50.  
    51. BOOL CDatasShowDlg::OnInitDialog()
    52. {
    53.    CDialogEx::OnInitDialog();
    54.  
    55.    // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
    56.    // 执行此操作
    57.    SetIcon(m_hIcon, TRUE); // 设置大图标
    58.    SetIcon(m_hIcon, FALSE); // 设置小图标
    59.  
    60.    // TODO: 在此添加额外的初始化代码
    61.    m_run = false;
    62.    recvcount = 0;
    63.    CRect rect;
    64.    /*m_picture.GetWindowRect(rect);*/
    65.  
    66.    /*pictureWH = ▭ 下面的参数没什么卵用*/
    67.    AfxBeginThread((AFX_THREADPROC)DealThread,(LPVOID)GetSafeHwnd(),THREAD_BASE_PRIORITY_IDLE);
    68.    AfxBeginThread((AFX_THREADPROC)ReceiverThread,NULL,THREAD_BASE_PRIORITY_IDLE);
    69.    //对edit控件赋值
    70.    /*char label[20] = {0};
    71.    char busnum[20] = {0};*/
    72.    SetDlgItemText(IDC_EDIT1,"Path_GPS");
    73.    SetDlgItemText(IDC_EDIT2,"1");
    74.  
    75.    return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
    76. }
    77.  
    78. // 如果向对话框添加最小化按钮,则需要下面的代码
    79. // 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
    80. // 这将由框架自动完成。
    81.  
    82.  
    83. DWORD WINAPI DealThread(LPVOID pParam)
    84. {
    85.  
    86.    //CRect* rect = (CRect*)pParam;
    87.    while(1)
    88.    {
    89.       if (m_run)
    90.     {
    91.       unsigned char str1[arrayBytes] = {0}; //获取数据
    92.       //开辟两个无符号类型,这里是加了锁机制处理,string 默认并不是无符号类型
    93.  
    94.       for (int i = 0; i < arrayBytes; ++i)
    95.       {
    96.          str1[i] = szbuffer[(recvcount-1+10)%10][i];
    97.       }
    98.       Matrix *matrixH = new Matrix(); //记得释放
    99.       memset(matrixH,0,sizeof(Matrix));
    100.       matrixH->Num = str1[3]*16*16*16*16*16*16*16*16 + str1[2]*16*16*16*16 + str1[1]*16*16 + str1[0];
    101.       int obs1 = 0;
    102.       for (int i = 0; i < matrixH->Num; ++i)
    103.       {
    104.          matrixH->point[obs1].x = str1[startoffset + 1 + i*PointLength]*16*16 + str1[startoffset + 0 + i*PointLength];
    105.          matrixH->point[obs1].y = str1[startoffset + 3 + i*PointLength]*16*16 + str1[startoffset + 2 + i*PointLength];
    106.          matrixH->point[obs1].value = str1[startoffset + 4 + i*PointLength];
    107.          //matrixH->point[obs1].value = 50;
    108.          matrixH->point[obs1].U = str1[startoffset + 5 + i*PointLength];
    109.          obs1++; //注意清零
    110.       }
    111.       DrawPoints(matrixH,pParam);
    112.  
    113.  
    114.       delete matrixH;
    115.       }//end if
    116.       else
    117.       {
    118.          Sleep(1);
    119.       }
    120.    }
    121.  
    122.  
    123.    return 0;
    124. }
    125.  
    126. void DrawPoints(Matrix *marix,LPVOID pParam)
    127. {
    128.    //HWND hWnd = (HWND)pParam;
    129.    CRect rect;
    130.     AfxGetApp()->m_pMainWnd->GetWindowRect(rect);
    131.    int PicW = rect.Width();
    132.    int PicH = rect.Height() - 145;
    133.    //曲线轮廓显示
    134.    //以下是画在主线程中,我们需要画在picture控件中
    135.    CDC* pDC = AfxGetApp()->m_pMainWnd->GetDC(); //通过GetDc()获取的HDC直接与相关设备沟通, CDC* pDC = picture.GetDC();
    136.  
    137.    CDC memDC;
    138.    CBitmap bmp; //本函数创建的DC,则是与内存中的一个表,面相关联。
    139.    memDC.CreateCompatibleDC(pDC); //该函数创建一个与指定设备兼容的内存设备上下文环境(DC)。
    140.    bmp.CreateCompatibleBitmap( pDC, PicW, PicH); //该函数创建与指定的设备环境相关的设备兼容的位图
    141.    memDC.SelectObject(bmp); //该函数选择一对象到指定的设备上下文环境中,该新对象替换先前的相同类型的对象
    142.  
    143.    memDC.SelectStockObject(WHITE_BRUSH);//该语句把终端字体选入设备环境
    144.    memDC.SelectStockObject(WHITE_PEN);
    145.  
    146.    pDC->SelectStockObject(WHITE_BRUSH);
    147.    pDC->SelectStockObject(WHITE_PEN);
    148.  
    149.    int yGap = 10;
    150.    memDC.Ellipse( PicW/2-5, PicH-yGap-5, PicW/2+5, PicH-yGap+5); //小圆形,用来标识雷达
    151.  
    152.    int n = 0;
    153.    int m = 0;
    154.    for (int i = 0; i < marix->Num; ++i)
    155.    {
    156.       n = marix->point[i].x;
    157.       m = marix->point[i].y;
    158.       if ((n > 0 && n < 350) && (m > 0 && m < 100))
    159.       {
    160.          n = n * PicH / 400;
    161.          m = m * PicW / 100;
    162.          memDC.SetPixel(m, n,RGB(255,255,255));
    163.          //memDC.Ellipse( m-5, n-yGap-5, m+5, n-yGap+5); //小圆形,用来标识雷达
    164.       }
    165.    }
    166.  
    167.    pDC->StretchBlt(0,0,PicH,PicH,&memDC,0,0,PicH,PicH,SRCCOPY); //函数从源矩形中复制一个位图到目标矩形
    168.    bmp.DeleteObject(); //必要时按目标设备设置的模式进行图像的拉伸或压缩
    169.  
    170.    /*目标区域左上角点的x坐标
    171.     目标区域左上角点的y坐标
    172.    目标区域的宽度
    173.    目标区域的高度
    174.    源贴图区域DC的指针
    175.    源贴图区域x坐标
    176.    源贴图区域y坐标
    177.    像素直接拷贝模式*/
    178.    memDC.DeleteDC();
    179.    AfxGetApp()->m_pMainWnd->ReleaseDC(pDC);
    180.    Sleep(50);
    181. }
    182.  
    183. DWORD WINAPI ReceiverThread(LPVOID pParam)
    184. {
    185.    VirtualSwitchPlusRecv *vspR;
    186.    while(1) //等待用户输入
    187.     {
    188.       if (m_run)
    189.      {
    190.        int BUSNUM = busNum[0] - '0';
    191.         vspR = new VirtualSwitchPlusRecv(BUSNUM);
    192.        break;
    193.       }
    194.       else
    195.       {
    196.          Sleep(1);
    197.         }
    198.      }
    199.  
    200.  
    201.    while (true)
    202.    {
    203.        vspR->SubMsg(msgLable); //数据必须这样接收,每次判断一次
    204.       for (int i = 0; i < 3000; ++i)
    205.       {
    206.          szbuffer[recvcount][i] = vspR->szbuffer[i];
    207.       }
    208.       int nRet = vspR->nRet;
    209.  
    210.       if (nRet == SOCKET_ERROR)
    211.       {
    212.          cout << "Path_GPS not receive!" << endl;
    213.       }
    214.       if(nRet > 0) //主程序需要循环检测
    215.       {
    216.          cout << "flag0: "<<recvcount<<endl;
    217.          recvcount = (recvcount + 1) % 10;
    218.       }else{
    219.          recvcount = 0;
    220.       }
    221.    }
    222.    delete vspR;
    223. }
    224.  
    225. void CDatasShowDlg::OnPaint()
    226. {
    227.    if (IsIconic())
    228.    {
    229.       CPaintDC dc(this); // 用于绘制的设备上下文
    230.  
    231.       SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
    232.  
    233.       // 使图标在工作区矩形中居中
    234.       int cxIcon = GetSystemMetrics(SM_CXICON);
    235.       int cyIcon = GetSystemMetrics(SM_CYICON);
    236.       CRect rect;
    237.       GetClientRect(&rect);
    238.       int x = (rect.Width() - cxIcon + 1) / 2;
    239.       int y = (rect.Height() - cyIcon + 1) / 2;
    240.  
    241.       // 绘制图标
    242.       dc.DrawIcon(x, y, m_hIcon);
    243.    }
    244.    else
    245.    {
    246.       CDialogEx::OnPaint();
    247.    }
    248. }
    249.  
    250. //当用户拖动最小化窗口时系统调用此函数取得光标
    251. //显示。
    252. HCURSOR CDatasShowDlg::OnQueryDragIcon()
    253. {
    254.    return static_cast<HCURSOR>(m_hIcon);
    255. }
    256.  
    257.  
    258.  
    259. void CDatasShowDlg::OnBnClickedOk()
    260. {
    261.    // TODO: 在此添加控件通知处理程序代码
    262.    if (!m_run){
    263.       m_show.SetWindowText(_T("暂停"));
    264.       m_run = true;
    265.       char label[20] = {0};
    266.       char busnum[20] = {0};
    267.       GetDlgItemText(IDC_EDIT1,label,20);
    268.       GetDlgItemText(IDC_EDIT2,busnum,20);
    269.  
    270.       busNum = busnum[0];
    271.       for (int i = 0; i < 20; ++i)
    272.       {
    273.          if (label[i] != 0)
    274.          {
    275.             msgLable += label[i];
    276.          }
    277.       }
    278.    }else{
    279.       m_show.SetWindowText(_T("显示"));
    280.       m_run = false;
    281.    }
    282.  
    283. }

     

  4. 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要点概括

 

 

 

posted on 2015-08-04 01:48  zhuxuekui3  阅读(608)  评论(0编辑  收藏  举报