zoukankan      html  css  js  c++  java
  • [MFC] 手动美化 MFC 窗体

    去除边框

    1.把窗口边框改成无边框:
    在这里插入图片描述

    但只这样做会导致无法拖动窗口。

    2.在类向导中添加这个消息:OnHcHitTest
    在这里插入图片描述

    3.修改这个消息处理函数的返回值为:HTCAPTION
    在这里插入图片描述


    添加背景图片

    1.准备一张 bmp 格式的图片(其他格式我没有实验,可能会有问题),在项目中添加资源,选择 BitMap ,导入:
    在这里插入图片描述

    在这里插入图片描述

    2.在 OnPaint() 函数中添加如下代码:

    // 上面还有一部分代码,是 vs 自动生成的
    else
    	{
    		//CDialogEx::OnPaint();			// 这是原本的,注释掉
    
    		/*
    			从这里开始是我们自己的代码 ---------------
    		*/ 
    		
    		CPaintDC   dc(this);
    		CRect   rect;
    		GetClientRect(&rect);												// 获取对话框长宽      
    		CDC   dcBmp;															// 定义并创建一个内存设备环境
    		dcBmp.CreateCompatibleDC(&dc);						// 创建兼容性DC
    		CBitmap   bmpBackground;
    		bmpBackground.LoadBitmap(IDB_BITMAP1);    // 载入资源中图片
    		BITMAP   m_bitmap;												// 图片变量               
    		bmpBackground.GetBitmap(&m_bitmap);			// 将图片载入位图中
    		
    		//将位图选入临时内存设备环境
    		CBitmap* pbmpOld = dcBmp.SelectObject(&bmpBackground);
    		
    		//调用函数显示图片StretchBlt显示形状可变
    		dc.SetStretchBltMode(COLORONCOLOR);			// 防止 bmp 图片压缩后失真
    		dc.StretchBlt(0, 0, rect.Width(), rect.Height(), &dcBmp, 0, 0, m_bitmap.bmWidth, m_bitmap.bmHeight, SRCCOPY);
    	}
    

    注意:背景图片在窗口拉伸时会失真,但配合无边框使用时不需要在意,因为本身无边框窗体不支持拉伸窗口。


    添加背景颜色

    这个没有添加背景图片好用,但还是记录一下吧。
    1.类向导里添加消息处理函数 : WM_CTLCOLOR
    2.在 xxxDlg.h 的 protected 里添加成员变量:CBrush m_brush;
    3.在 WM_CTLCOLOR 的处理函数 OnCtlColor() 中 ,修改返回值为 m_brush

    HBRUSH Ctestmfc2Dlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
    {
    	HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
    
    	// TODO:  在此更改 DC 的任何特性
    
    
    	// TODO:  如果默认的不是所需画笔,则返回另一个画笔
    	return /*hbr*/m_brush;
    }
    

    4.在 OnInitDialog() 中添加代码,绘制背景颜色:

    m_brush.CreateSolidBrush(RGB(255, 255, 102));
    

    给按钮添加背景图片

    比起 bmp 图片,显然按钮必须要用 png 的透明图片更加好看,但是 MFC 对 png 的支持并不太友好,我找了很久,终于在这篇文章的启发下完成了这个功能:
    https://www.codeproject.com/Articles/26887/A-user-draw-button-that-supports-PNG-files-with-tr

    https://github.com/JustLoveI/GdipButton 这里的代码更新,但是我没有调通,所以我用的时上面连接里的代码。

    以防链接失效,这里记录下具体实现过程,不愿看英文的人也可以直接看我下面写的。

    1.首先需要几个文件
    CGdiPlusBitmap.h

    #pragma once
    
    class CGdiPlusBitmap
    {
    public:
    	Gdiplus::Bitmap* m_pBitmap;
    
    public:
    	CGdiPlusBitmap()							{ m_pBitmap = NULL; }
    	CGdiPlusBitmap(LPCWSTR pFile)				{ m_pBitmap = NULL; Load(pFile); }
    	virtual ~CGdiPlusBitmap()					{ Empty(); }
    
    	void Empty()								{ delete m_pBitmap; m_pBitmap = NULL; }
    
    	bool Load(LPCWSTR pFile)
    	{
    		Empty();
    		m_pBitmap = Gdiplus::Bitmap::FromFile(pFile);
    		return m_pBitmap->GetLastStatus() == Gdiplus::Ok;
    	}
    
    	operator Gdiplus::Bitmap*() const			{ return m_pBitmap; }
    };
    
    
    class CGdiPlusBitmapResource : public CGdiPlusBitmap
    {
    protected:
    	HGLOBAL m_hBuffer;
    
    public:
    	CGdiPlusBitmapResource()					{ m_hBuffer = NULL; }
    	CGdiPlusBitmapResource(LPCTSTR pName, LPCTSTR pType = RT_RCDATA, HMODULE hInst = NULL)
    												{ m_hBuffer = NULL; Load(pName, pType, hInst); }
    	CGdiPlusBitmapResource(UINT id, LPCTSTR pType = RT_RCDATA, HMODULE hInst = NULL)
    												{ m_hBuffer = NULL; Load(id, pType, hInst); }
    	CGdiPlusBitmapResource(UINT id, UINT type, HMODULE hInst = NULL)
    												{ m_hBuffer = NULL; Load(id, type, hInst); }
    	virtual ~CGdiPlusBitmapResource()			{ Empty(); }
    
    	void Empty();
    
    	bool Load(LPCTSTR pName, LPCTSTR pType = RT_RCDATA, HMODULE hInst = NULL);
    	bool Load(UINT id, LPCTSTR pType = RT_RCDATA, HMODULE hInst = NULL)
    												{ return Load(MAKEINTRESOURCE(id), pType, hInst); }
    	bool Load(UINT id, UINT type, HMODULE hInst = NULL)
    												{ return Load(MAKEINTRESOURCE(id), MAKEINTRESOURCE(type), hInst); }
    };
    
    inline
    void CGdiPlusBitmapResource::Empty()
    {
    	CGdiPlusBitmap::Empty();
    	if (m_hBuffer)
    	{
    		::GlobalUnlock(m_hBuffer);
    		::GlobalFree(m_hBuffer);
    		m_hBuffer = NULL;
    	} 
    }
    
    inline
    bool CGdiPlusBitmapResource::Load(LPCTSTR pName, LPCTSTR pType, HMODULE hInst)
    {
    	Empty();
    
    	HRSRC hResource = ::FindResource(hInst, pName, pType);
    	if (!hResource)
    		return false;
    	
    	DWORD imageSize = ::SizeofResource(hInst, hResource);
    	if (!imageSize)
    		return false;
    
    	const void* pResourceData = ::LockResource(::LoadResource(hInst, hResource));
    	if (!pResourceData)
    		return false;
    
    	m_hBuffer  = ::GlobalAlloc(GMEM_MOVEABLE, imageSize);
    	if (m_hBuffer)
    	{
    		void* pBuffer = ::GlobalLock(m_hBuffer);
    		if (pBuffer)
    		{
    			CopyMemory(pBuffer, pResourceData, imageSize);
    
    			IStream* pStream = NULL;
    			if (::CreateStreamOnHGlobal(m_hBuffer, FALSE, &pStream) == S_OK)
    			{
    				m_pBitmap = Gdiplus::Bitmap::FromStream(pStream);
    				pStream->Release();
    				if (m_pBitmap)
    				{ 
    					if (m_pBitmap->GetLastStatus() == Gdiplus::Ok)
    						return true;
    
    					delete m_pBitmap;
    					m_pBitmap = NULL;
    				}
    			}
    			::GlobalUnlock(m_hBuffer);
    		}
    		::GlobalFree(m_hBuffer);
    		m_hBuffer = NULL;
    	}
    	return false;
    }
    
    
    

    GdipButton.h

    //
    // GdipButton.h : Version 1.0 - see article at CodeProject.com
    //
    // Author:  Darren Sessions
    //          
    //
    // Description:
    //     GdipButton is a CButton derived control that uses GDI+ 
    //     to support alternate image formats
    //
    // History
    //     Version 1.0 - 2008 June 10
    //     - Initial public release
    //
    // License:
    //     This software is released under the Code Project Open License (CPOL),
    //     which may be found here:  http://www.codeproject.com/info/eula.aspx
    //     You are free to use this software in any way you like, except that you 
    //     may not sell this source code.
    //
    //     This software is provided "as is" with no expressed or implied warranty.
    //     I accept no liability for any damage or loss of business that this 
    //     software may cause.
    //
    ///
    
    #pragma once
    
    // GdipButton.h : header file
    //
    
    class CGdiPlusBitmapResource;
    /
    // CGdipButton window
    
    class CGdipButton : public CButton
    {
    public:
    
    	CGdipButton();
    	virtual ~CGdipButton();
    
    	// image types
    	enum	{
    				STD_TYPE	= 0,
    				ALT_TYPE,
    				DIS_TYPE
    			};
    
    	// sets the image type
    	void SetImage(int type);
    
    	BOOL LoadAltImage(UINT id, LPCTSTR pType);
    	BOOL LoadStdImage(UINT id, LPCTSTR pType);
    
    	// if false, disables the press state and uses grayscale image if it exists
    	void EnableButton(BOOL bEnable = TRUE) { m_bIsDisabled = !bEnable; }
    
    	// in toggle mode each press toggles between std and alt images
    	void EnableToggle(BOOL bEnable = TRUE);
    
    	// return the enable/disable state
    	BOOL IsDisabled(void) {return (m_bIsDisabled == TRUE); }
    
    	void SetBkGnd(CDC* pDC);
    
    	void SetToolTipText(CString spText, BOOL bActivate = TRUE);
    	void SetToolTipText(UINT nId, BOOL bActivate = TRUE);
    	void SetHorizontal(bool ImagesAreLaidOutHorizontally = FALSE);
    	void DeleteToolTip();
    
    
    protected:
    
    	void PaintBk(CDC* pDC);
    	void PaintBtn(CDC* pDC);
    
    	BOOL	m_bHaveAltImage;
    	BOOL	m_bHaveBitmaps;
    
    	BOOL	m_bIsDisabled;
    	BOOL	m_bIsToggle;
    	BOOL	m_bIsHovering;
    	BOOL	m_bIsTracking;
    
    	int		m_nCurType;
    
    	CGdiPlusBitmapResource* m_pAltImage;
    	CGdiPlusBitmapResource* m_pStdImage;
    
    	CString			m_tooltext;
    	CToolTipCtrl*	m_pToolTip;
    	
    	void	InitToolTip();
    
    	virtual void PreSubclassWindow();
    	virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/);
    	virtual BOOL PreTranslateMessage(MSG* pMsg);
    
    	//{{AFX_MSG(CGdipButton)
    	afx_msg HBRUSH CtlColor(CDC* pDC, UINT nCtlColor);
    	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
    	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
    	afx_msg LRESULT OnMouseLeave(WPARAM wparam, LPARAM lparam);
    	afx_msg LRESULT OnMouseHover(WPARAM wparam, LPARAM lparam) ;
    	//}}AFX_MSG
    
    	DECLARE_MESSAGE_MAP()
    
    private:
    
    	CDC		m_dcBk;			// button background
    	
    	CDC		m_dcStd;		// standard button
    	CDC		m_dcStdP;		// standard button pressed
    	CDC		m_dcStdH;		// standard button hot
    
    	CDC		m_dcAlt;		// alternate button
    	CDC		m_dcAltP;		// alternate button pressed
    	CDC		m_dcAltH;		// alternate button hot
    
    	CDC		m_dcGS;			// grayscale button (does not have a hot or pressed state)
    
    	CDC*	m_pCurBtn;		// current pointer to one of the above
    
    };
    
    

    MemDC.h

    //
    // CMemDC - memory DC
    //
    // Author: Keith Rule, keithr@europa.com,  Copyright 1996-1997, Keith Rule
    //
    // You may freely use or modify this code provided this copyright is included in all derived versions.
    //
    // History - 10/3/97 Fixed scrolling bug.
    //                   Added print support.
    //				 - 14/7/99 Added optional clip rect parameter [jgh]
    //
    //				 - 06/06/08  Added option to copy screen on construction
    //
    #if !defined(AFX_CaMemDC_H__F666A491_3847_11D3_A58E_00805FC1DE10__INCLUDED_)
    #define AFX_CaMemDC_H__F666A491_3847_11D3_A58E_00805FC1DE10__INCLUDED_
    
    	class CaMemDC : public CDC {			// 高版本的 vs 这里 CMemDC 会报重定义错误,我这里改成了 CaMemDC
    	private:
    		CBitmap m_bitmap; // Offscreen bitmap
    		CBitmap* m_oldBitmap; // bitmap originally found in CMemDC
    		CDC* m_pDC; // Saves CDC passed in constructor
    		CRect m_rect; // Rectangle of drawing area.
    		BOOL m_bMemDC; // TRUE if CDC really is a Memory DC.
    	public:
    		/// Function Header
    		CaMemDC(CDC* pDC, CRect rect = CRect(0,0,0,0), BOOL bCopyFirst = FALSE) : CDC(), m_oldBitmap(NULL), m_pDC(pDC)
    		//
    		{
    			ASSERT(m_pDC != NULL); // If you asserted here, you passed in a NULL CDC.
    			
    			m_bMemDC = !pDC->IsPrinting();
    			
    			if (m_bMemDC){
    				// Create a Memory DC
    				CreateCompatibleDC(pDC);
    				if ( rect == CRect(0,0,0,0) )
    					pDC->GetClipBox(&m_rect);
    				else
    					m_rect = rect;
    
    				m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height());
    				m_oldBitmap = SelectObject(&m_bitmap);
    				SetWindowOrg(m_rect.left, m_rect.top);
    				if(bCopyFirst)
    				{
    					this->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
    							m_pDC, m_rect.left, m_rect.top, SRCCOPY);
    				}
    			} else {
    				// Make a copy of the relevent parts of the current DC for printing
    				m_bPrinting = pDC->m_bPrinting;
    				m_hDC = pDC->m_hDC;
    				m_hAttribDC = pDC->m_hAttribDC;
    			}
    		}
    		
    		/// Function Header
    		~CaMemDC()
    		//
    		{
    			if (m_bMemDC) {
    				// Copy the offscreen bitmap onto the screen.
    				m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
    					this, m_rect.left, m_rect.top, SRCCOPY);
    				//Swap back the original bitmap.
    				SelectObject(m_oldBitmap);
    			} else {
    				// All we need to do is replace the DC with an illegal value,
    				// this keeps us from accidently deleting the handles associated with
    				// the CDC that was passed to the constructor.
    				m_hDC = m_hAttribDC = NULL;
    			}
    		}
    		
    		// Allow usage as a pointer
    		CaMemDC* operator->() {return this;}
    		
    		// Allow usage as a pointer
    		operator CaMemDC*() {return this;}
    	};
    
    #endif
    // End CMemDC
    //
    
    
    
    

    GdipButton.cpp

    //
    // GdipButton.cpp : Version 1.0 - see article at CodeProject.com
    //
    // Author:  Darren Sessions
    //          
    //
    // Description:
    //     GdipButton is a CButton derived control that uses GDI+ 
    //     to support alternate image formats
    //
    // History
    //     Version 1.0 - 2008 June 10
    //     - Initial public release
    //
    // License:
    //     This software is released under the Code Project Open License (CPOL),
    //     which may be found here:  http://www.codeproject.com/info/eula.aspx
    //     You are free to use this software in any way you like, except that you 
    //     may not sell this source code.
    //
    //     This software is provided "as is" with no expressed or implied warranty.
    //     I accept no liability for any damage or loss of business that this 
    //     software may cause.
    //
    ///
    
    #include "pch.h"		//  低版本的 vs 使用 stdafx.h
    #include "GdipButton.h"
    
    #include "CGdiPlusBitmap.h"
    #include "MemDC.h"
    
    
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    
    /
    // CGdipButton
    
    CGdipButton::CGdipButton()
    {
    	m_pStdImage = NULL;
    	m_pAltImage = NULL;
    
    	m_bHaveBitmaps = FALSE;
    	m_bHaveAltImage = FALSE;
    
    	m_pCurBtn = NULL;
    
    	m_bIsDisabled = FALSE;
    	m_bIsToggle = FALSE;
    
    	m_bIsHovering = FALSE;
    	m_bIsTracking = FALSE;
    
    	m_nCurType = STD_TYPE;
    
    	m_pToolTip = NULL;
    
    }
    
    CGdipButton::~CGdipButton()
    {
    	if(m_pStdImage) delete m_pStdImage;
    	if(m_pAltImage) delete m_pAltImage;
    
    	if(m_pToolTip)	delete m_pToolTip;
    }
    
    
    BEGIN_MESSAGE_MAP(CGdipButton, CButton)
    	//{{AFX_MSG_MAP(CGdipButton)
    	ON_WM_DRAWITEM()
    	ON_WM_ERASEBKGND()
    	ON_WM_CTLCOLOR_REFLECT()
    	ON_WM_MOUSEMOVE()
    	ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
    	ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover)
    	//}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    
    
    
    //=============================================================================
    //
    // LoadStdImage()
    //
    // Purpose:     The LoadStdImage() Loads the image for the button.  This 
    //				function must be called at a minimum or the button wont do 
    //				anything.
    //
    // Parameters:  
    //		[IN]	id
    //				resource id, one of the resources already imported with the 
    //				resource editor, usually begins with IDR_  
    //
    //		[IN]	pType
    //				pointer to string describing the resource type
    //				
    // Returns:     BOOL
    //				Non zero if successful, otherwise zero
    //
    //=============================================================================
    BOOL CGdipButton::LoadStdImage(UINT id, LPCTSTR pType)
    {
    	m_pStdImage = new CGdiPlusBitmapResource;
    	return m_pStdImage->Load(id, pType);
    }
    
    //=============================================================================
    //
    // LoadAltImage()
    //
    // Purpose:     The LoadAltImage() Loads the altername image for the button.  
    //				This function call is optional
    // Parameters:  
    //		[IN]	id
    //				resource id, one of the resources already imported with the 
    //				resource editor, usually begins with IDR_  
    //
    //		[IN]	pType
    //				pointer to string describing the resource type
    //				
    // Returns:     BOOL
    //				Non zero if successful, otherwise zero
    //
    //=============================================================================
    BOOL CGdipButton::LoadAltImage(UINT id, LPCTSTR pType)
    {
    	m_bHaveAltImage = TRUE;
    	m_pAltImage = new CGdiPlusBitmapResource;
    	return (m_pAltImage->Load(id, pType));
    }
    
    
    //=============================================================================
    //
    //	The framework calls this member function when a child control is about to 
    //	be drawn.  All the bitmaps are created here on the first call. Every thing
    //	is done with a memory DC except the background, which get's it's information 
    //	from the parent. The background is needed for transparent portions of PNG 
    //	images. An always on top app (such as Task Manager) that is in the way can 
    //	cause it to get an incorrect background.  To avoid this, the parent should 
    //	call the SetBkGnd function with a memory DC when it creates the background.
    //				
    //=============================================================================
    HBRUSH CGdipButton::CtlColor(CDC* pScreenDC, UINT nCtlColor) 
    {
    	if(!m_bHaveBitmaps)
    	{
    		if(!m_pStdImage)
    		{
    			return NULL; // Load the standard image with LoadStdImage()
    		}
    
    		CBitmap bmp, *pOldBitmap;
    
    		CRect rect;
    		GetClientRect(rect);
    
    		// do everything with mem dc
    		CaMemDC pDC(pScreenDC, rect);
    
    		Gdiplus::Graphics graphics(pDC->m_hDC);
    
    		// background
    		if (m_dcBk.m_hDC == NULL)
    		{
    
    			CRect rect1;
    			CClientDC clDC(GetParent());
    			GetWindowRect(rect1);
    			GetParent()->ScreenToClient(rect1);
    
    			m_dcBk.CreateCompatibleDC(&clDC);
    			bmp.CreateCompatibleBitmap(&clDC, rect.Width(), rect.Height());
    			pOldBitmap = m_dcBk.SelectObject(&bmp);
    			m_dcBk.BitBlt(0, 0, rect.Width(), rect.Height(), &clDC, rect1.left, rect1.top, SRCCOPY);
    			bmp.DeleteObject();
    		}
    
    		// standard image
    		if (m_dcStd.m_hDC == NULL)
    		{
    			PaintBk(pDC);
    
    			graphics.DrawImage(*m_pStdImage, 0, 0);
    		
    			m_dcStd.CreateCompatibleDC(pDC);
    			bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
    			pOldBitmap = m_dcStd.SelectObject(&bmp);
    			m_dcStd.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, 0, 0, SRCCOPY);
    			bmp.DeleteObject();
    
    			// standard image pressed
    			if (m_dcStdP.m_hDC == NULL)
    			{
    				PaintBk(pDC);
    
    				graphics.DrawImage(*m_pStdImage, 1, 1);
    
    				m_dcStdP.CreateCompatibleDC(pDC);
    				bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
    				pOldBitmap = m_dcStdP.SelectObject(&bmp);
    				m_dcStdP.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, 0, 0, SRCCOPY);
    				bmp.DeleteObject();
    			}
    
    			// standard image hot
    			if(m_dcStdH.m_hDC == NULL)
    			{
    				PaintBk(pDC);
    
    				ColorMatrix HotMat = {	1.05f, 0.00f, 0.00f, 0.00f, 0.00f,
    										0.00f, 1.05f, 0.00f, 0.00f, 0.00f,
    										0.00f, 0.00f, 1.05f, 0.00f, 0.00f,
    										0.00f, 0.00f, 0.00f, 1.00f, 0.00f,
    										0.05f, 0.05f, 0.05f, 0.00f, 1.00f	};
    
    				ImageAttributes ia;
    				ia.SetColorMatrix(&HotMat);
    
    				float width = (float)m_pStdImage->m_pBitmap->GetWidth();
    				float height = (float)m_pStdImage->m_pBitmap->GetHeight();
    
    				RectF grect; grect.X=0, grect.Y=0; grect.Width = width; grect.Height = height;
    
    				graphics.DrawImage(*m_pStdImage, grect, 0, 0, width, height, UnitPixel, &ia);
    
    				m_dcStdH.CreateCompatibleDC(pDC);
    				bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
    				pOldBitmap = m_dcStdH.SelectObject(&bmp);
    				m_dcStdH.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, 0, 0, SRCCOPY);
    				bmp.DeleteObject();
    			}
    
    			// grayscale image
    			if(m_dcGS.m_hDC == NULL)
    			{
    				PaintBk(pDC);
    
    				ColorMatrix GrayMat = {	0.30f, 0.30f, 0.30f, 0.00f, 0.00f,
    										0.59f, 0.59f, 0.59f, 0.00f, 0.00f,
    										0.11f, 0.11f, 0.11f, 0.00f, 0.00f,
    										0.00f, 0.00f, 0.00f, 1.00f, 0.00f,
    										0.00f, 0.00f, 0.00f, 0.00f, 1.00f	};
    
    				ImageAttributes ia;
    				ia.SetColorMatrix(&GrayMat);
    
    				float width = (float)m_pStdImage->m_pBitmap->GetWidth();
    				float height = (float)m_pStdImage->m_pBitmap->GetHeight();
    
    				RectF grect; grect.X=0, grect.Y=0; grect.Width = width; grect.Height = height;
    
    				graphics.DrawImage(*m_pStdImage, grect, 0, 0, width, height, UnitPixel, &ia);
    
    				m_dcGS.CreateCompatibleDC(pDC);
    				bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
    				pOldBitmap = m_dcGS.SelectObject(&bmp);
    				m_dcGS.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, 0, 0, SRCCOPY);
    				bmp.DeleteObject();
    			}
    		}
    
    		// alternate image
    		if( (m_dcAlt.m_hDC == NULL) && m_bHaveAltImage )
    		{
    			PaintBk(pDC);
    
    			graphics.DrawImage(*m_pAltImage, 0, 0);
    		
    			m_dcAlt.CreateCompatibleDC(pDC);
    			bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
    			pOldBitmap = m_dcAlt.SelectObject(&bmp);
    			m_dcAlt.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, 0, 0, SRCCOPY);
    			bmp.DeleteObject();
    
    			// alternate image pressed
    			if( (m_dcAltP.m_hDC == NULL) && m_bHaveAltImage )
    			{
    				PaintBk(pDC);
    
    				graphics.DrawImage(*m_pAltImage, 1, 1);
    			
    				m_dcAltP.CreateCompatibleDC(pDC);
    				bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
    				pOldBitmap = m_dcAltP.SelectObject(&bmp);
    				m_dcAltP.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, 0, 0, SRCCOPY);
    				bmp.DeleteObject();
    			}
    
    			// alternate image hot
    			if(m_dcAltH.m_hDC == NULL)
    			{
    				PaintBk(pDC);
    
    				ColorMatrix HotMat = {	1.05f, 0.00f, 0.00f, 0.00f, 0.00f,
    										0.00f, 1.05f, 0.00f, 0.00f, 0.00f,
    										0.00f, 0.00f, 1.05f, 0.00f, 0.00f,
    										0.00f, 0.00f, 0.00f, 1.00f, 0.00f,
    										0.05f, 0.05f, 0.05f, 0.00f, 1.00f	};
    
    				ImageAttributes ia;
    				ia.SetColorMatrix(&HotMat);
    
    				float width = (float)m_pStdImage->m_pBitmap->GetWidth();
    				float height = (float)m_pStdImage->m_pBitmap->GetHeight();
    
    				RectF grect; grect.X=0, grect.Y=0; grect.Width = width; grect.Height = height;
    
    				graphics.DrawImage(*m_pAltImage, grect, 0, 0, width, height, UnitPixel, &ia);
    
    				m_dcAltH.CreateCompatibleDC(pDC);
    				bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
    				pOldBitmap = m_dcAltH.SelectObject(&bmp);
    				m_dcAltH.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, 0, 0, SRCCOPY);
    				bmp.DeleteObject();
    			}
    		}
    
    		if(m_pCurBtn == NULL)
    		{
    			m_pCurBtn = &m_dcStd;
    		}
    
    		m_bHaveBitmaps = TRUE;
    	}
    
    	return NULL;
    }
    
    //=============================================================================
    // paint the background
    //=============================================================================
    void CGdipButton::PaintBk(CDC *pDC)
    {
    	CRect rect;
    	GetClientRect(rect);
    	pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &m_dcBk, 0, 0, SRCCOPY);
    }
    
    //=============================================================================
    // paint the bitmap currently pointed to with m_pCurBtn
    //=============================================================================
    void CGdipButton::PaintBtn(CDC *pDC)
    {
    	CRect rect;
    	GetClientRect(rect);
    	pDC->BitBlt(0, 0, rect.Width(), rect.Height(), m_pCurBtn, 0, 0, SRCCOPY);
    }
    
    //=============================================================================
    // enables the toggle mode
    // returns if it doesn't have the alternate image
    //=============================================================================
    void CGdipButton::EnableToggle(BOOL bEnable)
    {
    	if(!m_bHaveAltImage) return;
    
    	m_bIsToggle = bEnable; 
    
    	// this actually makes it start in the std state since toggle is called before paint
    	if(bEnable)	m_pCurBtn = &m_dcAlt;
    	else		m_pCurBtn = &m_dcStd;
    
    }
    
    //=============================================================================
    // sets the image type and disabled state then repaints
    //=============================================================================
    void CGdipButton::SetImage(int type)
    {
    	m_nCurType = type;
    
    	(type == DIS_TYPE) ? m_bIsDisabled = TRUE : m_bIsDisabled = FALSE;
    
    	Invalidate();
    }
    
    //=============================================================================
    // set the control to owner draw
    //=============================================================================
    void CGdipButton::PreSubclassWindow()
    {
    	// Set control to owner draw
    	ModifyStyle(0, BS_OWNERDRAW, SWP_FRAMECHANGED);
    
    	CButton::PreSubclassWindow();
    }
    
    //=============================================================================
    // disable double click 
    //=============================================================================
    BOOL CGdipButton::PreTranslateMessage(MSG* pMsg) 
    {
    	if (pMsg->message == WM_LBUTTONDBLCLK)
    		pMsg->message = WM_LBUTTONDOWN;
    
    	if (m_pToolTip != NULL)
    	{
    		if (::IsWindow(m_pToolTip->m_hWnd))
    		{
    			m_pToolTip->RelayEvent(pMsg);		
    		}
    	}
    
    	return CButton::PreTranslateMessage(pMsg);
    }
    
    
    //=============================================================================
    // overide the erase function
    //=============================================================================
    BOOL CGdipButton::OnEraseBkgnd(CDC* pDC) 
    {
    	return TRUE;
    }
    
    //=============================================================================
    // Paint the button depending on the state of the mouse
    //=============================================================================
    void CGdipButton::DrawItem(LPDRAWITEMSTRUCT lpDIS) 
    {
    	CDC* pDC = CDC::FromHandle(lpDIS->hDC);
    
    	// handle disabled state
    	if(m_bIsDisabled)
    	{
    		m_pCurBtn = &m_dcGS;
    		PaintBtn(pDC);
    		return;
    	}
    
    	BOOL bIsPressed = (lpDIS->itemState & ODS_SELECTED);
    
    	// handle toggle button
    	if(m_bIsToggle && bIsPressed)
    	{
    		(m_nCurType == STD_TYPE) ? m_nCurType = ALT_TYPE : m_nCurType = STD_TYPE;
    	}
    
    	if(bIsPressed)
    	{
    		if(m_nCurType == STD_TYPE)
    			m_pCurBtn = &m_dcStdP;
    		else
    			m_pCurBtn = &m_dcAltP;
    	}
    	else if(m_bIsHovering)
    	{
    
    		if(m_nCurType == STD_TYPE)
    			m_pCurBtn = &m_dcStdH;
    		else
    			m_pCurBtn = &m_dcAltH;
    	}
    	else
    	{
    		if(m_nCurType == STD_TYPE)
    			m_pCurBtn = &m_dcStd;
    		else
    			m_pCurBtn = &m_dcAlt;
    	}
    
    	// paint the button
    	PaintBtn(pDC);
    }
    
    //=============================================================================
    LRESULT CGdipButton::OnMouseHover(WPARAM wparam, LPARAM lparam) 
    //=============================================================================
    {
    	m_bIsHovering = TRUE;
    	Invalidate();
    	DeleteToolTip();
    
    	// Create a new Tooltip with new Button Size and Location
    	SetToolTipText(m_tooltext);
    
    	if (m_pToolTip != NULL)
    	{
    		if (::IsWindow(m_pToolTip->m_hWnd))
    		{
    			//Display ToolTip
    			m_pToolTip->Update();
    		}
    	}
    
    	return 0;
    }
    
    
    //=============================================================================
    LRESULT CGdipButton::OnMouseLeave(WPARAM wparam, LPARAM lparam)
    //=============================================================================
    {
    	m_bIsTracking = FALSE;
    	m_bIsHovering = FALSE;
    	Invalidate();
    	return 0;
    }
    
    //=============================================================================
    void CGdipButton::OnMouseMove(UINT nFlags, CPoint point) 
    //=============================================================================
    {
    	if (!m_bIsTracking)
    	{
    		TRACKMOUSEEVENT tme;
    		tme.cbSize = sizeof(tme);
    		tme.hwndTrack = m_hWnd;
    		tme.dwFlags = TME_LEAVE|TME_HOVER;
    		tme.dwHoverTime = 1;
    		m_bIsTracking = _TrackMouseEvent(&tme);
    	}
    	
    	CButton::OnMouseMove(nFlags, point);
    }
    
    //=============================================================================
    //	
    //	Call this member function with a memory DC from the code that paints 
    //	the parents background.  Passing the screen DC defeats the purpose of 
    //  using this function.
    //
    //=============================================================================
    void CGdipButton::SetBkGnd(CDC* pDC)
    {
    	CRect rect, rectS;
    	CBitmap bmp, *pOldBitmap;
    
    	GetClientRect(rect);
    	GetWindowRect(rectS);
    	GetParent()->ScreenToClient(rectS);
    
    	m_dcBk.DeleteDC();
    
    	m_dcBk.CreateCompatibleDC(pDC);
    	bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
    	pOldBitmap = m_dcBk.SelectObject(&bmp);
    	m_dcBk.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, rectS.left, rectS.top, SRCCOPY);
    	bmp.DeleteObject();
    }
    
    
    //=============================================================================
    // Set the tooltip with a string resource
    //=============================================================================
    void CGdipButton::SetToolTipText(UINT nId, BOOL bActivate)
    {
    	// load string resource
    	m_tooltext.LoadString(nId);
    
    	// If string resource is not empty
    	if (m_tooltext.IsEmpty() == FALSE)
    	{
    		SetToolTipText(m_tooltext, bActivate);
    	}
    
    }
    
    //=============================================================================
    // Set the tooltip with a CString
    //=============================================================================
    void CGdipButton::SetToolTipText(CString spText, BOOL bActivate)
    {
    	// We cannot accept NULL pointer
    	if (spText.IsEmpty()) return;
    
    	// Initialize ToolTip
    	InitToolTip();
    	m_tooltext = spText;
    
    	// If there is no tooltip defined then add it
    	if (m_pToolTip->GetToolCount() == 0)
    	{
    		CRect rectBtn; 
    		GetClientRect(rectBtn);
    		m_pToolTip->AddTool(this, m_tooltext, rectBtn, 1);
    	}
    
    	// Set text for tooltip
    	m_pToolTip->UpdateTipText(m_tooltext, this, 1);
    	m_pToolTip->SetDelayTime(2000);
    	m_pToolTip->Activate(bActivate);
    }
    
    //=============================================================================
    void CGdipButton::InitToolTip()
    //=============================================================================
    {
    	if (m_pToolTip == NULL)
    	{
    		m_pToolTip = new CToolTipCtrl;
    		// Create ToolTip control
    		m_pToolTip->Create(this);
    		m_pToolTip->Activate(TRUE);
    	}
    } 
    
    //=============================================================================
    void CGdipButton::DeleteToolTip()
    //=============================================================================
    {
    	// Destroy Tooltip incase the size of the button has changed.
    	if (m_pToolTip != NULL)
    	{
    		delete m_pToolTip;
    		m_pToolTip = NULL;
    	}
    }
    
    
    2.在 pch.h (或者是 stdafx.h)里添加上对 GDI+ 的引用:
    
    ```cpp
    #include <gdiplus.h>
    #pragma comment(lib, "gdiplus.lib")
    using namespace Gdiplus;
    

    3.在 InitInstance() 函数的 CWinApp::InitInstance(); 之前中启用 GDI+:

    // ....
    
    
    GdiplusStartup(&GdiToken, &gdiplusstartupinput, NULL);					// 激活 GDI (应该在程序退出时应该调用 GdiplusShutdown 关闭)
    
    CWinApp::InitInstance();	// 要在这一句上面,否则会导致以后窗口不能自动重绘、不能使用字体等一系列问题。
    // .....
    
    

    4.关闭 GDI+ :
    应该在 ExitInstance() 里处理 ,但是我没有找到这个函数,可能是高版本里被废除掉了,所以我尝试用 OnDestroy 来代替它完成清理工作,但这么做会触发一个异常。

    GdiplusShutdown(GdiToken);
    

    关于 GDI+ 的内容,参考自:https://wenku.baidu.com/view/c662b31514791711cc791776.html

    5.在 OnInitDialog() 函数里添加如下代码(m_cPlay 是你按钮的变量名,IDR_PLAY 是你的 png 资源名)

    m_cPlay.LoadStdImage(IDR_PLAY, _T("PNG"));
    

    效果图:
    在这里插入图片描述


    修改普通按钮风格

    1 . 为按钮添加一个成员变量,类型为 CMFCButton
    关于 CMFCButton 的定义,参考 :
    https://docs.microsoft.com/zh-cn/cpp/mfc/reference/cmfcbutton-class?view=msvc-160

    2 . 在 OnInitDialog() 函数里添加按钮的属性:

    btn_1.SetWindowTextW(_T("LYSM"));						// 设置文本内容
    btn_1.SetTextColor(RGB(255, 255, 255));				// 设置文本颜色
    btn_1.SetTextHotColor(RGB(0, 0, 0));						// 设置文本被点击时的颜色
    btn_1.SetMouseCursorHand();									// 鼠标经过时变成手指
    btn_1.m_bTransparent = FALSE;								// 按钮透明
    btn_1.SetFaceColor(RGB(100, 0, 0));				// 更改背景颜色  
    btn_1.m_bDontUseWinXPTheme = TRUE;				// 使用 XP 风格,否则颜色不显示
    btn_1.m_bDrawFocus = FALSE;									// 去除周围黑框
    

    2 . 类向导里添加一个时钟事件,相应鼠标悬停逻辑:

    void Ctestmfc1Dlg::OnTimer(UINT_PTR nIDEvent)
    {
    	// TODO: 在此添加消息处理程序代码和/或调用默认值
    	if (1 == nIDEvent)
    	{
    		POINT p;
    		GetCursorPos(&p);
    		CWnd* hwndMouse  = WindowFromPoint(p);      
    		CWnd* hwndBtn1 = GetDlgItem(IDC_BUTTON1);
    		if (hwndMouse == hwndBtn1)
    		{
    			
    			btn_1.SetFaceColor(RGB(0, 100, 0));			// 鼠标悬停改变按钮颜色
    		}
    		else
    		{
    			btn_1.SetFaceColor(RGB(100, 0, 0));			// 否则使用默认颜色
    		}
    	}
    
    
    	CDialogEx::OnTimer(nIDEvent);
    }
    

    最后不要忘了在 OnInitDialog() 里初始化时钟:

    SetTimer(1, 100, NULL);
    

    效果图:
    在这里插入图片描述


    取消 ESC、ENTER 后程序退出

    mfc 对话框程序,按以上两个键会退出程序,所以需要处理一下。

    1 . 类向导里添加虚函数 : PreTranslateMessage

    2 . 添加如下代码,接管按键事件:

    BOOL Ctestmfc1Dlg::PreTranslateMessage(MSG* pMsg)
    {
    	// TODO: 在此添加专用代码和/或调用基类
    	if (pMsg->message == WM_KEYDOWN)
    	{
    		switch (pMsg->wParam)
    		{
    			case VK_RETURN :		// 屏蔽回车
    				return TRUE;
    			case VK_ESCAPE :			// 屏蔽 Esc
    				return TRUE;
    		}
    	}
    
    
    	return CDialogEx::PreTranslateMessage(pMsg);
    }
    
    

    edit control 修改字体大小

    1 .OnInitDialog() 里,添加如下代码:

    CFont my_Font;
    my_Font.CreatePointFont(300, L"Arial");		// 300 :字体大小 ,Arial : 字体样式
    edit_1.SetFont(&my_Font);					// edit_1 :edit control 控件变量
    

  • 相关阅读:
    企业如何在智能制造的时代保持竞争力?
    汽车行业MES系统在产品追溯方面的应用分析
    你能想象未来的MES系统是什么样吗?
    智能制造进入下半场?APS如何进行优化
    【案例】如何让阀门制造提高排产效率?APS系统帮你实现
    APS系统的现状以及与MES系统的关联
    MES被重新定义?做到这几点才算智能制造
    python部分笔记
    BUUCTF Hack World
    BUUCTF--checkin
  • 原文地址:https://www.cnblogs.com/csnd/p/15613325.html
Copyright © 2011-2022 走看看