翻译来源:https://www.codeproject.com/Articles/26887/A-user-draw-button-that-supports-PNG-files-with-tr
作者:Darren Sessions
介绍
这个网站上有几个自绘按钮,但是我找不到一个容易支持PNG文件透明度的按钮,所以我创建了这个类。由于这个类使用GDI +,它实际上支持许多图像格式,但是现在更好的质量按钮现在是PNG而不是ICO,所以这里就是一个。
更新:我的样式工具包(译者:这篇文章有翻译,请点击)中有这个类的扩展版本。如果你想要的是使用按钮上的图像,这个类可能更简单的使用。
背景
GDI +是Microsoft Windows SDK的一部分,需要在应用程序启动时进行初始化。如果您以前没有使用GDI +,请查看演示项目的源代码并阅读本文:
特征
- 灰度图像
- 该类将自动从加载的资源创建一个灰度图像。当按钮设置为禁用状态时,将显示灰度图像。
- 突出显示图像
- 该类将自动从加载的资源创建一个突出显示的图像。当鼠标悬停在按钮边界上时,显示突出显示的图像。
- 替代图像
- 您可以选择添加备用图像。当通过功能调用设置时,或者单击按钮并启用切换模式时,将显示备用图像。
- 切换模式
- 启用时,按钮会在标准图像和备用图像每次按下之间切换。
- 按钮状态
- 当按下按钮时,图像向下移动1像素。
- 工具提示
- 可以选择添加工具提示。
页面顶部的图像显示三种不同状态的播放按钮。从左到右,它们是:正常,突出显示和禁用。另外两个按钮就是更酷的例子。
从图片可能不太明显,第二个按钮处于突出显示状态。这是按设计,我不想大幅改变形象。高亮状态只是增加了亮度和对比度。当您将鼠标移动到其上时,显然是足够的。这个类别优先考虑图像质量,所以它永远不会拉伸或缩小通常降低质量的图像,它将只是绘制适合的部分。如果您需要调整图像大小,请使用Photoshop等图像编辑器。
下图显示了切换状态下的播放按钮,应该很明显,为什么会想要这样的功能。退出按钮处于突出显示状态,工具提示显示在此图像中。
使用GDI +仅在初始化期间被使用,所以没有性能损失。在创建时,图像将转换为位图,并且在需要使用位图时重新绘制控件。
使用代码
步骤1 - 将这些文件添加到您的项目
- GdipButton.h
- GdipButton.cpp
- MemDC.h(译)
- CGdiPlusBitmap.h(译)
- CMemDC来自Keith Rule,CGdiPlusBitmap.h来自Joe Woodbury。这些包含在源代码和演示包中。
步骤2 - 添加资源,成员变量和图像
使用资源编辑器在对话框中添加一个按钮,设置资源ID,然后在Caption框中删除文本。您可以将样式设置为Owner Draw,但不需要,因为代码将自动设置此样式。
使用类向导,添加一个变量到您刚刚创建的ID。在此示例中,我将ID设置为IDC_PLAY
,并将变量名称设置为m_cPlay
。编辑对话框的.h文件,并将控件更改CButton
为CGdiButton
。不要忘记包含文件“ GdipButton.h ”。
在资源编辑器中,从res文件夹导入.png文件,并将资源类型设置为PNG。使用PNG只是惯例,只要代码与命名相同,它就可以是任何东西。右键单击IDR_PNG1,选择属性,并将其重命名为有用的东西,IDR_PNG1
IDR_PLAY
在此示例中。
步骤3 - 添加LoadStdImage()函数
现在,我们只需要在初始化时将图像加载到按钮。在该OnInitDialg()
功能中,在底部附近添加以下代码:
BOOL CTestGdipButtonDlg::OnInitDialog() { CDialog::OnInitDialog(); /// a bunch of stuff here m_cPlay.LoadStdImage(IDR_PLAY, _T("PNG")); return TRUE; }
步骤4 - 构建和运行
您现在应该能够运行它,并看到您的新的PNG按钮!如果它在这里崩溃,可能是因为你没有初始化GDI +。查看本文的背景部分。
演示项目
这是在测试程序中创建按钮所需的所有代码:
// load the standard image and alternate image m_cPlay.LoadStdImage(IDR_PLAY, _T("PNG")); m_cPlay.LoadAltImage(IDR_PAUSE, _T("PNG")); m_cPlay.EnableToggle(TRUE); // just to show highlight state for article m_cPlayHi.LoadStdImage(IDR_PLAY, _T("PNG")); // set as disabled m_cPlayDis.LoadStdImage(IDR_PLAY, _T("PNG")); m_cPlayDis.EnableButton(FALSE); // show a larger button type m_cGear.LoadStdImage(IDR_GEAR, _T("PNG")); // replace the OK button with something m_cShutDn.LoadStdImage(IDR_EXIT, _T("PNG")); m_cShutDn.SetToolTipText(_T("Close Program"));//(译者:这里应该是m_cShutDn.SetToolTipText(_T("Close Program"),TRUE);)
VC6和VS2005版本都包含在演示项目中。
透明图像问题
按钮控件不知道它下面的背景应该是什么; 它从与当前DC相关联的位图获取此信息。在大多数情况下,这样做很好,背景是控制画面之前的屏幕。但是,应用程序在启动时可能不是最多的。总是在顶级应用程序,如任务管理器可能会阻碍,所以当它获取背景图像,这是错误的数据。通过SetBkGnd()
实际创建背景的代码调用函数来克服这个问题。
设置父项OnEraseBkgnd()
功能中的所有按钮背景。演示程序使用以下代码:
BOOL CTestGdipButtonDlg::OnEraseBkgnd(CDC* pDC) { CDialog::OnEraseBkgnd(pDC); CRect rect; GetClientRect(rect); CMemDC pDevC(pDC, rect); // fill in the back ground with something 译者:请注意,在demo中,这里有一段if (m_hBitmap) { pDevC->SelectObject(m_hBitmap); }没有的话对话框背景是黑色的 SetButtonBackGrounds(pDevC); return TRUE; } void CTestGdipButtonDlg::SetButtonBackGrounds(CDC *pDC) { m_cPlay.SetBkGnd(pDC); m_cPlayHi.SetBkGnd(pDC); m_cPlayDis.SetBkGnd(pDC); m_cShutDn.SetBkGnd(pDC); }
由于传递的DC是一个内存DC,所以其他应用程序可能正在做的事情并不重要。上面的代码假设你想要使用除了默认背景之外的东西; 否则,您可能只需使用默认的crummy按钮。
VC6构建问题
VC6需要一些额外的东西才能正确编译,将以下内容添加到stdafx.h文件中。还要将SDK include和lib路径添加到您的环境中。
// VC6 #if defined(_MSC_VER) && _MSC_VER == 1200 #ifndef ULONG_PTR #define ULONG_PTR unsigned long* #endif #include <span class="code-keyword"><Specstrings.h></span> #include <span class="code-keyword"><gdiplus.h></span> #pragma comment(lib, "gdiplus.lib") using namespace Gdiplus; // VS2005 #else #include <span class="code-keyword"><gdiplus.h></span> #pragma comment(lib, "gdiplus.lib") using namespace Gdiplus; #endif
评论和讨论(译者:摘抄重要的)
1.
在void CGdipButton :: DrawItem(LPDRAWITEMSTRUCT lpDIS){
滚动到底部并添加

// paint the button
PaintBtn(pDC);
#if 1
//add by lyj
CString m_DisplayText;
CRect rect;
CFont font;
font.CreateFont(
20, // nHeight
0, // nWidth
0, // nEscapement
0, // nOrientation
FW_BOLD, // nWeight FW_NORMAL
FALSE, // bItalic
FALSE, // bUnderline
0, // cStrikeOut
ANSI_CHARSET, // nCharSet
OUT_DEFAULT_PRECIS, // nOutPrecision
CLIP_DEFAULT_PRECIS, // nClipPrecision
DEFAULT_QUALITY, // nQuality
DEFAULT_PITCH | FF_SWISS,
_T("Arial") // nPitchAndFamily Arial
);
pDC->SelectObject(&font);
pDC->SetBkMode(TRANSPARENT);
GetClientRect(rect);
//rect.left += 10;
//pDC->SetTextColor(RGB(255,0,0));
GetWindowText(m_DisplayText);
if (m_DisplayText.IsEmpty() == false)
pDC->DrawText(m_DisplayText, rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
#endif
前>
但是,当按下鼠标,文字似乎不那么好;P