我在编写一个类似小球下落的程序时发生的问题。
1。怎么才可以让窗口不能改变大小
2。我没用向导生成代码,是手工写的,用的是MFC的类。当通过鼠标双击调用DarwBall函数画一个半径为10的小球,并没通过OnPaint绘制,可是当我切换到其他窗口时,小球就不见了,这是为什么,要怎么才可以解决。
3。其中一些代码,由于是第一次自己写程序,不好的地方起指出:
CPoint nPoint;
CRgn rgn;void CMainWindow::DrawBall(CDC* pDC,CPoint point)
{
pDC->BeginPath();
pDC->Ellipse((pint.x-10),(point.y-10),(point.x+10),(point.y+10));
pDC->EndPath();
pDC->SelectFromPath(&rgn) //是不是这个函数不记得了,就是创建一个区域
pDC->InvertRgn(&rgn)    //具体函数是不是也望了,就是反转区域颜色
}void .......::OnLButtonDlbClk(nFlags,point)
{
CClientDC dc(this);
nPoint = point;
dc.DPToLp(&nPoint);  //这个有没必要,我也不太清楚,请指点
DrawBall(&dc,nPoint);
}void ..........::OnStart()  //ON_COMMAND(ID_VIEW_START,OnStart)点击时下落
{
CClientDC dc(this);
CRrect rect;
GetClientRect(&rect);
int nHeight = rect.Height()- 10;
CPoint nball = nPoint;
for(nball.y;nball.y<nHeight;nball.y++)
 {
    dc.InvertRgn(&rgn);
    DarwBall(&dc,nball)
    ::sleep(50);
 }
}当编译时没有问题,双击鼠标后出现一个小球,可在点击开始时出现了错误提示,提示说断言错误,好象是有关GDIObject的m_hObject == NULL的断言有错。请问这是为什么要怎么才可以解决。在小球下落的处理中我觉得我构思方面不太对,请给出一个更好的方案,还有就是有关小球下落过程中的图象更新问题,我最开始是用在一个RECT中绘制一个小圆,然后在通过INVALIDATERECT来实现下落过程的图象更新问题,可是闪烁情况太严重了,请大家给我个好的方法。

解决方案 »

  1.   

    解决闪烁的问题:
    1、在窗口的 WM_ERASEBKGND 消息处理中,直接返回 true 禁止窗口刷新
    2、创建一个和窗口客户区一样大的内存 dc, 先把图像绘制到这个 dc 上面,然后一次把这个 dc 显示到窗口中,应该不会闪烁了。
    -------------
    至于断言错误,应该是某个gdi对象被重复创建或者是没有创建就开始使用,调试一下很容易找到。
      

  2.   

    你要调用WM_PRINT消息,才可以切换到其他窗口回来时重绘。
      

  3.   

    1. 去掉WS_THICKFRAME属性。
    2.在OnPaint中回入绘制小球的代码。
    3.用不用DpToLp视情况而定。
      

  4.   

    onpaint消息就是窗口重画的消息,如果你切换到其他窗口,窗口本身会重画,所以你的小球就消失了
    限制窗口不改变大小,可以通过相应消息来实现
      

  5.   

    绘制代码不放在WM_PAINT中就不行吗?哪位知道的能给个方案!
    如果要你编写个这样的程序,能说说你的构思吗?最好给出一些核心代码
      

  6.   

    要让窗口不能改变大小,就是要是左上角的放大按钮失效,以下代码请参考:
        CreateEx(0,strWndClass,_T(""),WS_OVERLAPPED|WS_SYSMENU|WS_CAPTION|WS_MINIMIZEBOX,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,NULL);不使用OnPaint来绘图,在窗口切换时图像消失是正常的,因为程序调用OnPaint重绘视图,而OnPaint函数中没有你要绘制的内容。所以要解决这个问题还是要把图形在OnPaint函数中绘制。至于解决屏幕闪烁的问题gboy说得没错,即所谓的双缓存,具体实现如下:
    在屏幕上绘制图形时经常出现桌面闪烁的情况,在图形较多的时候更是如此。这是因为Windows程序在重绘窗口以前总是要先用当前系统的背景色将窗口刷干净。然后再调用视图类的OnPaint函数,用OnDraw函数将窗口内的所有图形重绘一遍。闪烁现象是因为屏幕上的图像前后反差太大而造成的。要消除闪烁现象首先就要禁止程序用背景色刷屏。要达到这一目的,只要使视图类的OnEraseBkgnd函数的返回值为TRUE就行了。可是这样一来屏幕很快就会乱掉,除非在OnDraw函数中用背景色将窗口内以前的东西刷干净。但如果这样做的话就和没有设置OnEraseBkgnd函数的效果一样了。不过这样做了以后刷除背景的权利就掌握在了自己手中。
    前面已经讨论过了闪烁现象出现的原因,如果能使屏幕上前后的图像相差很小就不会有闪烁现象了。其实每次要在屏幕上绘制的整个图像与前面的图像相差都很小。但是由于绘图过程有时间延迟,使得整个图像被分成一个个反差很大图像。如果将所有异步输出的图像同步显示出来,那么问题就解决了。这也正是屏幕双缓存的工作原理。
    所谓双缓存,是指屏幕缓存和内存缓存。屏幕缓存中存有前面绘制的图像,内存缓存中存有当前要绘制的图像。屏幕重绘时只显示内存缓存中的东西,这样一来消除闪烁现象的条件就满足了。
    两个缓存中只有内存缓存是需要自己创建的。在程序里它被建在了OnDraw函数中:
    CBitmap bitmap;
    bitmap.CreateCompatibleBitmap (pDC,nBmpWidth,nBmpHight);
    CDC dcMem;
    dcMem.CreateCompatibleDC (pDC);
    CBitmap* pOldBitmap = dcMem.SelectObject (&bitmap);用dcMem画图pDC->BitBlt (0, 0,(int)(pDoc->m_WEworkEnviroment.GetActualDeskWidth()*fProportion), (int)(pDoc->m_WEworkEnviroment.GetActualDeskHight()*fProportion), &dcMem, 0, 0,SRCCOPY);
    这里使用一张DDB位图作为内存缓存。
    首先用CBitmap类的CreateCompatibleBitmap函数创建位图,然后用CDC类的CreateCompatibleDC函数创建一张内存设备描述表,并将位图选入其中,完成位图与内存的绑定。这以后图形都被画在内存设备描述表中。最后用屏幕设备描述表调用BitBlt函数将内存中的位图贴到屏幕上。
    这样双缓存就实现了。