1. 程式人生 > 實用技巧 >LedButton狀態控制(Owner-draw)

LedButton狀態控制(Owner-draw)

表的內容

  • 動機
  • 環境使用
  • 將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應該以不同的顏色顯示“開”或“關”狀態。

下面的狀態機可能提供更好的畫面:

當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/news14026.html