WIN32界面开发之一:初试加载背景界面

来源:互联网 发布:freebsd内核源码 编辑:程序博客网 时间:2024/05/22 06:33

前言:在实际开发中,虽然有已经成形的界面库DUILIB,但DUILIB无法加载异形窗体,对PNG图片的支持不到位,最终我下决心,自己开发一套界面库,利用GDI+完成2D和3D功能,在这里,我将要记录下,我所做的界面开发的过程,并将它们整理成博客分享给大家,一步步来学习吧。

内容概要:这篇主要实现的功能是加载一个背景界面,向大家介绍下,如何用GDI+加载背景界面的问题,然后就是如何在指定位置托动窗体。

一、创建WIN32工程

1、因为是GDI+绘图,所以对于GDI+的初始化是必须的,在stdafx.h里加入下面代码:

#include <gdiplus.h>#pragma comment(lib,"gdiplus.lib");using namespace Gdiplus;
2、首先看一下WINMAIN函数的写法:
ULONG_PTR gdiplusToken = 0;int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd){Gdiplus::GdiplusStartupInput gdiplusStartupInput;Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);Register(WindowProc,hInstance,L"transparent");HWND hwnd=Create(L"transparent",L"TEST",hInstance);Display(hwnd);Message();Gdiplus::GdiplusShutdown(gdiplusToken);return 0;}
讲解:
1、首先是GDI+的初始化;
2、注册窗口类(Register函数)
3、创建窗口(Create函数)
4、显示窗口(Display函数)
5、消息循环(Message函数)
6、关闭GDI+应用,释放资源

3、注册窗口类(Register函数)写法
BOOL Register(WNDPROC fWndProc,HINSTANCE hInstance,LPCTSTR szClassName){WNDCLASSEX wce={0};wce.cbSize=sizeof(wce);wce.style=CS_HREDRAW|CS_VREDRAW;wce.lpfnWndProc=fWndProc;wce.cbClsExtra=0;wce.cbWndExtra=0;wce.hInstance=hInstance;wce.hIcon=NULL;wce.hCursor=LoadCursor(NULL,IDC_ARROW);wce.hbrBackground=(HBRUSH)(6);wce.lpszMenuName=NULL;wce.lpszClassName=szClassName;wce.hIconSm=NULL;ATOM nAtom=RegisterClassEx(&wce);if(nAtom==0) return false;return true;}
讲解:注册窗口类也没什么好讲的,就是注册WNDCLASSEX结构体,首先对其各项进行赋值,然后调用RegisterClassEx()对其注册,但这里注意的两个地方,fWndPorc是传进来的消息处理函数的指针,我们就是在这个函数里截获窗体有关的各种消息,然后对其进行处理。szClassName是要注册窗体的类名;不同的窗口类,类名不能相同;

4、WndProc消息处理函数的写法;

LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam){switch(uMsg){case WM_DESTROY:PostQuitMessage(100);break;case WM_CREATE:{LONG styleValue = ::GetWindowLong(hwnd, GWL_STYLE);styleValue &= ~WS_CAPTION;styleValue &= ~WS_MAXIMIZEBOX; styleValue &= ~WS_MINIMIZEBOX; styleValue &= ~WS_THICKFRAME; styleValue &= ~WS_BORDER; styleValue &= ~WS_CAPTION;::SetWindowLong(hwnd, GWL_STYLE, styleValue | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);}break;case WM_PAINT:break;case WM_LBUTTONDOWN:break;}return DefWindowProc(hwnd,uMsg,wParam,lParam);}
5、创建窗体(Create函数)写法
HWND Create(LPCTSTR lpClassName,LPCTSTR lpWindowName,HINSTANCE hInstance){HWND m_hWnd = ::CreateWindowEx(WS_EX_LAYERED, L"transparent", _T(""),WS_POPUPWINDOW,CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, (HINSTANCE)::GetModuleHandle(NULL), 0);if(m_hWnd == NULL || !::IsWindow(m_hWnd))return NULL;return m_hWnd;}
6、显示窗体(Display函数)
void Display(HWND hwnd){ShowWindow(hwnd,SW_SHOWNORMAL);UpdateWindow(hwnd);}
7、消息循环(Message()函数)
void Message(){MSG msg={0};while(GetMessage(&msg,NULL,0,0)){TranslateMessage(&msg);DispatchMessage(&msg);}}

二、背景绘图

1、添加消息响应,在WM_PAINT消息中,添加消息响应SetBackground(hwnd,L"C:\\bg.png");

case WM_PAINT:SetBackground(hwnd,L"C:\\bg.png");break;
2、SetBackground函数实现
void SetBackground(HWND m_hWnd,const TCHAR* pBackImgFullPath){//加载图片Gdiplus::Image* pImage = Gdiplus::Image::FromFile(pBackImgFullPath);if (pImage==NULL){assert(false && _T("背景图片打开失败!"));}RECT windowRect;GetWindowRect(m_hWnd,&windowRect);SIZE sizeWindow;if (windowRect.left==windowRect.right){sizeWindow.cx=pImage->GetWidth();sizeWindow.cy=pImage->GetHeight();}else{sizeWindow.cx=windowRect.right-windowRect.left;sizeWindow.cy=windowRect.bottom-windowRect.top;}HDC hDC = ::GetDC(m_hWnd);HDC hdcMemory = CreateCompatibleDC(hDC);RECT rcWindow;GetWindowRect(m_hWnd,&rcWindow);BITMAPINFOHEADER stBmpInfoHeader = { 0 };   int nBytesPerLine = ((sizeWindow.cx * 32 + 31) & (~31)) >> 3;stBmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);   stBmpInfoHeader.biWidth = sizeWindow.cx;   stBmpInfoHeader.biHeight = sizeWindow.cy;   stBmpInfoHeader.biPlanes = 1;   stBmpInfoHeader.biBitCount = 32;   stBmpInfoHeader.biCompression = BI_RGB;   stBmpInfoHeader.biClrUsed = 0;   stBmpInfoHeader.biSizeImage = nBytesPerLine * sizeWindow.cy;   PVOID pvBits = NULL;   HBITMAP hbmpMem = ::CreateDIBSection(NULL, (PBITMAPINFO)&stBmpInfoHeader, DIB_RGB_COLORS, &pvBits, NULL, 0);assert(hbmpMem != NULL);HGDIOBJ hbmpOld = ::SelectObject( hdcMemory, hbmpMem);POINT ptWinPos = { rcWindow.left, rcWindow.top };Gdiplus::Graphics graph(hdcMemory);graph.SetSmoothingMode(Gdiplus::SmoothingModeNone);graph.DrawImage(pImage, 0, 0, sizeWindow.cx, sizeWindow.cy);graph.FillRectangle(&SolidBrush(Color::Gray),0,0,100,50); //用GDI+在画布上画图HMODULE hFuncInst = LoadLibrary(_T("User32.DLL"));typedef BOOL (WINAPI *MYFUNC)(HWND, HDC, POINT*, SIZE*, HDC, POINT*, COLORREF, BLENDFUNCTION*, DWORD);          MYFUNC UpdateLayeredWindow;UpdateLayeredWindow = (MYFUNC)::GetProcAddress(hFuncInst, "UpdateLayeredWindow");POINT ptSrc = { 0, 0};BLENDFUNCTION blendFunc;blendFunc.BlendOp = 0;blendFunc.BlendFlags = 0;blendFunc.AlphaFormat = 1;blendFunc.SourceConstantAlpha = 255;//AC_SRC_ALPHA//不会发送 WM_SIZE和WM_MOVE消息if(!UpdateLayeredWindow(m_hWnd, hDC, &ptWinPos, &sizeWindow, hdcMemory, &ptSrc, 0, &blendFunc, ULW_ALPHA)){assert(L"UpdateLayeredWindow 调用失败");TCHAR tmp[255] = {_T('\0')};}delete pImage;graph.ReleaseHDC(hdcMemory);::SelectObject( hdcMemory, hbmpOld); ::DeleteObject(hFuncInst);::DeleteObject(hbmpOld);::DeleteObject(hbmpMem); ::DeleteDC(hdcMemory);::DeleteDC(hDC);}
讲解:两个关键部分注意一下:
1、
BITMAPINFOHEADER stBmpInfoHeader = { 0 };   int nBytesPerLine = ((sizeWindow.cx * 32 + 31) & (~31)) >> 3;stBmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);   stBmpInfoHeader.biWidth = sizeWindow.cx;   stBmpInfoHeader.biHeight = sizeWindow.cy;   stBmpInfoHeader.biPlanes = 1;   stBmpInfoHeader.biBitCount = 32;   stBmpInfoHeader.biCompression = BI_RGB;   stBmpInfoHeader.biClrUsed = 0;   stBmpInfoHeader.biSizeImage = nBytesPerLine * sizeWindow.cy;   PVOID pvBits = NULL;   HBITMAP hbmpMem = ::CreateDIBSection(NULL, (PBITMAPINFO)&stBmpInfoHeader, DIB_RGB_COLORS, &pvBits, NULL, 0);
这是创建一个32位的位图,这部分代码必须有,否则会出现问题,我们的绘图就是在这个位图上画,然后再显示的桌面上;
2、
HMODULE hFuncInst = LoadLibrary(_T("User32.DLL"));typedef BOOL (WINAPI *MYFUNC)(HWND, HDC, POINT*, SIZE*, HDC, POINT*, COLORREF, BLENDFUNCTION*, DWORD);          MYFUNC UpdateLayeredWindow;UpdateLayeredWindow = (MYFUNC)::GetProcAddress(hFuncInst, "UpdateLayeredWindow");POINT ptSrc = { 0, 0};BLENDFUNCTION blendFunc;blendFunc.BlendOp = 0;blendFunc.BlendFlags = 0;blendFunc.AlphaFormat = 1;blendFunc.SourceConstantAlpha = 255;//AC_SRC_ALPHA//不会发送 WM_SIZE和WM_MOVE消息if(!UpdateLayeredWindow(m_hWnd, hDC, &ptWinPos, &sizeWindow, hdcMemory, &ptSrc, 0, &blendFunc, ULW_ALPHA)){assert(L"UpdateLayeredWindow 调用失败");TCHAR tmp[255] = {_T('\0')};}
讲解:这是UpdateLayeredWindow的标准写法,UpdateLayeredWindow支持ALPHA通道,所以支持PNG图片的显示,但需要注意的是UpdateLayeredWindow不会发送WM_PAINT消息,所以我们要在WM_CREATE消息中,添加一行
PostMessageW(hwnd,WM_PAINT,NULL,NULL);
最终的效果:

三、移动窗体
对于移动窗体就比较简单了,主要是发送SendMessage(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);消息,我们这里是只要在窗体上鼠标按下,就发送这个消息,所以在WM_LBUTTONDOWN消息中添加响应即可,代码如下:
case WM_LBUTTONDOWN:SendMessage(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);break;
至此,这篇的实现就全部讲完了,与往常一样,代码地址:http://download.csdn.net/detail/harvic880925/5757093
转载的标明出处哦!地址:http://blog.csdn.net/harvic880925/article/details/9331701


原创粉丝点击