我用VC编了一个在地图上实时绘制曲线的程序,就是算一个数据点画一段线那种。
用的当然是最基本的
moveto();
lineto();
啦~!
    绘图程序本身是view类里的成员函数,并且我没有在OnDraw里面调用该函数,而是在一个工作者线程里面调用的,该线程用于计算数据点。
    现在的问题是:绘图功能可以实现,但是在绘制了一段时间以后,程序就会报一个错误,然后就只能终止程序,错误我看不懂:(
   值得注意的是,这个错误似乎与计算步长有关。我编的是画卫星星下点轨道的程序,当计算步长为2秒时,只能画出1轨就报错了。而当我将步长改为30秒时,则可以画出大约15轨,正好与15:1对应,再改步长,该规律依然存在。这是什么原因?
    我尝试着在线程中注释掉绘图程序,只进行计算则不会出错。所以判断是绘图程序出错了。但是如果有错,为什么又可以绘图呢?   
    我是菜鸟,现学VC现编软件,关于绘图什么都不懂。这个问题,不知道表述得是否清楚,也许光靠这点信息无法对错误进行判断,但求各位大虾本着提携后辈的精神,给我提示一些可能的错误之处:比如是否需要用双缓冲,或者绘图程序中可能漏掉了哪些语句?
    最好有高手,能直接指出错误之处,感激不尽!!!!

解决方案 »

  1.   

    嗯,下面我把程序贴出来,有点多。麻烦大家了!首先是OnDraw函数,其中的DrawMapGrid()是在地图上画网格的,似乎没有问题。
    void CSatelliteView::OnDraw(CDC* pDC)
    {
        UNUSED_ALWAYS(pDC); CSatelliteDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    // TODO: add draw code for native data here
    CDC MemDC;//声明内存设备文本对象
    MemDC.CreateCompatibleDC(pDC);//创建兼容内存设备
    //将位图选入内存设备文本对象
    CBitmap*pbmpOld=MemDC.SelectObject(&m_Bitmap);
    //pDC->StretchBlt(0,0,m_Width,m_Height,&MemDC,
    //             0,0,m_Width,m_Height,SRCCOPY);//显示位图
    CRect rcClientRect;//定义一个矩形对象
    GetClientRect(&rcClientRect);//取得窗口客户区尺寸
    pDC->StretchBlt(0,0,rcClientRect.right,rcClientRect.bottom,
    &MemDC,0,0,m_Width,m_Height,SRCCOPY);//显示改变后的位图
    CPoint Pos(0,0);//定位窗口位置
    MemDC.SelectObject(pbmpOld);//恢复原状  DrawMapGrid();
    }
    然后是工作者线程:其中pSatelliteView 是全局变量,在CSatelliteView.cpp中声明的。
    UINT CalcuThreadProc(LPVOID pParam)
    {
    CSatOrbitData* pData = (CSatOrbitData*) pParam;
    int i=0;
    int k;
    double alphaG0 = 0.0;//暂取初始格林威治赤经为0 do
    {
    double r = pData->m_a0;
    pData->a = pData->m_a0;
    pData->e = pData->m_e0;
    pData->i = pData->m_i0*PI/180;
    pData->Omega = pData->m_Omega0*PI/180;
    double n = sqrt(niu/(pData->m_a0*pData->m_a0*pData->m_a0));
    pData->u = Transform(pData->m_u0*PI/180+n*(pData->m_step*i)); //求位置矢量
    pData->Xi = r*(cos(pData->u)*cos(pData->Omega)-sin(pData->u)*cos(pData->i)*sin(pData->Omega));
    pData->Yi = r*(cos(pData->u)*sin(pData->Omega)+sin(pData->u)*cos(pData->i)*cos(pData->Omega));
    pData->Zi = r*sin(pData->u)*sin(pData->i);
    //求速度矢量,暂时不求
    //求经纬度
    double delta = asin(pData->Zi/r);//赤纬
    double alpha = Judge(pData->Xi,pData->Yi);//赤经
    double alphaG = alphaG0+we*pData->m_step*i;//格林威治赤经
    pData->Latitude = delta;//纬度
    pData->Longitude = Transform(alpha-alphaG);//经度
    //开始绘图
    double xxjd[2],xxwd[2];//星下点地理经度、星下点地理纬度
    if(i==0)//需要用一次初始时刻的星下点地理经纬度
    {
    xxjd[0]=pData->Longitude*180/PI;
    xxwd[0]=pData->Latitude*180/PI;
    xxjd[1]=0;
    xxwd[1]=0;
    }
    if(i>=1)
    {
    xxjd[1]=pData->Longitude*180/PI;
    xxwd[1]=pData->Latitude*180/PI;
    } if(pSatelliteView && i>=1)//判断视图类指针是否为空
    pSatelliteView->DrawGroundTrack(xxjd,xxwd);//绘制星下点轨迹
    //写数据
    CString str[10];
    str[0].Format("%e",pData->Latitude*180/PI);
    str[1].Format("%e",pData->Longitude*180/PI);
    str[2].Format("%e",pData->Xi);
    str[3].Format("%e",pData->Yi);
    str[4].Format("%e",pData->Zi);
    str[5].Format("%e",pData->a);
    str[6].Format("%e",pData->e);
    str[7].Format("%e",pData->i);
    str[8].Format("%e",pData->Omega*180/PI);
    str[9].Format("%e",pData->u*180/PI); pBar2->m_wndChild.SetItemText(0,0,"1");
    for(k=0;k<10;k++)
    {
    pBar2->m_wndChild.SetItemText(0,k+1,str[k]);
    } i=i+1;
    }while( pData->Start && !pData->Pause && !pData->End);
    return 0;
    }
    绘制轨迹的函数:
    double CSatelliteView::DrawGroundTrack(double xxjd[2],double xxwd[2])
    {
    int du=10000;//为了避免象素点化整造成的数据点定位误差(表现为曲线抖动厉害)扩大客户坐标比例
    CDC* pDC;
    pDC=GetDC();
    CRect rcClientRect;//定义一个矩形对象
    GetClientRect(&rcClientRect);
    pDC->SetMapMode(MM_ANISOTROPIC);//选择映射模式
    //以下4句将坐标原点移至客户区中央,实现通常意义上的直角坐标系。
    pDC->SetWindowOrg(-180*du,90*du);
    pDC->SetWindowExt(360*du,-180*du);//使Y轴向上,所以纵向度量为负
    pDC->SetViewportOrg(0,0);
    pDC->SetViewportExt(rcClientRect.Width(),rcClientRect.Height());
    //pDC->SetViewportOrg(rcClientRect.Width()/2,
    // rcClientRect.Height()/2);//本来将坐标系原点移至客户区中央也可使用该语句,
    //但是坐标轴方向不合适,仍然是Y向下为正的。
    CPen NewPen;//声明画笔对象
    CPen *pOldPen;//保存原先画笔的指针
    //初始化实线、1象素宽的绿色画笔
    NewPen.CreatePen(PS_SOLID,1,RGB(0,255,0));
    //将画笔选入设备文本对象
    pOldPen=pDC->SelectObject(&NewPen);
    //使用画笔 //double xxjd_buff,xxwd_buff;//星下点地理经度、星下点地理纬度
    if (fabs(xxjd[1]-xxjd[0])>=350)
    {
    pDC->MoveTo(int(xxjd[1]*du),int(xxwd[1]*du));
    }
    else
    {
    pDC->MoveTo(int(xxjd[0]*du),int(xxwd[0]*du));
    pDC->LineTo(int(xxjd[1]*du),int(xxwd[1]*du));
    } xxjd[0]=xxjd[1];
    xxwd[0]=xxwd[1]; //恢复原先的画笔对象
    pDC->SelectObject(pOldPen);

       return (xxjd[0],xxwd[0]);
    return (xxjd[1],xxwd[1]);
    }
      

  2.   

    可能是没有清掉pDC
    在CSatelliteView::DrawGroundTrack中加上
    ReleaseDC(pDC); 试试
      

  3.   

    to fyhfyh1231() :
       嗯~!加入ReleaseDC(pDC); 问题解决了。我就知道肯定是犯了一些很低级的错误,没办法,菜鸟嘛。对vc绘图机制完全不清楚。
       大侠帮忙帮到底,解释一下为什么要释放指针?是不是因为我每次绘制一条线段都创造了一个新指针,而原来的指针没有释放掉,这样就占用了资源,所以当绘图进行到一定的时候,资源不足时,就会出错了?大体意思应该是这样的吧?
       那为什么,我看到很多书上的程序例子都没有ReleaseDC(pDC); 这个语句呢?我写的程序基本上都是看书之后稍做修改得来的。
    顺便问一下,如果同时有几个人为我解答了这个问题,我是否需要每人都给50分,那我岂不是穷了?5555~~~
      

  4.   

    to fyhfyh1231() :
       嗯~!加入ReleaseDC(pDC); 问题解决了。我就知道肯定是犯了一些很低级的错误,没办法,菜鸟嘛。对vc绘图机制完全不清楚。
       大侠帮忙帮到底,解释一下为什么要释放指针?是不是因为我每次绘制一条线段都创造了一个新指针,而原来的指针没有释放掉,这样就占用了资源,所以当绘图进行到一定的时候,资源不足时,就会出错了?大体意思应该是这样的吧?
       那为什么,我看到很多书上的程序例子都没有ReleaseDC(pDC); 这个语句呢?我写的程序基本上都是看书之后稍做修改得来的。
    顺便问一下,如果同时有几个人为我解答了这个问题,我是否需要每人都给50分,那我岂不是穷了?5555~~~