win32 窗体开发主要流程

来源:互联网 发布:申万宏源证券炒股软件 编辑:程序博客网 时间:2024/05/21 10:24

窗体设计

窗体设计和消息循环设计流图: 

代码示例:

//设计窗口WNDCLASS wndclass;wndclass.cbClsExtra=0;wndclass.cbWndExtra=0;wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);wndclass.hIcon=LoadIcon(NULL,IDI_ERROR);wndclass.hInstance=hInstance;wndclass.lpfnWndProc=textprom;wndclass.lpszClassName="text";wndclass.lpszMenuName=NULL;wndclass.style=CS_HREDRAW | CS_VREDRAW;//注册窗口类if(!RegisterClass(&wndclass)){    MessageBox(NULL,"create windows error!","error",MB_OK | MB_ICONSTOP);}//创建窗口HWND hwnd=CreateWindow("text","hellow world",WS_DLGFRAME | WS_MINIMIZEBOX | WS_SYSMENU,CW_USEDEFAULT,CW_USEDEFAULT,        CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL);//显示更新窗口ShowWindow(hwnd,nCmdShow);UpdateWindow(hwnd);//消息循环MSG msg;while(GetMessage(&msg,NULL,0,0)){    TranslateMessage(&msg);    DispatchMessage(&msg);}

回调函数设计

设计流图:

设计大致模型:

LRESULT CALLBACK WindowProc(  HWND hwnd,     // handle to window  UINT uMsg,     // message identifier  WPARAM wParam, // first message parameter  LPARAM lParam   // second message parameter){    ……    switch(uMsg)    {    case ‥ : ……;          break;    ……    case WM_DESTROY:  PostQuitMessage(0);//在消息队列尾部插入一个WM_QUIT消息             break;    default: return DefWindowProc(hwnd,uMsg,wParam,lParam);    }    ……    return 0;}

注意:

  1. 必须把所有不处理的消息交给 DefWindowPro 函数处理,也要把它的返回值返回给 windows 否则 windows 就失去了与应用程序通信的途径也就是说不能在控制窗口的行为
  2. WM_DESTROY 是窗口函数必须处理的消息,因为在窗体销毁的时候并不会主动向程序发送一个 WM_QUIT 这个消息,所以我们的窗体即使销毁了程序依旧还在消息循环中,为了达到在销毁窗体时候并且退出消息循环我们应用处理这个WM_DESTROY 这个消息,在程序接收到这个消息时候向消息队列发一个 WM_QUIT 消息来退出消息循环
  3. WM_CLOSE 默认由 DefWindowPro 函数处理,它会调用 DestroyWindow 函数销毁窗口
  4. WM_CREATE 为 WndProc 第一处理的信息
  5. 在视窗大小改变时,会发 WM_SIZE 这个消息且在 lParam 中 LOWORD(lParam) 中为窗口横坐标 HIWORD(lParam) 中为窗口纵坐标
  6. 回调函数的参数与 MSG 结构的前四位成员相同

总体开发流程

程序样例

#include<windows.h>#include"resource.h"#include<string.h>LRESULT CALLBACK textprom(  HWND hwnd,      // handle to window  UINT uMsg,      // message identifier  WPARAM wParam,  // first message parameter  LPARAM lParam   // second message parameter);int WINAPI WinMain(  HINSTANCE hInstance,  // handle to current instance  HINSTANCE hPrevInstance,  // handle to previous instance  LPSTR lpCmdLine,      // pointer to command line  int nCmdShow          // show state of window  ){    WNDCLASS wndclass;    wndclass.cbClsExtra=0;    wndclass.cbWndExtra=0;    wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);    wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);    wndclass.hIcon=LoadIcon(NULL,IDI_ERROR);    wndclass.hInstance=hInstance;    wndclass.lpfnWndProc=textprom;    wndclass.lpszClassName="text";    wndclass.lpszMenuName=NULL;    wndclass.style=CS_HREDRAW | CS_VREDRAW;    if(!RegisterClass(&wndclass))    {        MessageBox(NULL,"create windows error!","error",MB_OK | MB_ICONSTOP);    }    HWND hwnd=CreateWindow("text","hellow world",WS_DLGFRAME | WS_MINIMIZEBOX | WS_SYSMENU,CW_USEDEFAULT,CW_USEDEFAULT,        CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL);    ShowWindow(hwnd,nCmdShow);    UpdateWindow(hwnd);    MSG msg;    while(GetMessage(&msg,NULL,0,0))    {        TranslateMessage(&msg);        DispatchMessage(&msg);    }    return msg.wParam;}LRESULT CALLBACK textprom(  HWND hwnd,      // handle to window  UINT uMsg,      // message identifier  WPARAM wParam,  // first message parameter  LPARAM lParam   // second message parameter){    HDC hdc;    PAINTSTRUCT ps;    RECT rect;    switch(uMsg)    {    case WM_PAINT:        hdc=BeginPaint(hwnd,&ps);        GetClientRect(hwnd,&rect);        DrawText(hdc,"hellow my first windows program",strlen("hellow my first windows program"),&rect,            DT_SINGLELINE | DT_CENTER | DT_VCENTER);        EndPaint(hwnd,&ps);        break;    case WM_RBUTTONDOWN:        hdc=GetDC(hwnd);        TextOut(hdc,0,0,"success",strlen("success"));        ReleaseDC(hwnd,hdc);            break;    case WM_RBUTTONUP:        GetClientRect(hwnd,&rect);        InvalidateRect(hwnd,&rect,true);        break;    case WM_DESTROY:        PostQuitMessage(0);        break;    default:        ;    }    return DefWindowProc(hwnd,uMsg,wParam,lParam);}

 示例图片

透明窗口编写

步骤:

  • 调用 SetWindowLong 设置窗口属性,把窗口设置为具有GWL_EXSTYLE扩展的窗口风格的窗口(可以用SetWindowLong(GetSafeHwnd(),GWL_EXSTYLE,GetWindowLong(GetSafeHwnd(),GWL_EXSTYLE) | WS_EX_LAYERED))
  • 调用SetLayeredWindowAttributes设置窗口透明度

流程图如下:

函数 SetLayeredWindowAttributes 说明:

  • 函数原型:
      BOOL SetLayeredWindowAttributes(
        HWND hwnd, // handle to the layered window 透明窗体的句柄
        COLORREF crKey, // specifies the color key 颜色值,可以用RGB(r,g,b)来指定
        BYTE bAlpha, // value for the blend function 透明度,取值范围是[0,255]
        DWORD dwFlags // action 透明方式,
      );
  • dwFlags说明:
    • 当取值为LWA_ALPHA = 0x2 (值为2) 时,crKey参数无效,bAlpha参数有效;
    • 当取值为LWA_COLORKEY = 0x1 (值为1) 时,bAlpha参数无效,而窗体中的所有颜色为crKey的地方将变为透明
    • 也可以取两个值的组合:LWA_ALPHA Or LWA_COLORKEY.这样crKey的地方将变为全透明,而其它地方根据bAlpha参数确定透明度
  • 要求:  要使使窗体拥有透明效果,首先要有WS_EX_LAYERED扩展属性(可以调用SetWindowLong函数,设置窗体类具有扩展属性属性例如SetWindowLong(this->GetSafeHwnd(), GWL_EXSTYLE, WS_EX_LAYERED) ;)

窗体半透明控件不透明方法:

也是使用SetLayeredWindowAttributes,不同的是,他还用了另一API函数SetParent,基本思路是将某个容器控件用SetParent另外指定一个父窗口,这样控件和主窗体就可以分别使用SetLayeredWindowAttributes函数,控制透明方式,以迅雷的悬浮窗而言就是,将主窗体以窗体透明的方式(LWA_ALPHA标志)半透明,控件以指定颜色的方式(LWA_COLORKEY标志)镂空特定颜色透明,但是由于控件指定了其他的父窗口,因此会有一个不主动跟随窗体移动和显示层次(窗体会覆盖控件)的问题,这些都需要手动控制,实际上就是等于创建两个窗体使用不同的透明方式,然后叠加在一起