窗口自绘

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了窗口自绘相关的知识,希望对你有一定的参考价值。

1. 派生CWnd类

  class CTreePropertySheetEx : public CWnd

2. 注册窗口类 

  LPCTSTR AFXAPI AfxRegisterWndClass(
  UINT nClassStyle,
  HCURSOR hCursor = 0,
  HBRUSH hbrBackground = 0,
  HICON hIcon = 0
  );
  窗口将会设置以下的默认值
  *设置鼠标格式为CS_DBLLCKS,设置该属性意味着当在窗口上双击的时候窗口处理函数将会受到双击消息
  *设置鼠标的光标形式为Windows的标准的IDC_ARROW
  *设置窗口的背景为NULL,也就是指该窗口不会擦除它的背景
  *设置窗口的ICON为Windows标准的waving_flag的ICON
  hCursor:指定句柄在每个窗口上安装光标资源创建从窗口类。 如果使用 0默认值,您将收到标准 IDC_ARROW 光标。
  hbrBackground:指定句柄在每个窗口上安装画笔资源创建从窗口类。 如果使用 0默认值,您将具有一个 NULL 背景画        
  笔,并且,如果您的窗口中,默认情况下,在处理WM_ERASEBKGND时,不会清除其背景。
  hIcon:指定句柄在每个窗口上安装图标资源创建从窗口类。 如果使用 0默认值,您将收到该条件,挥动标志 windows   
  徽标图标。
  // 注册窗口
   LPCTSTR lpszClass = AfxRegisterWndClass(CS_OWNDC);
3. 创建窗口
  CreateEx
4. 消息循环
  RunModalLoop或Run
5. 响应WM_CREATE消息,创建窗口内容
6. 实现OnEraseBkgnd消息,绘制背景
7. 响应WM_SIZE消息
8. 响应WM_OK或WM_CANCEL消息EndModalLoop或EndLoop
 
TreePropertySheetEx.h
技术分享图片
/*
* 自绘树控件属性页 
*/
#pragma once

#define IDC_TREE 1000
class CMyMemDC;
class CTreePropertySheetEx : public CWnd
{
    DECLARE_DYNAMIC(CTreePropertySheetEx)

public:
    CTreePropertySheetEx();
    CTreePropertySheetEx(UINT nBitmap);
    CTreePropertySheetEx(PCSTR szFile);
    virtual ~CTreePropertySheetEx();

    void DoModal(CWnd* pParent); // 创建模态对话框

protected:
    DECLARE_MESSAGE_MAP()
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    afx_msg BOOL OnEraseBkgnd(CDC* pDC);
    void DrawBackground(CDC* pDC, CRect& rcItem);
private:
    CWnd* m_pParentWnd;
    CTreeCtrl    m_TreeCtrl;
    CMyMemDC    *m_pBackgroundBmpDC;
    afx_msg void OnSize(UINT nType, int cx, int cy);
    afx_msg void OnClose();
    afx_msg void OnOk();
};

class CMyMemDC : public CDC
{
public:
    CMyMemDC(int nWidth,int nHeight,CDC *pDC=NULL)
    {
        Create(nWidth,nHeight,pDC);
    }
    CMyMemDC(UINT nBitmap, CDC* pDC=NULL)
    {
        LoadBitmap(nBitmap,pDC);
    }
    CMyMemDC(PCSTR szFile, CDC* pDC = NULL)
    {
        LoadBitmap(szFile,pDC);
    }
    ~CMyMemDC()
    {
        DeleteDC();
    }

    BOOL DeleteDC()
    {
        if (!GetSafeHdc())
            return FALSE;
        CBitmap* pBitmap = GetCurrentBitmap();
        if (pBitmap)
            pBitmap->DeleteObject();

        return CDC::DeleteDC();
    }
    int GetWidth(){return m_size.cx;}
    int GetHeight(){return m_size.cy;}
    // 创建空白位图
    BOOL Create(int nWidth, int nHeight, CDC* pDC = NULL)
    {
        CBitmap bitmap;
        CreateCompatibleDC(pDC);
        if (!bitmap.CreateCompatibleBitmap(pDC, nWidth, nHeight))
            return FALSE;
        SelectObject(&bitmap);
        return TRUE;
    }
    // 进程内位图资源加载
    BOOL LoadBitmap(UINT nBitmap, CDC* pDC=NULL)
    {
        CBitmap bmp;
        if (!bmp.LoadBitmap(nBitmap))
            return FALSE;
        BITMAP bm;
        bmp.GetBitmap(&bm);
        m_size.cx = bm.bmWidth;
        m_size.cy = bm.bmHeight;
        CreateCompatibleDC(pDC);
        SelectObject(&bmp);
        return TRUE;
    }
    // 进程外位图文件加载
    BOOL LoadBitmap(LPCSTR szFile, CDC* pDC = NULL)
    {
        HBITMAP hBitmap = (HBITMAP)LoadImage(NULL, szFile,       
                IMAGE_BITMAP, 0,0,LR_LOADFROMFILE);
        if (!hBitmap)
            return FALSE;
        // 获取GDI资源的详细信息方法一
        /*CBitmap bitmap = CBitmap::FromHandle(hBitmap);
        BITMAP bm;
        bitmap.GetBitmap(&bm);*/
        // 获取GDI资源的详细信息方法一
        BITMAP bm;
        GetObject(hBitmap, sizeof(BITMAP), &bm);
        m_size.cx = bm.bmWidth;
        m_size.cy = bm.bmHeight;
        CreateCompatibleDC(pDC);
        SelectObject(hBitmap);
        return TRUE;
    }

public:
    CSize m_size;   // 图片大小
};

             
View Code

TreePropertySheetEx.cpp

技术分享图片
/*
*    @TreePropertySheet设计
    1.窗口的注册和创建
    2.背景设置
    3.添加ok和cancel按钮,并添加响应事件
    4.实现系列控件的添加
*/

// TreePropertySheetEx.cpp : 实现文件
//

#include "stdafx.h"
#include "mfcctrlstu.h"
#include "TreePropertySheetEx.h"
#include "btnST.h"


// CTreePropertySheetEx

IMPLEMENT_DYNAMIC(CTreePropertySheetEx, CWnd)

CTreePropertySheetEx::CTreePropertySheetEx()
{
    m_pParentWnd = NULL;
    m_pBackgroundBmpDC = NULL;
}

CTreePropertySheetEx::CTreePropertySheetEx( UINT nBitmap )
{
    CDC *pDC = (CDC *)GetDesktopWindow()->GetDC();
    m_pBackgroundBmpDC = new CMyMemDC(nBitmap, pDC);
}

CTreePropertySheetEx::CTreePropertySheetEx( PCSTR szFile )
{
    CDC *pDC = (CDC *)GetDesktopWindow()->GetDC();
    m_pBackgroundBmpDC = new CMyMemDC(szFile, pDC);
}

CTreePropertySheetEx::~CTreePropertySheetEx()
{
}


BEGIN_MESSAGE_MAP(CTreePropertySheetEx, CWnd)
    ON_WM_CREATE()
    ON_WM_ERASEBKGND()
    ON_WM_SIZE()
    ON_WM_CLOSE()
    ON_BN_CLICKED(IDOK, OnOk)
END_MESSAGE_MAP()

void CTreePropertySheetEx::DoModal(CWnd* pParent)
{
    // 得到父窗口句柄
    HWND hWndTop;
    CWnd *pParentWnd = GetSafeOwner(pParent, &hWndTop);
    
    // 让父窗口enable,子窗口modal
    BOOL bEnableParent = FALSE;
    if (pParentWnd!=NULL && pParentWnd->IsWindowEnabled())
    {
        pParentWnd->EnableWindow(FALSE);
        bEnableParent = TRUE;
    }
    HWND hWndCapture = ::GetCapture();
    if (hWndCapture != NULL)
        ::SendMessage(hWndCapture, WM_CANCELMODE, 0, 0);            // ReleaseCapture

    // 注册窗口
    LPCTSTR lpszClass = AfxRegisterWndClass(CS_OWNDC);
    
    UINT nStyle = WS_POPUP|WS_CLIPCHILDREN|WS_BORDER|WS_CAPTION;

    CreateEx(NULL,
        lpszClass,
        "Tree property sheet",
        nStyle,
        200,200,
        800,500,
        pParentWnd->GetSafeHwnd(),
        NULL,NULL);

    int nRetValue=RunModalLoop(MLF_SHOWONIDLE);

    if (m_hWnd != NULL)
    {
        SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW|
            SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
    }
    
    if (bEnableParent)
        pParentWnd->EnableWindow(TRUE);
    if (pParentWnd != NULL && ::GetActiveWindow() == m_hWnd)
        pParentWnd->SetActiveWindow();

    // 销毁窗口
    DestroyWindow();
}

// 创建窗口
int CTreePropertySheetEx::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CWnd::OnCreate(lpCreateStruct) == -1)
        return -1;

    // 创建OK和CANCEL按钮
    CButton *pOkBtn = new CButton();
    pOkBtn->Create(_T("OK"), WS_CHILD|WS_TABSTOP,CRect(0,0,60,20), this, IDOK);
    pOkBtn->ShowWindow(SW_SHOW);

    CButton *pCancelBtn = new CButton();
    pCancelBtn->Create(_T("Cancel"), WS_CHILD|WS_TABSTOP,CRect(0,0,60,20), this, IDCANCEL);
    
    pCancelBtn->MoveWindow(70,0,60,20);
    pCancelBtn->ShowWindow(SW_SHOW);
    // 创建TreeCtrl
    //m_TreeCtrl.CreateEx(WS_EX_CLIENTEDGE, TVS_HASLINES|TVS_FULLROWSELECT|TVS_LINESATROOT|TVS_HASBUTTONS|WS_CHILD|WS_VISIBLE|WS_TABSTOP,
    //    CRect(0,0,0,0), this, IDC_TREE);

    //// 设置树控件
    //HTREEITEM hTreeItem = m_TreeCtrl.InsertItem("根",TVI_ROOT);
    
    return 0;
}

BOOL CTreePropertySheetEx::OnEraseBkgnd(CDC* pDC)
{
    CRect rcClient;
    GetClientRect(&rcClient);
    DrawBackground(pDC,rcClient);

    return TRUE;//return CWnd::OnEraseBkgnd(pDC);
}

void CTreePropertySheetEx::DrawBackground(CDC* pDC, CRect& rcItem)
{
    if(m_pBackgroundBmpDC!=NULL) 
    {
        pDC->SetStretchBltMode(COLORONCOLOR);
        pDC->StretchBlt(0,0,rcItem.Width(),rcItem.Height(),
            m_pBackgroundBmpDC,0,0,m_pBackgroundBmpDC->m_size.cx,m_pBackgroundBmpDC->m_size.cy,SRCCOPY);
    }    else
    {
        pDC->FillSolidRect(rcItem,GetSysColor(COLOR_3DFACE));
    }
}

void CTreePropertySheetEx::OnSize(UINT nType, int cx, int cy)
{
    CWnd::OnSize(nType, cx, cy);

    Invalidate(FALSE);
}

void CTreePropertySheetEx::OnClose()
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    EnableWindow(FALSE);
    EndModalLoop(IDCANCEL);
}

void CTreePropertySheetEx::OnOk()
{
    EnableWindow(FALSE);
    EndModalLoop(IDCANCEL);
}
View Code

 

 

以上是关于窗口自绘的主要内容,如果未能解决你的问题,请参考以下文章

QT自绘标题和边框

自绘LISTVIEW的滚动条(Delphi实现)

控件的自绘

WinApi:如何为屏幕阅读器的自绘按钮添加替代文本?

易语言GDI自绘中怎么实现这个效果~!!

VC如果得到其他程序窗口的控件句柄