[MFC] 手动美化 MFC 窗体

您所在的位置:网站首页 mfc风格直播 [MFC] 手动美化 MFC 窗体

[MFC] 手动美化 MFC 窗体

2024-03-13 14:15| 来源: 网络整理| 查看: 265

去除边框

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, [email protected], 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 #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 控件变量


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3