win32实现类酷狗安装的进度条显示

1.前言

项目中需要一个类似酷狗安装的更新进度条显示,用win32实现了下,需要美工做三张图,代码比较简单

2.实现

1.用vs2010创建一个win32项目

2.将三张图片放在res文件夹下面,并将其导入到项目中

3.在stdafx.h中增加对gdi的支持

// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//

#pragma once

#include "targetver.h"

#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的信息
// Windows 头文件:
#include <windows.h>

// C 运行时头文件
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <locale.h>

#include <olectl.h>
#include <assert.h>

#include <gdiplus.h>
#pragma comment(lib,"gdiplus.lib")
using namespace Gdiplus;

// TODO: 在此处引用程序需要的其他头文件

4.对变量函数进行声明

void SetBackground(HWND m_hWnd);  //实现图片叠加显示
DWORD dw_main = IDB_PNG1;         //底图
DWORD dw_process = IDB_PNG2;      //部分进度条
DWORD dw_count = 0;               //当前显示的进度
DWORD dw_max = 20;                //最大刻度值
DWORD dw_x = 20;                  //进度条在图片上的水平起始坐标
DWORD dw_y  = 310;                //进度条在图片上的垂直起始坐标
#define ID_PROCESS_TIMER 200 //进度条定时器
ULONG_PTR gdiplusToken = 0;       //gdi全局变量

5._tWinMain中对gdi进行初始化

**int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: 在此放置代码。
    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    MSG msg;
    HACCEL hAccelTable;

    // 初始化全局字符串
    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadString(hInstance, IDC_LIKEKUGOU, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // 执行应用程序初始化:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_LIKEKUGOU));

    // 主消息循环:
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    Gdiplus::GdiplusShutdown(gdiplusToken);
    return (int) msg.wParam;
}

6.对窗口属性进行修改

//
// 函数: InitInstance(HINSTANCE, int)
//
// 目的: 保存实例句柄并创建主窗口
//
// 注释:
//
// 在此函数中,我们在全局变量中保存实例句柄并
// 创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // 将实例句柄存储在全局变量中

   //hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
   // CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   hWnd = CreateWindowEx(WS_EX_LAYERED, szWindowClass, szTitle, WS_POPUPWINDOW,
       CW_USEDEFAULT, CW_USEDEFAULT, 
       CW_USEDEFAULT, CW_USEDEFAULT, 
       NULL, NULL, (HINSTANCE)::GetModuleHandle(NULL), 0);


   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

7.wndproc中对消息的处理主要是针对定时器的

//
// 函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// 目的: 处理主窗口的消息。
//
// WM_COMMAND - 处理应用程序菜单
// WM_PAINT - 绘制主窗口
// WM_DESTROY - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;

    switch (message)
    {
    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);

            int scrWidth = GetSystemMetrics ( SM_CXSCREEN ); 
            int scrHeight = GetSystemMetrics ( SM_CYSCREEN ); 
            int nleft = (scrWidth - 580) / 2;
            int ntop  = (scrHeight - 380) / 2;
            SetWindowPos(hWnd, HWND_TOPMOST, nleft, ntop, 580, 380, SWP_SHOWWINDOW);

            InvalidateRect(hWnd, NULL, TRUE);
            UpdateWindow(hWnd);

            //这里开一个定时器测试下效果 看下情况.
            SetTimer(hWnd, ID_PROCESS_TIMER, 500, NULL);
            break;
        }
    case WM_TIMER:
        {
            if (wParam == ID_PROCESS_TIMER)
            {
                dw_count += (dw_count % 3+1);
                if (dw_count > dw_max)
                {
                    //dw_count = dw_max;
                    dw_main = IDB_PNG3;
                    KillTimer(hWnd, ID_PROCESS_TIMER);
                    InvalidateRect(hWnd, NULL, TRUE);
                    UpdateWindow(hWnd);
                    Sleep(1000);
                    SendMessage(hWnd, WM_CLOSE, 0, 0);
                    break;
                }
                InvalidateRect(hWnd, NULL, TRUE);
                UpdateWindow(hWnd);
            }
            break;
        }
    case WM_COMMAND:
        wmId    = LOWORD(wParam);
        wmEvent = HIWORD(wParam);
        // 分析菜单选择:
        switch (wmId)
        {
        case IDM_ABOUT:
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
            break;
        case IDM_EXIT:
            DestroyWindow(hWnd);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        // TODO: 在此添加任意绘图代码...
        SetBackground(hWnd);
        EndPaint(hWnd, &ps);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

8.对底图和进度条进行图片叠加显示

void SetBackground(HWND m_hWnd)
{
    HMODULE hInstance = ::GetModuleHandle(NULL);
    HRSRC hRsrc = ::FindResource(hInstance, MAKEINTRESOURCE(dw_main), _T("PNG")); 
    DWORD dwSize = ::SizeofResource(hInstance, hRsrc);
    LPBYTE lpRsrc = (LPBYTE)::LoadResource(hInstance, hRsrc);

    HGLOBAL hMem = ::GlobalAlloc(GMEM_FIXED, dwSize);
    LPBYTE pMem = (LPBYTE)::GlobalLock(hMem);
    memcpy(pMem, lpRsrc, dwSize);
    IStream* pStream = NULL;
    ::CreateStreamOnHGlobal( hMem, TRUE, &pStream );

    Gdiplus::Image* pImage =  Gdiplus::Image::FromStream(pStream);
    if (pImage==NULL)
        assert(false && _T("error in FromStream."));

    HRSRC hRww = ::FindResource(hInstance, MAKEINTRESOURCE(dw_process), _T("PNG")); 
    DWORD dwWwSize = ::SizeofResource(hInstance, hRww);
    LPBYTE lpRww = (LPBYTE)::LoadResource(hInstance, hRww);
    HGLOBAL hWwMem = ::GlobalAlloc(GMEM_FIXED, dwWwSize);
    LPBYTE pWwMem = (LPBYTE)::GlobalLock(hWwMem);
    memcpy(pWwMem, lpRww, dwWwSize);
    IStream* pWwStream = NULL;
    ::CreateStreamOnHGlobal( hWwMem, TRUE, &pWwStream );
    Gdiplus::Image* pWwImage =  Gdiplus::Image::FromStream(pWwStream);
    if (pWwImage==NULL)
        assert(false && _T("error in FromStream."));

    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);
    //20,310,560,316
    int process_width = pWwImage->GetWidth();
    int process_height = pWwImage->GetHeight();
    if (dw_count <= dw_max)
    {
        for (int nindex = 0; nindex < dw_count; ++nindex)
            graph.DrawImage(pWwImage, dw_x + nindex * process_width, dw_y, process_width, process_height);
    }

    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;
    if(!UpdateLayeredWindow(m_hWnd, hDC, &ptWinPos, &sizeWindow, hdcMemory, &ptSrc, 0, &blendFunc, ULW_ALPHA))
        assert(L"UpdateLayeredWindow failed.");

    SelectObject( hdcMemory, hbmpOld); 
    DeleteObject(hbmpMem); 
    DeleteDC(hdcMemory);
    ReleaseDC(m_hWnd, hDC);
    FreeLibrary(hFuncInst);

    if (pImage != NULL)
        delete pImage;
    pStream->Release();
    ::GlobalUnlock(hMem);

    if (pWwImage != NULL)
        delete pWwImage;
    pWwStream->Release();
    ::GlobalUnlock(hWwMem);
}

3.备注

1.http://download.csdn.net/detail/zhang_ruiqiang/9826938
2.代码比较简单,也比较随意,打破传统编码从控件继承模式,直接进行图片叠加更直观快捷,仅供参考

你可能感兴趣的:(Win32,图片进度条)