C#數碼管控件(轉)


源:一個簡單Led控件

Led控件,可能是非常經典和常用的了,但是很遺憾的是,這個名稱至少涵蓋了三種控件:
1.是7段式的有發光二極管構成的Led,通常用來顯示數字。
2.是指示燈,通常用來閃爍,指示電源,等狀態。
3.是由發光二極管陣列組成的模擬顯示屏,這種led屏有較高的分辨率,所以可以顯示中文內容和一定容量的界面。

這篇文章里面說的是1.其中2這種在codeproject上面有很多例子,我曾經改寫其中的例子成為在移動設備上使用。

今天我用c#寫了這樣一個Led控件。我也曾經下載過,可惜好像沒有什么源碼,想來這個東西應該沒太復雜,所以干脆自己也寫個玩玩。記得當年本科時候我就寫過單片機程序,控制led數碼管,實現了時間調節時閃爍,“霓虹燈”屏保等效果,大大出乎了老師的預期。我想作為一個控件,這個東西的主要功能是為了模擬現實中的用戶界面,或者讓它更美觀,更有趣味一些。而如果只是為了顯示一些信息,顯然有太多其他的更方便的選擇了。所以我用較短的時間實現了一個功能比較簡陋的但是能用的控件。

它的運行效果如下:我想這個沒什么可說的。


筆畫變細以后是這樣的:


這里我加載了6個控件,一個定時器,用來實時的顯示系統時間。
對於這個控件我想了一下,也許可以使用圖片資源來做,比較方便,但我還是把它做成了矢量型的,這樣,把一個led中所有筆畫(我稱為section,段)采用一個六邊形模擬,我需要隨時能夠計算出所有筆畫的坐標,這樣一個led具有6個點*7段=42個點,這樣會占用300多bytes左右。如果顯示的數字不多,還是可以不去在乎這點內存的。這就是矢量圖的特點,如果你想表現的更細膩,顯然會極大加大計算量,腦子也會累的。

然后我用下面的函數計算出七段的坐標:

/// <summary>
/// 重新計算段的坐標!!!(這種方法得出的圖形將是矢量的,不受縮放影響)
/// </summary>
private void ComputeSections(int ledwidth,int ledheight)
{
    //計算出控件中心點的坐標
    int cx=ledwidth/2;
    int cy=ledheight/2;

    int t1=this.m_SectionThick*3/4;    //大斜坡長
    int t2=this.m_SectionThick/4;    //小斜坡長
    int t3=this.m_SectionThick/2;    //中斜坡長
    //段的一半長度!
    int hw=cx-this.m_SectionThick-2;    //half width of section 距離邊緣2像素
    int hh=cy-this.m_SectionThick-2;    //half height of section
    Section[] s=this.m_Sections;

    //第0段(最底下一橫)
    s[0].P[0].X=cx-hw-this.m_SectionThick/4;
    s[0].P[0].Y=cy+hh+this.m_SectionThick/4;
    s[0].P[1].X=s[0].P[0].X-t2;
    s[0].P[1].Y=s[0].P[0].Y-t2;
    s[0].P[2].X=s[0].P[1].X+t1;
    s[0].P[2].Y=s[0].P[1].Y-t1;

    //第1段(它是中間的一橫,因為和其他任何段都沒對稱關系,只能手寫!)
    s[1].P[0].X=cx-hw+this.m_SectionThick*3/16;
    s[1].P[0].Y=cy+t3;
    s[1].P[1].X=s[1].P[0].X-t3;
    s[1].P[1].Y=s[1].P[0].Y-t3;
    s[1].P[2].X=s[1].P[0].X;
    s[1].P[2].Y=cy-t3;

    //第2段(最上面一橫,與第0段按y軸對稱)
    for(int i=0;i<3;i++)
    {
        s[2].P[i].X=s[0].P[2-i].X;
        s[2].P[i].Y=ledheight-s[0].P[2-i].Y;
    }
    //循環為0,1,2三個水平段的p[3],p[4],p[5]賦值,注意這幾個值可以根據錢三個點求出
    for(int i=0;i<3;i++)
    {
        for(int j=3;j<6;j++)
        {
            s[i].P[j].X=ledwidth-s[i].P[5-j].X;
            s[i].P[j].Y=s[i].P[5-j].Y;
        }
    }
    //到這里我們已經計算好了0,1,2段的全部坐標,下面開始計算3~6段,他們具有相互對稱的關系!
    
    //第3段(左上的豎)(注意本身自己也不具備對稱關系,6個點都要手寫)
    s[3].P[0].X=cx-hw+this.m_SectionThick/5;
    s[3].P[0].Y=cy-this.m_SectionThick*3/5;
    s[3].P[1].X=s[3].P[0].X-t3;
    s[3].P[1].Y=s[3].P[0].Y+t3;
    s[3].P[2].X=s[3].P[1].X-t3;
    s[3].P[2].Y=s[3].P[1].Y-t3;
    s[3].P[3].X=s[3].P[2].X;
    s[3].P[3].Y=s[3].P[0].Y-hh+this.m_SectionThick;
    s[3].P[4].X=s[3].P[3].X+t2;
    s[3].P[4].Y=s[3].P[3].Y-t2;
    s[3].P[5].X=s[3].P[4].X+t1;
    s[3].P[5].Y=s[3].P[4].Y+t1;

    //計算4,5,6段的點坐標(4和3段x對稱,5和3是y對稱,6和3是原點對稱)
    for(int i=0;i<6;i++)
    {
        int m=(8-i)%6;
        s[4].P[i].X=ledwidth-s[3].P[m].X;
        s[4].P[i].Y=s[3].P[m].Y;

        s[5].P[i].X=s[3].P[m].X;
        s[5].P[i].Y=ledheight-s[3].P[m].Y;

        s[6].P[i].X=ledwidth-s[3].P[i].X;
        s[6].P[i].Y=ledheight-s[3].P[i].Y;
    }
}

上面的代碼可能是這個控件里唯一復雜的工作。。。。這是一個很勞累的工作,可是我暫時沒想到更好的辦法讓它更加簡化。段的編號順序是:0底部橫,1中部橫,2頂部橫,3左上豎,4右上豎,5左下豎,6右下豎,7小數點(我暫時沒有繪制它)。

顯示時,使用一個byte來控制,其所在位為1時,相應的section被點亮,否則為熄滅。
因此,幾個基本數字的編碼如下:

(byte)0x7d,//0
(byte)0x50,//1
(byte)0x37,//2
(byte)0x57,//3
(byte)0x5a,//4
(byte)0x4f,//5
(byte)0x6f,//6
(byte)0x54,//7
(byte)0x7f,//8
(byte)0x5f,//9
(byte)0x02,//-

最后,當我們顯示時:

//繪制七段,section是一個struct,包含一個point數組
for(int i=0;i<this.m_Sections.Length;i++)
   {
    if((this.m_DisplayCode & (1<<i))!=0)
         {
                this.m_Brush.Color=this.ForeColor;    
                g.FillPolygon( this.m_Brush, this.m_Sections[i].P);
    }
    else
          {
                 this.m_Brush.Color=this.m_OffColor;
                 g.FillPolygon( this.m_Brush, this.m_Sections[i].P); 
        }
}

對外部可以提供一個簡單的屬性,displaynumber來獲取和設置顯示的數字,允許0~9.
也允許外部設置筆畫寬度,這樣上面的sections坐標需要重新計算,並更新到顯示。但是這個屬性不能設置的過大,否則坐標值相互超越則顯示會出錯。

最后我想了一下,目前它的靈活性被我懷疑,加載了6個一摸一樣的led控件也讓我感到使得代碼很笨拙。它現在的功能比較簡陋,它可以繼續擴展,使他將來能夠同時容納多個顯示位。

在最后我提供這個控件以及示例的完整代碼下載地址:(當然,它目前還不成熟,在結構和接口上有進一步的進化空間)

http://files.cnblogs.com/hoodlum1980/LedTest_ByHoodlum.rar


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM