在API中怎么解决鼠标拉动图片时的闪烁白条(纯API代码)网上有很多关于这个的问题 但是都是MFC的代码 都是说的双重缓存技术,但是我不知道在纯API怎么实现我现在正在学API 还没有接触MFC 所以看不懂MFC代码//以下是我的代码 麻烦大家帮我 这代码应该怎么改才不会闪烁
---------------------------------
#include <windows.h>
#include <stdio.h>
#include "resource.h"
HDC hdc,hdcBit;//定义图形句柄
HBITMAP hBm;
BITMAP bm;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message,WPARAM wParam, LPARAM lParam);//申明窗口处理函数//-------初始化窗口类---------------------------------
int APIENTRY WinMain(
 HINSTANCE hInstance,      //应用程序当前实例句柄
 HINSTANCE hPrevInstance,  //应用程序其他实例句柄
 LPTSTR lpCmdLine,         //指向程序命令行参数的指针
 int nCmdShow              //应用程序开始执行时窗口显示方式的整数值标识
 )
{
HWND hwnd;         //定义窗口句柄
MSG Msg;           //定义消息的类
WNDCLASS wndclass; //定义窗口的类
char lpszClassName[]="窗口"; //定义窗口类名
char lpszTitle[]="我的窗口"; //定义窗口标题
wndclass.style=0;  //设置窗口样式
wndclass.lpfnWndProc=WndProc;//定义窗口处理函数
wndclass.cbClsExtra=0;//窗口类无扩展
wndclass.cbWndExtra=0;//窗口实例无扩展
wndclass.hInstance=hInstance;//当前实例句柄
wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);//窗口最小化图标为缺省
wndclass.hCursor=LoadCursor(hInstance,MAKEINTRESOURCE(IDB_BITMAP));//窗口采用箭头光标
wndclass.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);//窗口背景色为白色
wndclass.lpszMenuName="Menu";//窗口中无菜单
wndclass.lpszClassName=lpszClassName;//定义窗口类名
//-------初始化窗口类---------------------------------


//-------注册窗口---------------------------------
if(!RegisterClass(&wndclass)) //注册窗口
{
MessageBeep(0); //如果注册失败,则发出警告
return FALSE; //返回为假
}
//-------注册窗口---------------------------------


//-------创建窗口---------------------------------
hwnd=CreateWindow( 
lpszClassName, //窗口类名
lpszTitle,     //窗口标题名
WS_OVERLAPPEDWINDOW|WS_VSCROLL|WS_HSCROLL, //创建窗口的样式,WS_VSCROLL垂直滚动条,WS_HSCROLL水平滚动条
100,100,       //窗口左上角坐标
800,600,       //窗口宽度和度高
NULL,          //该窗口的父窗口句柄
NULL,          //窗口主菜单句柄
hInstance,     //创建窗口的应用程序当前句柄
NULL           //指向一个传递给窗口的参数值的指针 
); 
//-------创建窗口---------------------------------

hBm=LoadBitmap(hInstance,MAKEINTRESOURCE(IDB_BITMAP));
GetObject(hBm,sizeof(BITMAP),(LPVOID)&bm);
ShowWindow(hwnd,nCmdShow);  //显示窗口函数
UpdateWindow(hwnd);         //刷新窗口函数

//-------消息循环---------------------------------
while (GetMessage(&Msg,NULL,0,0))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return (int) Msg.wParam;
}
//-------消息循环---------------------------------//-------窗口处理函相数------------------------------
LRESULT CALLBACK WndProc(HWND hwnd, UINT message,WPARAM wParam, LPARAM lParam)
{
static HINSTANCE     hInst ;
PAINTSTRUCT ps;//定义指向包含绘图信息的结构变量
static POINT nPos,oPos,aPos;
static BOOL ndw=FALSE;
char str[20];
switch(message)
{
case WM_CREATE:
hdc=GetDC(hwnd);
hdcBit=CreateCompatibleDC(hdc);
hBm=CreateCompatibleBitmap(hdc,bm.bmWidth,bm.bmHeight);//双重缓存
hInst = ((LPCREATESTRUCT)lParam)->hInstance;// 获取程序实例句柄
SetClassLong(hwnd, GCL_HICON, (LONG)LoadIcon(hInst, MAKEINTRESOURCE(IDB_BITMAP)));
SetCursor(LoadCursor(hInst, MAKEINTRESOURCE(IDB_BITMAP)));
ReleaseDC(hwnd,hdc);
break;
case WM_LBUTTONDOWN:
if(LOWORD(lParam)>=aPos.x&&LOWORD(lParam)<=aPos.x+bm.bmWidth&&HIWORD(lParam)>=aPos.y&&HIWORD(lParam)<=aPos.y+bm.bmHeight)
{
SetCursor(LoadCursor(hInst,MAKEINTRESOURCE(IDC_CURSOR)));
nPos.x=LOWORD(lParam);
nPos.y=HIWORD(lParam);
ndw=TRUE;
}
break;
case WM_RBUTTONDOWN:
InvalidateRect(hwnd,NULL,TRUE);
break;
case WM_LBUTTONUP:
if(ndw==TRUE)
{
aPos.x=aPos.x+oPos.x;
aPos.y=aPos.y+oPos.y;
ndw=FALSE;
SetCursor(LoadCursor(NULL,IDC_ARROW));
InvalidateRect(hwnd,NULL,TRUE);
}
break;
case WM_MOUSEMOVE:
if(ndw==TRUE)
{
oPos.x=LOWORD(lParam)-nPos.x;
oPos.y=HIWORD(lParam)-nPos.y;

InvalidateRect(hwnd,NULL,TRUE);
ReleaseDC(hwnd,hdc);
}
else
SetCursor(LoadCursor(NULL,IDC_ARROW));
if(LOWORD(lParam)>=aPos.x&&LOWORD(lParam)<=aPos.x+bm.bmWidth&&HIWORD(lParam)>=aPos.y&&HIWORD(lParam)<=aPos.y+bm.bmHeight)
SetCursor(LoadCursor(hInst,MAKEINTRESOURCE(IDC_CURSOR)));
break;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps); //开始绘图
SelectObject(hdcBit,hBm);
if(ndw==FALSE)
StretchBlt(hdc,aPos.x,aPos.y,bm.bmWidth,bm.bmHeight,hdcBit,0,0,bm.bmWidth,bm.bmHeight,SRCCOPY);
else
StretchBlt(hdc,aPos.x+oPos.x,aPos.y+oPos.y,bm.bmWidth,bm.bmHeight,hdcBit,0,0,bm.bmWidth,bm.bmHeight,SRCCOPY);
sprintf(str,"%d,%d",aPos.x,aPos.y);
TextOut(hdc,0,0,str,strlen(str));
EndPaint(hwnd,&ps);//结束绘图
return 0;

case WM_DESTROY://退出消息
DeleteObject(hdcBit);
PostQuitMessage(0);//退出处理函数
return 0;
default: //缺省消息处理函数
return DefWindowProc(hwnd,message,wParam,lParam);
}
return(0);
}
//-------窗口处理函相数------------------------------

解决方案 »

  1.   

    画面闪烁主要旭背景要重画,请将代码中所有的InvalidateRect(hwnd,NULL,TRUE);第三个参数改为FALSE再试试
      

  2.   

    InvalidateRect是为了简化刷新的处理, 通常应在背景反差不大的情况下使用. 在很多入门级的代码示例中用的较多。如果简单的使用InvalidateRect, 即使使用双缓冲,实际应用中也免不了会闪烁。
    比较实用的解决方法是在原使用InvalidateRect的地方直接绘制(别怕麻烦)。可以定义一个函数OnDraw(HDC hdc);在WM_PAINT、WM_MOUSEMOVE等地方直接调用OnDraw
      

  3.   

    chehw(chehw) 说的很有道理
    我那样做了 是不闪烁了 但是鼠标动图片经过的所有位置会留下以前的痕迹
    意思就是图片以外的所有区域没有被刷新
    我想 如果是不用刷新根本解决不了这个问题
    只有解决了刷新的时候产生的闪烁才能根本解决
    希望会的帮帮小弟!
      

  4.   

    chehw(chehw)  说的很有道理  
    我那样做了  是不闪烁了  但是鼠标动图片经过的所有位置会留下以前的痕迹  
    意思就是图片以外的所有区域没有被刷新 
    你说的方法也相当于是把InvalidateRect的最后个值设置为FALSE的效果
    我想  如果是不用刷新根本解决不了这个问题  
    InvalidateRect(hwnd,&rect,FALSE)也不能解决问题
    只有解决了刷新的时候产生的闪烁才能根本解决 
    希望会的帮帮小弟!
      

  5.   

    记录每次移动的位置, 根据记录的位置(rtPrev), 先用FillRect或PatBlt或BitBlt等方法恢复原背景, 然后再用OnDraw在移动后的位置上BitBlt图片. 并记录新位置至rtPrev
      

  6.   

    InvalidateRect决不是入门级才使用的函数。相反它的用法是很有技巧的,像上面的例子,用InvalidateRect来恢复背景,要比用FillRect或PatBlt或BitBlt等方法好的多。前提是设置失效的区域,你不要直接重绘。
    好好体会一下InvalidateRect函数吧。会给你得绘图带来高效率的。
      

  7.   

    InvalidateRect(hWnd, NULL,);
    第二个参数设为NULL后,标记的是整个客户区无效,均需重绘. 写代码时会比较简单,但它是利用系统的消息机制, 通知系统准备重绘. 这种方法即使后面紧跟UpdateWindow, 也必须要等到系统处理完相关消息后才能生效, 如果背景反差大且绘制过程复杂,闪烁很难避免.在WM_SIZE/WM_VSCROLL/WM_HSCROLL等消息的处理中,先GetDC然后直接绘制, 虽然增加了额外的代码量, 但这是高效的方法(不必等系统发消息后再处理, 且在多数情况下不必重绘整个客户区)
      

  8.   

    InvalidateRect的高效通常指的是开发过程的高效(比较省事), 决不是程序运行的高效.