#include<stdio.h>
#include<windows.h>
struct 
{
int iStyle;
TCHAR* szText;
}button[]=
{
BS_PUSHBUTTON,TEXT("PUSHBUTTON"),
BS_DEFPUSHBUTTON,TEXT("DEFPUSHBUTTON"),
BS_CHECKBOX,TEXT("CHECKBOX"),
BS_AUTOCHECKBOX,TEXT("AUTOCHECKBOX"),
BS_RADIOBUTTON,TEXT("RADIOBUTTON"),
BS_3STATE,TEXT("3STATE"),
BS_AUTO3STATE,TEXT("AUTO3STATE"),
BS_GROUPBOX,TEXT("GROUPBOX"),
BS_AUTORADIOBUTTON,TEXT("AUTORADIO"),
BS_OWNERDRAW,TEXT("OWNERDRAW")
};
#define NUM (sizeof(button)/sizeof(button[0]))
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
/* char buf[30];
DWORD a=GetTickCount();
//printf("%d\n",a);
//wsprintf(buf,"time:%d",a);
itoa(a,buf,10);
MessageBox(NULL,buf,buf,0);
return 0;*/ static TCHAR szAppName[]=TEXT("BtnLook");
HWND hwnd;
MSG  msg;
WNDCLASS wndclass;
 wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     //wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
 wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
     wndclass.lpszMenuName  = NULL;
     wndclass.lpszClassName = szAppName ;
     
     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("This program requires Windows NT!"),
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }
 hwnd = CreateWindow (szAppName, TEXT ("Button Look"), 
                          WS_OVERLAPPEDWINDOW, 
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;     while (GetMessage (&msg, NULL, 0, 0))
     {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
     }
     return msg.wParam ;
}
//void CALLBACK TimerProc(HWND hwnd,UINT message,UINT iTimerID,DWORD dwTimer)LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
static HWND hwndButton[NUM];
static RECT rect;
static TCHAR szTop[]=TEXT("Message wParam lParam"),szUnd[]=TEXT("_____ _____ _____"),szFormat[]=TEXT("%-16s%04X-%04X %04X-%04X"),szBuffer[50];
szBuffer[50];
static int cxChar,cyChar;
HDC hdc;
PAINTSTRUCT ps;
int i;
switch(message)
{
case WM_CREATE:
////WORD HIWORD(
///DWORD dwValue
//);
cxChar=LOWORD(GetDialogBaseUnits());
cyChar=HIWORD(GetDialogBaseUnits());
for(i=0;i<NUM;i++)
hwndButton[i]=CreateWindow(TEXT("button"),button[i].szText,WS_CHILD|WS_VISIBLE|button[i].iStyle,
cxChar,cyChar*(1+2*i),20*cxChar,7*cyChar/4,hwnd,(HMENU)i,((LPCREATESTRUCT)lParam)->hInstance,NULL);
return 0;
case WM_SIZE:
rect.left=24*cxChar;
rect.top=2*cyChar;
rect.right=LOWORD(lParam);
rect.bottom=HIWORD(lParam);
return 0;
case WM_PAINT:
InvalidateRect(hwnd,&rect,TRUE);
hdc=BeginPaint(hwnd,&ps);
SetBkColor(hdc,GetSysColor(COLOR_BTNFACE+1));
SetTextColor(hdc,GetSysColor(COLOR_WINDOWTEXT));
SelectObject(hdc,GetStockObject(SYSTEM_FIXED_FONT));
SetBkMode(hdc,TRANSPARENT);
TextOut(hdc,24*cxChar,cyChar,szTop,lstrlen(szTop));
TextOut(hdc,24*cxChar,cyChar,szUnd,lstrlen(szUnd));
EndPaint(hwnd,&ps);
return 0;
case WM_DRAWITEM:
case WM_COMMAND:
ScrollWindow(hwnd,0,-cyChar,NULL,&rect);//多注意这里,这里有问题
hdc=GetDC(hwnd); SelectObject(hdc,GetStockObject(SYSTEM_FIXED_FONT));
TextOut(hdc,24*cxChar,cyChar*(rect.bottom/cyChar-1),szBuffer,wsprintf(szBuffer,szFormat,message==WM_DRAWITEM?TEXT("WM_DRAWITEM"):TEXT("WM_COMMAND"),HIWORD(wParam),LOWORD(wParam),HIWORD(lParam),LOWORD(lParam)));
ReleaseDC(hwnd,hdc);
ValidateRect(hwnd,&rect);
break;
case WM_KEYDOWN:
switch(wParam)
{
case VK_TAB:
MessageBox(NULL,TEXT("asd "),TEXT("xxx"),0);
}
return 0;
case WM_SYSCOLORCHANGE:
InvalidateRect(hwnd,NULL,TRUE);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
以上代码大家可以测试运行看看效果,当把窗口最小化或者挡住然后恢复显示的时候,发现那10个按钮变的乱七八糟的,因为窗口发生了重绘响应了WM_PAINT消息。这10个按钮是系统自定义的,然后控件==窗口==也有消息处理函数==有自己的WM_PAINT消息处理,对吧?哈哈,相信大家没争议
ScrollWindow(hwnd,0,-cyChar,NULL,&rect);//多注意这里,这里有问题
第三个参数我把变成NULL,表示整个客户区都属于滚动区域,但是第四个参数是裁剪区域才是真正决定谁滚动,所以这里只有rect区域内滚动,而后面的10个按钮不在裁剪区域,所以不需要滚动,但是事实上却不是如此,请问为什么?大家可以测试测试,10个按钮的排列变的乱七八槽,什么导致的?3Q!

解决方案 »

  1.   

        case WM_DRAWITEM:
        case WM_COMMAND:
            ScrollWindow(hwnd,0,-cyChar,NULL,&rect);//多注意这里,这里有问题
            hdc=GetDC(hwnd);-----------
        //case WM_DRAWITEM: 这里注释掉,否则,每次WM_DRAWITEM消息都执行 WM_COMMAND,执行ScrollWindow,肯定有问题了。
        case WM_COMMAND:
            ScrollWindow(hwnd,0,-cyChar,NULL,&rect);//多注意这里,这里有问题
            hdc=GetDC(hwnd);
      

  2.   

    新手问个问题哈这个程序编译之后说我没有main入口啊
      

  3.   


    你用的 console的工程类型吧  应该用WIN32 Application的工程类型建立工程
      

  4.   

    ScrollWindow 对这个函数的理解不到位造成的,以前看的都是百度百科中文翻译,都说真正决定滚动区域的是第四个参数,仔细看了MSDN的英文才发现事实并非如此,第三个参数就是决定谁滚动,而第四个参数更是别有用意的,贴出MSDN解释:
    lpRect [in] 
    Type: const RECT*Pointer to the RECT structure specifying the portion of the client area to be scrolled. If this parameter is NULL, the entire client area is scrolled. lpClipRect [in] 
    Type: const RECT*Pointer to the RECT structure containing the coordinates of the clipping rectangle. Only device bits within the clipping rectangle are affected. Bits scrolled from the outside of the rectangle to the inside are painted; bits scrolled from the inside of the rectangle to the outside are not painted. 第四个参数可以结合第三个参数是使用,比如说第三个参数NULL表示客户区全部滚动,第四个参数&rect表示了客户区中间的一部分。则当整个客户区滚动的时候会出现以下情况:
    一定有客户区的内容滚动到了这个&rect区域中,同时必有这个裁剪区域&rect中的内容滚出去了,滚动了客户区,参考Bits scrolled from the outside of the rectangle to the inside are painted; bits scrolled from the inside of the rectangle to the outside are not painted. 
    相信大家啊就明白这个参数的意义了。
    回头看上述代码,
    ScrollWindow(hwnd,0,-cyChar,NULL,&rect);//
    整个客户区都会滚动,10个按钮在客户区吧,会滚动吧,这里没争议吧,然而ScrollWindow会触发WM_PAINT消息(这点大家可以随便证明)所以导致窗口要重绘的,
    代码
    case WM_PAINT:
            InvalidateRect(hwnd,&rect,TRUE);
            hdc=BeginPaint(hwnd,&ps);
            SetBkColor(hdc,GetSysColor(COLOR_BTNFACE+1));
            SetTextColor(hdc,GetSysColor(COLOR_WINDOWTEXT));
            SelectObject(hdc,GetStockObject(SYSTEM_FIXED_FONT));
            SetBkMode(hdc,TRANSPARENT);
            TextOut(hdc,24*cxChar,cyChar,szTop,lstrlen(szTop));
            TextOut(hdc,24*cxChar,cyChar,szUnd,lstrlen(szUnd));
            EndPaint(hwnd,&ps);
            return 0;
    可以看到没有重绘这10个已经被上移的按钮,所以必然会发生乱七八糟的,这个时候我们刷新一下窗口就看到效果了,移上去了。
    也做了一个实验,因为WM_PAINT中有两句很关键
            TextOut(hdc,24*cxChar,cyChar,szTop,lstrlen(szTop));
            TextOut(hdc,24*cxChar,cyChar,szUnd,lstrlen(szUnd));
    所以我定义了一个全局变量count并初始化为0,在WM_PAINT中if(count<3) 则TEXTOUT那两句
    否则不画这两句,最后在WM_COMMAND中加上count++,来测试用户点击按钮导致WM_COMMAND(我测试的时候把WM_DRAWITEM注释掉了,为了方便)然后count自增,当小于3的时候窗口的客户区会输出TEXTOUT的那两句的内容的,当你在点击2才WM_COMMAND的时候,count=3了,此时不满足if(count<3)了,所以窗口上不会在继续出现TEXTOUT的那两句话了(这个其实已经证明了SCROLLWINDOW可以触发WM_PAINT消息了)。
    主要的原因在于起床没把SCROLLWINDOW理解正确,结论:以后还是看MSDN好点。