• 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

  • 相关阅读:
    shutil模块详解
    pycharm连接服务器
    python中__name__属性的使用
    ORM学习笔记
    ORM连表操作
    python操作mysql实例
    python登录项目
    pycharm建立第一个django工程-----windows中
    打印顺序
    shell脚本
  • 原文地址:https://www.cnblogs.com/Dincat/p/13488352.html
Copyright © 2020-2023  润新知