LedButton状态控制(Owner-draw)

Sample Image

表的内容

  • 动机
  • 环境使用
  • 将LED按钮文件和资源添加到项目中
  • 一个简单的LED按钮
  • 一个多状态LED按钮
  • 活动LED按钮
  • A条件LED按钮
  • 文本属性
  • 工具提示
  • 代码文档
  • 提供文件
  • 免责声明
  • 使用条款
  • 更新日志

动机

写这个CLedButton控件的动机是有一个LED控件,即:

  • 只读了控制。
  • 能够处理传统的两国关系之外的问题。
  • 能够发出“活动”信号(在可控超时后自动关闭)。
  • 能够控制从一种状态到另一种状态的转换。(从一种状态到另一种状态的转换由外部控制。)
  • 使用从资源文件加载的LED图标。
  • 无闪烁的控制。

两年前,我在CodeProject和SourceForge中寻找一个可以满足我的五个需求的静态控件或按钮控件,但是我没有找到,所以我决定自己构建一个。

我从这个伟大的网站上展示的以下控件中获得了灵感:

  • 第一个候选是Benjamin Mayrargue[^]发布的CLedButton[^],它给了我使用复选框(CBbutton作为基类)作为控件的想法。
  • 然后我看到了VGirish的动态LED控制,但也缺少一些我想要的功能。
  • 保罗·梅西纳(Paolo Messina)的COddButton给了我使用自画按钮的想法。
  • 然后Davide Calabro[^]在他的神奇的CButtonST[^]中为我提供了实现LED按钮控制所需的其余背景。

有了这个背景,两年前我开始定制我自己的CLedButton控件。从一个项目到另一个项目,代码得到了增强和简化,直到它变得成熟和健壮,可以在这里发布。

环境使用

LED按钮最初是用VC 6.0 (Visual Studio c++ 6.0)开发的,现在我用的是VC 7.1 (Visual Studio c++ . net 2003)。我将“尝试”提供适用于这两个版本的说明。

将LED按钮文件和资源添加到项目中

确保你有以下文件:

  • 此控件的来源:LedButton.h和LedButton。cpp,将它们复制到项目目录中。
  • 您想要使用的LED图标文件。(你可以使用我提供的演示中的那些。)将它们复制到项目资源目录(res子目录)。

在您的开发环境中打开您的项目,并遵循以下步骤:

  • 将LedButton.h和LedButton.cpp文件添加到项目中。
  • 使用资源编辑器,在对话框中添加一个复选框,将其ID更改为IDC_LED_CHECK。你也可以改变这个复选框的属性,相关的属性是:左文本,多行,水平对齐,垂直对齐,右对齐文本。
  • 使用资源编辑器导入图标文件,将id分别命名为IDI_GRAY_ICON、IDI_GREEN_ICON、IDI_YELLOW_ICON、IDI_RED_ICON和IDI_BLUE_ICON。
  • 使用ClassWizard添加名为m_ledCtrl的成员变量作为控制变量。(生成的类型为CButton,稍后会更改)。
  • 在对话框头文件中将LED按钮控件的类型从CButton更改为CLedButton。
  • 添加预处理器#include“LedButton”。h"的头文件,以及。

对话头文件应该包含:

...
#include "LedButton.h"
...
class DemoDlg : public CDialog
{
   ...
private:
   ...
   CLedButton m_ledCtrl;
};

对话框实现文件应该包含:

void CDemoDlg::DoDataExchange(CDataExchange* pDX)
{
   ...
   DDX_Control(pDX, IDC_LED_CHECK, m_ledCtrl);
   ...
}

现在是初始化和配置LED按钮的时候了。

一个简单的LED按钮

默认情况下,创建的CLedButton控件有两个LedStates,你只需要设置图标,每个状态一个,然后根据你的需要设置LedState。

为了方便起见,可以定义用于描述每种状态的枚举类型。关闭状态的整数值为0,打开状态的值为1,或使用Afx FALSE和TRUE #定义,或使用LED按钮自己预定义的值LED_BUTTON_STATE_OFF或LED_BUTTON_STATE_ON。

在InitDialog()方法中添加以下代码:

...
m_ledCtrl.SetIcons(IDI_GRAY_ICON, IDI_YELLOW_ICON);
...

LED按钮的默认状态是LED_BUTTON_STATE_OFF。

如果你想改变图标的默认大小,你不能使用SetIcons(),相反,调用SetIcon()方法为每个LED状态:

...
m_ledCtrl.SetIcon(LED_BUTTON_STATE_OFF, IDI_GRAY_ICON, 14,14);
m_ledCtrl.SetIcon(LED_BUTTON_STATE_ON, IDI_YELLOW_ICON, 14,14);
...

每次您想要改变LED的颜色时,只需调用SetLedState()方法来显示新的LED状态。

...
// Turn the Led ON
m_ledCtrl.SetLedState(LED_BUTTON_STATE_ON);
...

如果你不想要一个更复杂的LED按钮,这就是全部。

如果在与LED当前显示的LED状态相同的情况下调用该方法,则SetLedState()不会执行任何操作。(这样做是为了减少闪烁)

一个多状态LED按钮

多状态LED按钮就像一个简单的LED,但有两个以上的LED状态。

定义一个枚举类型来表示每个LED状态可能是符合逻辑的,尽管这不是强制性的。

在本文档中,让我们定义一个名为EMyLedState的枚举类型,用于多状态LED按钮,如下所示:

...
enum EMyLedState {
    GRAY_LED_STATE = LED_BUTTON_STATE_ON,     // Initial LedState
    GREEN_LED_STATE,
    YELLOW_LED_STATE,
    RED_LED_STATE,
    BLUE_LED_STATE,

    MY_LED_STATES_SENTINEL    // Not to be used as a EMyLedState.
};
...

MY_LED_STATES_SENTINEL是我们将使用的LED状态的数量。

多状态LED按钮的初始化要求在为每个状态设置图标之前,调用SetLedStatesNumber()方法来设置LED状态的最大数量。

InitDialog()中的代码变成:

...
m_ledCtrl.SetLedStatesNumber(MY_LED_STATES_SENTINEL);
m_ledCtrl.SetIcon(GRAY_LED_STATE, IDI_GRAY_ICON);
m_ledCtrl.SetIcon(GREEN_LED_STATE, IDI_GREEN_ICON);
m_ledCtrl.SetIcon(YELLOW_LED_STATE, IDI_YELLOW_ICON);
m_ledCtrl.SetIcon(RED_LED_STATE, IDI_RED_ICON);
m_ledCtrl.SetIcon(BLUE_LED_STATE, IDI_BLUE_ICON);
...

状态设置与以前相同,但是现在可能的值是从GRAY_LED_STATE到BLUE_LED_STATE。

活动LED按钮

Activity LED按钮是在可控一段时间后自动关闭的LED按钮,这样用户就不用负责管理关闭时间了。

活动时间由一个内部计时器控制,当LED按钮被设置为除LED_BUTTON_STATE_OFF之外的任何状态时,它就会被触发。当定时器计时结束时,LED按钮关闭。(当定时器计时结束时,LED将停止活动。)

因为计时器是一个有限的全局资源,要激活一个LED按钮,用户应该提供一个timerId来识别计时器。这样,两个或多个Activity LED按钮可以在同一个应用程序中共存,每个按钮都有不同的计时器标识。

要停用一个活动计时器,只需提供一个空的timerId。计时器也被释放时,LED按钮窗口被销毁。

首先,你可能想要管理所有的计时器你使用的代码在一个单独的地方,因此,在一些可见的头文件,定时器标识符:

...
#define MY_ACTIVITY_LED_TIMER_ID         (WM_USER + 0x123)
...

然后InitDialog()中的代码变成:

...
// Simple Led with Activity detection
m_ledCtrl.SetIcons(IDI_GRAY_ICON, IDI_YELLOW_ICON);
m_ledCtrl.SetLedActivityTimer(MY_ACTIVITY_LED_TIMER_ID, 123);
...

上面的代码将LED设置为持续时间123毫秒的活动LED。

一个简单的,多状态或条件LED按钮也可以是一个活动LED按钮。

A条件LED按钮

为了更好地理解条件LED的状态,让我们来看看下面的情况:

  • LED按钮控件能够显示两种以上的状态。
  • LED按钮用作故障检测器。
  • 一个线程将高速从硬件读取一些数据,等待一些信号的改变。当需要时,它将向GUI发送带有更改通知的通知。
  • 当变化为“缓慢”变化时,LED应在“开”和“关”之间正常改变颜色。但是,如果在不到50秒的时间内连续发生两次变化,则LED应该以不同的颜色显示“开”或“关”状态。

下面的状态机可能提供更好的画面:

Glitch Detector

当LED按钮状态依赖于两个(或更多)输入时,则LED按钮成为条件LED。

对于“故障检测器”,输入如下:

  • 当前领导国家。
  • 被请求的新LED状态。
  • 自上次更换LED以来的经过时间。

为了设置条件LED,您应该从派生自CLedStateCondition(在LedButton.h头文件中定义的一个类)的类中创建一个派生对象。

子类应该覆盖ChangeState()虚方法。

ChangeState()方法接收三个参数:

  • newLedState,被请求的新LedState。
  • oldLedState,转换前的当前LedState。
  • isForcedChange,指示强制转换到newLedState的布尔标志。派生类应该修复它的私有FSM,以反映这种强制更改,并返回newLedState。

ChangeState()应该包含决定LED按钮将进入的新LED状态的所有逻辑。(我不会在这里提供故障检测器的代码,因为我想关注条件LED。)

您可以在某些头文件中定义以下枚举类型来处理故障检测器:

...
enum EGlitchDetectorState
{
    OFF_STATE = LED_BUTTON_STATE_ON,      // Green LED,
    ON_STATE,                             // Yellow LED,
    GLITCH_OFF_STATE,                     // Blue LED,
    GLITCH_ON_STATE,                      // Red LED,
    IDLE_STATE,                           // No LED Icon,

    GLITCH_DETECTOR_STATES_SENTINEL // Not to be used as a EGlitchDetectorState.
};
...

硬件通知将分别为TRUE和FALSE。

对于本例,CLedStateCondition派生类的名称将是CGlitchDetector。将这个CGlitchDetector的一个实例放在CDemoDlg中,并调用它m_glitchDetector。

对话框InitDialog()的代码可以是:

...
//
// 1) Initialize the m_glitchDetector as required (code not shown here)
// 2) Set the led as a multi-state led.
// 3) Add the Glitch Detector to the Led Button.
// 4) Set the initial state as IDLE_STATE. (Force this state)
//
m_ledCtrl.SetLedStatesNumber(GLITCH_DETECTOR_STATES_SENTINEL);
m_ledCtrl.SetIcon(OFF_STATE, IDI_GREEN_ICON);
m_ledCtrl.SetIcon(ON_STATE, IDI_YELLOW_ICON);
m_ledCtrl.SetIcon(GLITCH_ON_STATE, IDI_RED_ICON);
m_ledCtrl.SetIcon(GLITCH_OFF_STATE, IDI_BLUE_ICON);
m_ledCtrl.SetIcon(IDLE_STATE, 0,0,0); // No Icon on purpose.

m_ledCtrl.SetLedStateCondition(&m_glitchDetector);

m_ledCtrl.SetLedState(IDLE_STATE, true); // Force IDLE_STATE.
...

在接收硬件通知的代码中,我们将分别使用OFF_STATE或ON_STATE值调用SetLedState()方法。

afx_msg LONG CDemoDlg::OnHWUpdate(WPARAM wparam, LPARAM /*lparam*/)
{
    ...
    LedState ledState = (TRUE == wparam) ? ON_STATE : OFF_STATE;
    m_ledCtrl(ledState);
    ...
}

一个简单的,多状态或活动的LED按钮也可以是一个条件LED按钮。

文本属性

可以为每个LED状态更改文本前景色或/和按钮背景色。默认情况下,文本前景色为::GetSysColor(COLOR_BTNTEXT),按钮背景色为::GetSysColor(COLOR_BTNFACE)。

控制LED状态颜色的方法如下:

  • SetTextForeground (): 为特定的LED状态设置文本前景色。
  • GetTextForeground (): 获取特定LED状态的文本前景色。
  • SetTextBackground (): 为特定的LED状态设置文本背景颜色。
  • GetTextBackground (): 获取特定LED状态的文本背景颜色。
  • SetTextColors (): 为特定的LED状态设置文本前景色和按钮背景色。
  • RestoreDefaultColors (): 恢复所有LED状态的默认颜色,请小心使用。

工具提示

这个LED按钮控件可以显示一个“工具提示”,一个小的弹出窗口,显示一些描述LED用途的文本。工具提示在大多数情况下是隐藏的,只有当用户将光标放在LED按钮上并让它停留半秒时才会出现。工具提示出现在光标附近,当用户单击鼠标按钮或将光标移离工具时消失。

以下方法控制工具提示:

  • SetTooltipText (): 从资源字符串或提供的文本设置工具提示文本。
  • ActivateTooltip (): 激活/禁用工具提示。

在当前版本中,只支持“矩形”工具提示。

代码文档

代码中包含Doxygen注释,用于生成HTML文档的代码。我强烈建议你直接或间接地使用这些工具。

Doxygen是一个针对c++, C, Java, Objective-C, IDL (CORBA和微软风格)的文档系统,在某种程度上,也适用于PHP, c#和d。

辅助帮助文件是使用KingsTools [^] Visual Studio . net插件通过SteveKing[^]生成的。此外接程序包含您可能希望在开发环境中集成的几个有用工具。(Doxygen、代码统计、语法着色等)

感谢SteveKing提供了这个工具,以及我在代码中使用的他的免责声明。

提供文件

在源代码和演示项目中提供了以下文件,您可以在自己的项目上使用:

源文件:LedButton.h和LedButton.cppLED图标文件:13个不同颜色的LED图标。(LedButton_src.zip)灯泡文件:LightBulbOff。ico, LightBulbOn。ico, LightBulbBroken.ico(在演示项目中)

免责声明

本代码和随附文件是“按原样”提供的,没有明示或默示保证。不负责可能的损害,或其功能的副作用。用户必须承担使用此代码的全部风险。如果它对你的电脑造成任何损害,使你的宠物生病,使你的秃顶增加,或使你的汽车在你启动它时发出奇怪的噪音,作者不承担责任。这段代码没有bug,只是没有文档化的特性!

使用条款

此代码对于个人使用或免费软件应用程序是免费的。如果您计划在商业或共享软件应用程序中使用此代码,请与作者联系以获得他的许可。

更新日志

DateRev.Description2004/Jan/161.1无闪烁更新(感谢Iain Clarke[^])2004 / 12月/ 251.0在CodeProject上亮相2002 / 8月16——创建

后记

希望这个LED控制对你有用。

为了帮助其他使用CodeProject的用户,请对本文进行评价:)

本文转载于:http://www.diyabc.com/frontweb/news14508.html

原文地址:https://www.cnblogs.com/Dincat/p/13488352.html