65.9K
CodeProject 正在变化。 阅读更多。
Home

CRoundButton2 - 一个花哨的图形按钮

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.84/5 (53投票s)

2005 年 9 月 19 日

CPOL

9分钟阅读

viewsIcon

541590

downloadIcon

19449

一个自绘制的圆形按钮,支持不同样式和用法。

引言

我需要一个用于可换肤用户界面的按钮,用户可以更改其视觉效果。我的第一个想法是使用位图来换肤按钮,但这对于我的界面来说有点不方便,所以我寻找一个可以通过内部公式和用户给定参数来绘制自身的按钮。长话短说,我没有找到适合我需求的类,所以我开始编写代码。

我的第一次尝试是一场灾难 ;-)。一个使用大约15个按钮的应用程序在10秒内启动,因为按钮需要时间来绘制。第二次尝试就好多了。时间关键的图形以通用方式绘制一次,然后由按钮用于绘制自己的图像。通过这种结构,还可以为整个项目生成一个全局按钮样式。

介绍使用的类和结构

CRoundButton2 需要两个类:"CRoundButton2" 和 "CRoundButtonStyle"。每个按钮需要一个 "CRoundButton2" 类型的对象。这个类代表按钮及其功能。只需要一个 "CRoundButtonStyle" 类型的对象(好吧,好吧,每个使用的按钮样式一个)。这个对象控制所有使用它的按钮的样式。让我们从它开始...

CRoundButtonStyle

CRoundButtonStyle 有一些公共函数,但除了构造函数和析构函数之外,我们感兴趣的是:

  • GetButtonStyle(tButtonStyle* _ptButtonStyle)

    用于用当前设置的样式填充 tButtonStyle 结构。

  • SetButtonStyle(tButtonStyle* _ptButtonStyle)

    用于将当前样式设置为 tButtonStyle 结构中给定的样式。

这两个函数都需要一个指向 tButtonStyle 类型对象的指针。

tButtonStyle

tButtonStyle 是一个结构,包含样式中所有可更改的选项。该图像显示了按钮样式的主要参数

按钮的几何形状由所示函数计算。

参数详细说明如下:

  • double m_dSizeAA

    用于使图像平滑的抗锯齿区域的像素大小。

  • double m_dRadius

    按钮边缘的半径。如果按钮对于选定的半径来说太小,它将被缩小,但请注意,缩放例程不是很好。如果你必须将非常小的按钮与大的按钮一起使用,请使用第二个按钮比例,该比例仅在此参数上有所不同。

  • double m_dBorderRatio

    边框与半径之间的比率(介于0.0和1.0之间)。如果给定半径为16.0,并且 m_dBorderRatio 为0.25,则按钮的边框宽度为4.0像素。

  • double m_dHeightBorder

    边框的颜色通过函数 y=x^2 计算,高度为这个值。你需要稍微尝试一下才能找到适合你的按钮的好值。

  • double m_dHeightButton

    按钮的颜色通过函数 y=x^2 计算,高度为这个值。你需要稍微尝试一下才能找到适合你的按钮的好值。

  • double m_dHighLightX

    按钮高光在X方向上的位置。使用这个值和下一个值来改变3D效果。

  • double m_dHighLightY

    按钮高光在X方向上的位置。使用这个值和上一个值来改变3D效果。

  • double m_dRadiusHighLight

    使用的高光的半径。你需要稍微尝试一下才能找到一个好看的值。

  • double m_dPowerHighLight

    使用的高光的强度。这个值越大,高亮区域就越接近白色 ;-)

  • tColorScheme m_tColorBack

    这是按钮的背景色。因为按钮不会自绘透明,所以你可以在这里给出对话框的颜色,这样按钮看起来是圆形的而不是矩形的。

  • tColorScheme m_tColorBorder

    这是按钮边框最高点显示的颜色。

  • tColorScheme m_tColorFace

    这是按钮表面,即按钮中间区域显示的颜色。

tColorScheme

按钮的着色由这个结构完成,它包含了按钮所有不同状态的颜色。

详细介绍如下:

  • COLORREF m_tDisabled

    当按钮被禁用时使用的颜色。

  • COLORREF m_tEnabled

    当按钮启用但未被点击时使用的颜色。

  • COLORREF m_tClicked

    当按钮被点击时使用的颜色。如果按钮是复选框,则表示选中;如果按钮是单选按钮,则表示选中。

  • COLORREF m_tPressed

    当按钮被按下时使用的颜色。这意味着鼠标悬停在按钮上并点击了鼠标左键。

  • COLORREF m_tHot

    当按钮是热点按钮且鼠标指针悬停在按钮上时使用的颜色。

因此,每个按钮都使用一个类对象...

CRoundButton2

此类别包含一些用于控制按钮行为的 SetGet 例程。这些例程详细介绍如下:

  • bool SetRoundButtonStyle(CRoundButtonStyle* _ptRoundButtonStyle)

    此例程将按钮对象中的指针设置为全局按钮样式对象。通过它,您可以控制哪个按钮使用哪个按钮样式。

  • bool GetFont(LOGFONT* _ptLogFont)

    您需要提供一个 LOGFONT 类型对象的地址,该对象将由函数填充实际设置的字体数据。LOGFONT 是MFC的 CreateFontIndirect 使用的结构。

  • bool SetFont(LOGFONT* _ptLogFont)

    您需要提供一个 LOGFONT 类型对象的地址,该对象将由函数用于设置按钮的实际字体。LOGFONT 是MFC的 CreateFontIndirect 使用的结构。

  • bool GetTextColor(tColorScheme* _ptTextColor)

    此例程用按钮文本的当前设置颜色填充 _ptTextColor 处的对象。此颜色以 tColorScheme 形式给出,因此您可以为禁用的按钮使用不同的颜色,或者通过其他字体颜色标记已选中的按钮。

  • bool GetTextColor(tColorScheme* _ptTextColor)

    此例程将按钮的字体颜色设置为 _pttextColor 中给定的值。此颜色以 tColorScheme 形式给出,因此您可以为禁用的按钮使用不同的颜色,或者通过其他字体颜色标记已选中的按钮。

  • void SetCheckButton(bool _bCheckButton)

    将按钮状态更改为复选按钮或返回。如果 _bCheckbuttontrue,则按钮为复选按钮。每次鼠标点击都会更改选中状态。

  • bool GetCheckButton()

    如果按钮是复选按钮,则返回 true,否则返回 false

  • void SetRadioButton(bool _bRadioButton)

    将按钮的状态更改为单选按钮或返回。如果 _bRadiobuttontrue,则按钮为单选按钮。每次鼠标点击都会选中一个单选按钮。组中其他单选按钮的取消选中必须手动完成(目前)。(稍后将看到一个示例。)

  • bool GetRadioButton()

    如果按钮是单选按钮,则返回 true,否则返回 false

  • void SetHotButton(bool _bHotButton)

    将按钮状态更改为热点按钮或返回。如果 _bRadiobuttontrue,则按钮为热点按钮。如果鼠标悬停在按钮面上,按钮将改变其外观为热点按钮样式,以便更引人注目。

  • bool GetHotButton()

    如果按钮是热点按钮,则返回 true,否则返回 false

  • void SetCheck(bool _bIsChecked)

    选中或取消选中按钮。

  • bool GetCheck()

    获取按钮的实际选中状态。true 表示按钮已选中。

使用代码

首先,您需要在项目中包含这四个文件:

  • RoundButton2.h
  • RoundButton2.cpp
  • RoundButtonStyle.h
  • RoundButtonStyle.cpp

使用代码最简单的方法是为每个使用的按钮生成变量。第一步是:转到对话框的头文件并包含

.
.
.
#include "..."

#include "RoundButton2.h"
#include "RoundButtonStyle.h"

class CMyDialog : public CDialog
{
.
.
.

下一步是进入对话框编辑器。首先我们需要一个要使用的按钮样式。右键单击对话框标题并选择“添加变量...”。在对话框中,将变量类型更改为“CRoundButtonStyle”并给变量命名。此示例使用 m_tMyButtonStyle。按下“确定”,您的第一个全局按钮样式就生成了。

现在,我们需要为每个使用的按钮提供一个变量。要获取它们,请为每个按钮遵循以下步骤:

右键单击您要更改的按钮,然后选择“添加变量...”。在弹出的对话框中,选择您的变量名(此示例使用 m_tMyButton1 等),并将变量类型更改为 CRoundButton2。按“确定”,按钮的变量就包含进去了。

最后一个必要的步骤是将样式与按钮关联起来。转到对话框的 OnInitDialog() 例程,并为每个按钮设置以下行:

BOOL CMyDialog::OnInitDialog()
{
    .
    .
    .
    All other initialization
    
    m_tMyButton1.SetRoundButtonStyle(&m_tMyButtonStyle);
    m_tMyButton2.SetRoundButtonStyle(&m_tMyButtonStyle);
    m_tMyButton3.SetRoundButtonStyle(&m_tMyButtonStyle);
    m_tMyButton4.SetRoundButtonStyle(&m_tMyButtonStyle);
    m_tMyButton5.SetRoundButtonStyle(&m_tMyButtonStyle);
    
    return TRUE
}

现在您可以像使用MFC中的任何其他按钮一样使用您的按钮了。

复选框

如果您想将按钮用作复选框,只需调用...

BOOL CMyDialog::OnInitDialog()
{
    .
    .
    .
    All other initialization
    
    m_tMyButton1.SetCheckButton(true);

    return TRUE
}

...在你的 OnInitDialog() 例程中。按钮每次点击都会改变选中状态,或者你可以通过调用 void SetCheck(bool) 自行改变状态。你可以通过调用 bool GetCheck() 获取当前的选中状态。

单选按钮

单选按钮的实现稍微复杂一些。让我们假设,在这个例子中,你想将“MyButton2”到“MyButton4”用作一个单选按钮组。首先,你必须使用以下代码将按钮的状态设置为“单选按钮”:

BOOL CMyDialog::OnInitDialog()
{
    .
    .
    .
    All other initialization
    
    m_tMyButton2.SetRadioButton(true);
    m_tMyButton3.SetRadioButton(true);
    m_tMyButton4.SetRadioButton(true);

    return TRUE
}

每次用户点击单选按钮时,它都会被“选中”。您必须自己取消选中单选按钮组中未选中的按钮。为此,请为单选按钮组中的每个按钮实现 OnBnClicked() 函数。这些函数包含以下代码:

void CMyDialog::OnBnClickedMyButton2()
{
    // Uncheck the two other Buttons
    m_tMyButton3.SetCheck(false);
    m_tMyButton4.SetCheck(false);
}

void CMyDialog::OnBnClickedMyButton3()
{
    // Uncheck the two other Buttons
    m_tMyButton2.SetCheck(false);
    m_tMyButton4.SetCheck(false);
}

void CMyDialog::OnBnClickedMyButton4()
{
    // Uncheck the two other Buttons
    m_tMyButton2.SetCheck(false);
    m_tMyButton3.SetCheck(false);
}

这将取消选中您的单选按钮组中所有未被点击的按钮。

热点按钮

要使按钮成为热点,您必须调用...

BOOL CMyDialog::OnInitDialog()
{
    .
    .
    .
    All other initialization
    
    m_tMyButton5.SetHotButton(true);

    return TRUE
}

...在你的 OnInitDialog() 例程中。如果鼠标光标悬停在按钮上,热点按钮将改变其外观。

按钮的重新设计

您在重新设计中有两个可能的部分。第一个是...

ButtonStyle

要重新设计按钮的样式,您必须遵循这个简单的概念:

// Generate local struct-object for style-data
tButtonStyle tStyle;

// Get the current style of your button-style-object
m_tMyButtonStyle.GetRoundButtonStyle(&tStyle);

// Do your changes here. As example lets change the radius 
// of the button and the color of the checked button face:
tStyle.m_dRadius = 16.0;
tStyle.m_tColorFace.m_tChecked = RGB(0xFF, 0xFF, 0);

// Save the style back
m_tMyButtonStyle.SetRoundButtonStyle(&tStyle);

现在,你已经更改了按钮样式,所以所有使用此样式的按钮都将拥有更改后的外观。

第二个要更改的样式是...

FontStyle

FontStyleCRoundButton2 类的一部分,因为更改按钮字体比更改其图形细节更常见。例如,考虑一个带有符号的按钮,就像演示应用程序中的高而细的按钮。它使用“WingDings”的双箭头。这个例子展示了同时更改按钮标题的字体和字体颜色。

// Generate local font object
LOGFONT tFont;

// Get the current font of your button-object
m_tMyButton1.GetFont(&tFont);

// Do your changes here. As example lets change the 
// font to "WingDings" and the font-size to 14:
strcpy(tFont.lfFaceName,"WingDings");
tFont.lfHeight = 14;

// Save the Font back
m_tMyButton1.SetFont(&tStyle);

// Generate local ColorSheme object
tColorScheme tColor;

// Get current Color of Caption
m_tMyButton1.GetFontColor(&tColor);

// Do your changes here. As example lets change the 
// captions' color of a checked button to yellow:
tColor.m_tChecked = RGB(0xFF, 0xFF, 0);

// Set Color of Caption
m_tMyButton1.SetFontColor(&tColor);

历史

  • 2005年9月12日 - 首次发布。
  • 2005年9月29日 - 添加了 HotButton 功能(感谢 AndrewSmirnov)并修复了两个错误(感谢 Thomas KayserBhalvinder)。
© . All rights reserved.