<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    VC++ WIN32 sdk實現按鈕自繪詳解 之二.

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接 網上找了很多,可只是給出代碼,沒有詳細解釋,不便初學者理解.我就抄回冷飯.把這個再拿出來說說. 實例圖片:   RFID設備管理軟件 首先建立一個標準的Win32 Application 工程.選擇a simple Win32 Application. 然后建立我們的資源文件首先新建一個對話框資源,資源ID改為IDD_MAIN_DLG 然后在其上新建一個按鈕控件資源ID改為IDC_ODBUTTON,此按鈕的styles中必須選中owenerdraw屬性. 然后將其保存為.rc的資源文件.并將其導入我們的工程.同理新建一個圖標文件資源ID改為IDI_OWNERDRAW保存為.ico的圖標然后導入. 準備工作做完了下面開始寫代碼. 首先聲明如下全局變量. #include "stdafx.h"
    #include "resource.h"
       HINSTANCE odInst = NULL;  //接收程序實例的句柄
    HWND hMainWnd = NULL;     //接收主窗口的句柄
    HWND hDlgNow = NULL;      //接收對話框的句柄
    static HICON hOwnerDrawIcon = NULL;  //用作自繪按鈕的圖標
    static LONG prev_proc;                 //儲存按鈕先前的回調函數
    static HICON hIcon = NULL;           //對話框圖標句柄
    然后開始寫WinMain()函數 int APIENTRY WinMain(HINSTANCE hInstance,
                         HINSTANCE hPrevInstance,
                         LPSTR     lpCmdLine,
                         
    int       nCmdShow)
    {
         
    // TODO: Place code here.
        odInst = hInstance;
        
        WNDCLASS  wc;
        wc.style         = 0;
        wc.lpfnWndProc   = (WNDPROC)ODWndProc; 
    //
    定義一個窗口默認函數,這里我們會交由默認窗口函數處理
        wc.cbClsExtra    = 0;
        wc.cbWndExtra    = 0;
        wc.hInstance     = hInstance;
        wc.hIcon         = LoadIcon(odInst,MAKEINTRESOURCE(IDI_OWNERDRAW));
        wc.hCursor       = NULL;
        wc.hbrBackground = 0;
        wc.lpszClassName = "OwnerDraw";
        wc.lpszMenuName     = NULL;

        RegisterClass(&wc);

    MSG msg;
        
        HWND onlywin= FindWindow("OwnerDraw","MyOwnerDraw");

        
    if (onlywin)
            
    {
            ExitProcess(1);
            }
        
        hMainWnd=CreateWindow("OwnerDraw","MyOwnerDraw",WS_OVERLAPPEDWINDOW,
                    CW_USEDEFAULT,0,CW_USEDEFAULT,0,NULL,NULL,hInstance,NULL);

        
        
    if (!hMainWnd)
            
    {
                
    return FALSE;
            }

        
        hDlgNow = DoMainDlg(hMainWnd);
        ShowWindow(hDlgNow, nCmdShow);


        
    while(GetMessage(&msg, NULL, 0, 0)) 
        
    {
            
    if (NULL == hDlgNow || !IsDialogMessage(hDlgNow, &msg))
            
    {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }

        
    return msg.wParam;
    }
      首先注冊一個標準的窗口類,WNDCLASS結構體,默認的窗口過程為ODWndProc.其定義如下. LRESULT CALLBACK ODWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        
    return DefWindowProc(hWnd, message, wParam, lParam);//
    返回系統默認的窗口過程
    }
       然后判斷有無相同實例存在如有則結束之 HWND onlywin= FindWindow("OwnerDraw","MyOwnerDraw");

        if (onlywin)
            {
            ExitProcess(1);
            }
      接下來創建主窗口 hMainWnd=CreateWindow("OwnerDraw","MyOwnerDraw",WS_OVERLAPPEDWINDOW,
                    CW_USEDEFAULT,0,CW_USEDEFAULT,0,NULL,NULL,hInstance,NULL);
    需要注意的是我們這里并不調用ShowWindow()和UpdateWindow();因為我們不需要顯示主窗口    hDlgNow = DoMainDlg(hMainWnd);
        ShowWindow(hDlgNow, nCmdShow);
    這里調用DoMainDlg函數創建一個對話框并顯示之. DoMainDlg函數實現如下. HWND DoMainDlg(HWND parent)
    {
        DWORD dwErr;
        HWND hRet = CreateDialog(odInst, (LPCTSTR)IDD_MAIN_DLG, parent, (DLGPROC)MainDlgProc);
        
    if(hRet == NULL)
            dwErr = GetLastError();

        
    return hRet;

    }
      最后為消息循環 while(GetMessage(&msg, NULL, 0, 0)) 
        
    {
            
    if (NULL == hDlgNow || !IsDialogMessage(hDlgNow, &msg))
            
    {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
      其中IsDialogMessage(hDlgNow, &msg)主要作用是把指定對話框的消息,路由給其處理.     下面是對話框窗口的默認消息響應回調函數MainDlgProc 我這里主要講響應WM_DRAWITEM消息與WM_INITDIALOG.. 首先是響應WM_INITDIALOG case WM_INITDIALOG:
                
                
    if(hIcon == NULL)
                    hIcon = LoadIcon(odInst, MAKEINTRESOURCE(IDI_OWNERDRAW));
                
                
    if(hOwnerDrawIcon == NULL)
                    hOwnerDrawIcon = (HICON)LoadImage(odInst, 
                                            MAKEINTRESOURCE(IDI_OWNERDRAW), 
                                            IMAGE_ICON, 
                                            38,
                                            38,
                                            0);
                prev_proc = SetWindowLongPtr(GetDlgItem(hDlg, IDC_ODBUTTON), GWLP_WNDPROC, (LONG)ButtWindProc);
                
                SendMessage(hDlg, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);

                SetFocus(GetDlgItem(hDlg, IDC_ODBUTTON));
                
                
                
    break;
      首先為對話框加載一個圖標,我這里圖省事全部都用了一個圖標,在實際應用中.可以隨需要更換. 然后是為自繪按鈕加載圖標.接下來改變默認的自繪按鈕的窗口過程.將原按鈕過程存與prev_proc. 最后發送WM_SETICON消息設置對話框圖標和設置焦點.   接下來是響應WM_DRAWITEM消息,需要說明的是這個消息必須要設置了BS_OWNERDRAW 我們用記事本打開我們的對話框資源文件會看到類似下面的設置 IDD_MAIN_DLG DIALOG DISCARDABLE  0, 0, 250, 142
    STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
    CAPTION "Dialog"
    FONT 10, "System"
    BEGIN
        DEFPUSHBUTTON   "OK",IDOK,193,7,50,14
        PUSHBUTTON      "Cancel",IDCANCEL,193,24,50,14
        CONTROL         "OwnerDraw",IDC_ODBUTTON,"Button",BS_OWNERDRAW | 
                        WS_TABSTOP,49,31,79,26
    END
      此處資源文件中的BS_OWNERDRAW即對應創建按鈕時選中的Ownerdraw屬性.之所以這樣作是因為只有這樣 對話框才能響應WM_DRAWITEM消息.下面為代碼.    case WM_DRAWITEM:
                
    {
                    LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT) lParam;
                    
    //
    聲明一個指向DRAWITEMSTRUCT結構體的指針并將其指向存儲著按鈕構造信息的lParam

                    
    if(lpDIS->CtlID != IDC_ODBUTTON)
                        
    return (0);
                    
                    HDC dc = lpDIS->hDC; 
    //用于按鈕繪制的DC
                    BOOL bIsPressed  = (lpDIS->itemState & ODS_SELECTED);
                    BOOL bIsFocused  = (lpDIS->itemState & ODS_FOCUS);
                    BOOL bIsDisabled = (lpDIS->itemState & ODS_DISABLED);
                    BOOL bDrawFocusRect = !(lpDIS->itemState & ODS_NOFOCUSRECT);
                    
    //判斷按鈕各種狀態的BOOL
                    RECT itemRect = lpDIS->rcItem; //按鈕的矩形區域
                    
                    SetBkMode(dc, TRANSPARENT); 
    //設置繪制按鈕時的背景狀態
                    if (bIsFocused)  //判斷按鈕是否獲得了焦點并對其邊框進行處理
                    {
                        HBRUSH br = CreateSolidBrush(RGB(0,0,0));  
                        FrameRect(dc, &itemRect, br);
                        InflateRect(&itemRect, -1, -1);
                        DeleteObject(br);
                    } 
    // if        
                    
                    COLORREF crColor = GetSysColor(COLOR_BTNFACE);
    //得到系統按鈕顏色
                    
                    HBRUSH    brBackground = CreateSolidBrush(crColor);
    //創建畫刷
                    
                    FillRect(dc, &itemRect, brBackground);
    //繪制按鈕
                    
                    DeleteObject(brBackground);
                    
                    
    // 這里畫被按下去的按鈕
                    if (bIsPressed)
                    
    {
                        HBRUSH brBtnShadow = CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW));
                        FrameRect(dc, &itemRect, brBtnShadow);
                        DeleteObject(brBtnShadow);
                    }
                    
                    
    else //如果沒有被按下就這樣畫
                    {
                        UINT uState = DFCS_BUTTONPUSH |
                            ((bIsPressed) ? DFCS_PUSHED : 0);
                        
                        DrawFrameControl(dc, &itemRect, DFC_BUTTON, uState);
                    }
                    
                    
    char sTitle[100];
                    GetWindowText(GetDlgItem(hDlg, IDC_ODBUTTON), sTitle, 100);
    //得到按鈕的文本
                    
                    RECT captionRect = lpDIS->rcItem;
    //把文本的區域設置為按鈕區域
                    
                    
                    BOOL bHasTitle = (sTitle[0] !='/0');
    //按鈕上是否有文本存在
                    
    //
    這里畫按鈕上的圖標,具體實現見下面
                     (GetDlgItem(hDlg, IDC_ODBUTTON), &dc, bHasTitle, 
                        &lpDIS->rcItem, &captionRect, bIsPressed, bIsDisabled);
                    
                    
                    
                    
    if (bHasTitle)//如果按鈕有文本標題
                    {
                        
    // 按鈕被按下的處理
                        if (bIsPressed)
                            OffsetRect(&captionRect, 1, 1);
                        
                        
    // 將文本居中
                        RECT centerRect = captionRect;
                        DrawText(dc, sTitle, -1, &captionRect, DT_WORDBREAK | DT_CALCRECT|DT_CENTER);
                        LONG captionRectWidth = captionRect.right - captionRect.left;
                        LONG captionRectHeight = captionRect.bottom - captionRect.top;
                        LONG centerRectWidth = centerRect.right - centerRect.left;
                        LONG centerRectHeight = centerRect.bottom - centerRect.top;
                        OffsetRect(&captionRect, (centerRectWidth - captionRectWidth)/2, (centerRectHeight - captionRectHeight)/2);
                        
                        
                        
                        SetBkMode(dc, TRANSPARENT);
                        
                        
    if (bIsDisabled)//如果按鈕被禁用
                        {
                            OffsetRect(&captionRect, 1, 1);
                            SetTextColor(dc, ::GetSysColor(COLOR_3DHILIGHT));
                            DrawText(dc, sTitle, -1, &captionRect, DT_WORDBREAK | DT_CENTER);
                            OffsetRect(&captionRect, -1, -1);
                            SetTextColor(dc, ::GetSysColor(COLOR_3DSHADOW));
                            DrawText(dc, sTitle, -1, &captionRect, DT_WORDBREAK | DT_CENTER);
                        } 
                        
    else //如果沒被禁用正常畫
                        {
                            SetTextColor(dc, ::GetSysColor(COLOR_BTNTEXT));
                            SetBkColor(dc, ::GetSysColor(COLOR_BTNFACE));
                            DrawText(dc, sTitle, -1, &captionRect, DT_WORDBREAK | DT_CENTER);
                        } 
                        
                    }
                    
                    
    // 畫按鈕得到焦點時的虛線方框
                    if (bIsFocused && bDrawFocusRect)
                    
    {
                        RECT focusRect = itemRect;
                        InflateRect(&focusRect, -3, -3);
                        DrawFocusRect(dc, &focusRect);
                    } 
    // if
                    return (TRUE);
                }
                
    break;
      到此WM_DRAWITEM消息響應完畢.下面我們看看DrawTheIcon這個函數. static void DrawTheIcon(HWND hButtonWnd, HDC* dc, BOOL bHasTitle, RECT* rpItem, RECT* rpTitle, BOOL bIsPressed, BOOL bIsDisabled)
    {
        RECT    rImage;
        PrepareImageRect(hButtonWnd, bHasTitle, rpItem, rpTitle, bIsPressed, 38, 38, &rImage);
        
        
    // 
    調用API函數按準備好的形式將圖片畫到按鈕上
        DrawState(    *dc,
            NULL,
            NULL,
            (LPARAM)hOwnerDrawIcon,
            0,
            rImage.left,
            rImage.top,
            (rImage.right - rImage.left),
            (rImage.bottom - rImage.top), 
            (bIsDisabled ? DSS_DISABLED : DSS_NORMAL) | DST_ICON);
    }
    還有其中的PrepareImageRect函數   static void PrepareImageRect(HWND hButtonWnd, BOOL bHasTitle, RECT* rpItem, RECT* rpTitle, BOOL bIsPressed, DWORD dwWidth, DWORD dwHeight, RECT* rpImage)
    {
        RECT rBtn;
        
        CopyRect(rpImage, rpItem);
        
        
        GetClientRect(hButtonWnd, &rBtn);
        
    if (bHasTitle == FALSE)//
    如果按鈕上有文本內容
        {
            
    // 使圖片水平居中
            LONG rpImageWidth = rpImage->right - rpImage->left;
            rpImage->left += ((rpImageWidth - (
    long)dwWidth)/2);
        }
        
    else
        
    {   //控制圖片與焦點方框內部
            LONG rpTitleWidth = rpTitle->right - rpTitle->left;
            rpTitle->right = rpTitleWidth - dwWidth - 30;
            rpTitle->left = 30;
            rpImage->left = rBtn.right - dwWidth - 22;
            
            LONG rpImageHeight = rpImage->bottom - rpImage->top;
            rpImage->top += ((rpImageHeight - (
    long)dwHeight)/2);
        }
        
    if (bIsPressed)//按鈕被按下的處理
            OffsetRect(rpImage, 1, 1);
        
    }
      行了到這里主要的工作都作完了還要說明的就是ButtWindProc這個按鈕窗口的回調函數.寫它的主要目的是為了 實現按鈕的連續單擊,在此函數中我們處理了WM_LBUTTONDBLCLK鼠標雙擊事件,并將其轉化為一個單擊事件.像這樣: LRESULT CALLBACK ButtWindProc(
                                  HWND hWnd,                            
    //window handle                   
                                  UINT message,                         // type of message                 
                                  WPARAM wParam,                        // additional information          
                                  LPARAM lParam)                        //additional information          
    {
        
    switch (message)
        
    {
        
    case WM_LBUTTONDBLCLK:
            PostMessage(hWnd, WM_LBUTTONDOWN, wParam, lParam);
            
    break;
        
        }
        
    //
    將不做處理的消息路由給原默認函數
        return CallWindowProc((WNDPROC)prev_proc, hWnd, message, wParam, lParam);
        
    }
      下面只需再響應WM_SETICON, WM_SYSCOMMAND, WM_COMMAND.這三個沒什么好說的.前兩個交由系統默認過程處理,最后一個對應對話框上的確定和取消,都是銷毀窗口的行為. case WM_SETICON:
                    DefWindowProc(hDlg, message, wParam, lParam);
                
    break;
        
        
    case WM_SYSCOMMAND:
                    
    {
                        
    return DefWindowProc(hDlg, message, wParam, lParam);
                    }
        
    case WM_COMMAND:
                    
    switch (LOWORD(wParam))
                    
    {
                    
    case IDCANCEL:
                    
    case IDOK:
                        
                        DestroyIcon(hOwnerDrawIcon);
                        
                        PostQuitMessage(0);
                        
    return TRUE;
                    }
    //switch
                    break;
    本文部分內容參考自http://www.codeproject.com/buttonctrl/nativewin32xpthemes.asp 本實例源代碼http://geniusdot.googlepages.com/new.rarRFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全