C# 超簡單但無聊的自製Track Bar

  • 5279
  • 0

摘要:C# 超簡單但無聊的自製Track Bar

網路上有很多換膚(skin)或者自製的UI設計,

然而SV很懶又很笨,於是只好用這種魚目混珠的方式。

因為客戶的設計,

只好想辦法用圖片兜出結果了frown

然後我發現pictureBox真是好物!!!不但可以代替Button,還可以像這樣自己玩設計~

 

請看設計:

 

很好,你會想這什麼鬼?

就是類似trackBar的設計。當然,學會這招,你可以依樣畫葫蘆設計更漂亮更複雜的造型。

 

首先準備兩張圖,一個當bar,一個當thumb(用來拖動的地方),

如果你的圖片很複雜,那就要準備圖片代換,thumb的背景要與bar設計好(就是融入bar中)

如下:

↑這是bar

↑這是thumb

然後在UI上面放上兩個pictureBox,聰明的你一定知道要將thumb放在bar上面。
接著看是用Image或者BackgroundImage來做障眼法!

圖片建議用Property裡新增現有檔案將Resource加入。
要是你有需要改圖片,就這樣做:

 

pictureBox1.Image=Resources.thumb;

 

其中Resources是要Import專案的Property。

 

因為有些人的圖案可能很複雜,就需要在移動時改變thumb了。
所以建議用Image換圖片,然後大小就設成AutoSize。(在Property)

接下來才是重點了!
因為trackBar有兩種操作,
一種是拖拉,另一種是點。
我們先來處理拖拉的部份:

在thumb的地方加入MouseDown動作,
準備給他拖拉了!

        int movX = 0;
        private void trckbSpeaker_MouseDown(object sender, MouseEventArgs e)
        {
            movX = e.X;
        }

先記錄按下的位置,接著是滑鼠移動時拖動他,所以加入MouseMove動作事件:
 

         private void trckbSpeaker_MouseMove(object sender, MouseEventArgs e)
        {
            
            if (e.Button == MouseButtons.Left)
            {
                trckbSpeaker.Left += e.X - movX;
                if (trckbSpeaker.Left <= pb1.Location.X - (trckbSpeaker.Width / 2))
                {
                    trckbSpeaker.Left = pb1.Location.X - (trckbSpeaker.Width / 2);
                }
                if (trckbSpeaker.Right >= pb1.Location.X + pb1.Width + (trckbSpeaker.Width / 2))
                {
                    trckbSpeaker.Left = pb1.Location.X + pb1.Width + (trckbSpeaker.Width / 2) - trckbSpeaker.Width;
                }
            }
        }

上面有個pb1,這個就是bar的部份,trckbSpeaker則是thumb部分。基本上if部分去掉的話,你的thumb就可以跑到天外之遠,
然而真正的trackBar,他的thumb只能在bar中間跑。
順代一提,因為thumb是橫的,所以是動X軸。
若你的trackBar是直的,那麼就是動Y軸啦!
至於中間範圍的判斷,請自行理解(咦?),總之就是我們的數值判斷其實是thumb的中間,
而thumb中間的X數值為thumb.Left+thumb.Width/2
到目前為止你的拖拉就有動作了~
可是要有值呀!不然是玩假的嗎??
因此這個就用最笨的方法了:區間
因為我的圖片很簡單而固定,

於是我就用個表來換算返回的值,

請看:

       #region SpeakerVolume
        private int spVolume(int value)
        {
            if (value >= 0 && value < 20)
            {
                return 0;
            }
            else if (value >= 20 && value < 26)
            {
                return 5;
            }
            else if (value >= 26 && value < 32)
            {
                return 10;
            }
            else if (value >= 32 && value < 38)
            {
                return 15;
            }
            else if (value >= 38 && value < 43)
            {
                return 20;
            }
            else if (value >= 43 && value < 49)
            {
                return 25;
            }
            else if (value >= 49 && value < 55)
            {
                return 30;
            }
            else if (value >= 55 && value < 61)
            {
                return 35;
            }
            else if (value >= 61 && value < 66)
            {
                return 40;
            }
            else if (value >= 66 && value < 72)
            {
                return 45;
            }
            else if (value >= 72 && value < 78)
            {
                return 50;
            }
            else if (value >= 78 && value < 83)
            {
                return 55;
            }
            else if (value >= 83 && value < 89)
            {
                return 60;
            }
            else if (value >= 89 && value < 95)
            {
                return 65;
            }
            else if (value >= 95 && value < 101)
            {
                return 70;
            }
            else if (value >= 101 && value < 106)
            {
                return 75;
            }
            else if (value >= 106 && value < 112)
            {
                return 80;
            }
            else if (value >= 112 && value < 118)
            {
                return 85;
            }
            else if (value >= 118 && value < 123)
            {
                return 90;
            }
            else if (value >= 123 && value < 129)
            {
                return 95;
            }
            else if (value >= 129 && value < 134)
            {
                return 100;
            }
            return 0;
        }
        #endregion

#region只是為了美觀用XDDD不然沒收合這一串實在很醜cool

總之就是將bar切成10等份,然後中間可能再切一半。
為了配合thumb寬度,我又再切一半做區間,

因為怕區間有時不是等分(有時要配合圖片誤差),所以就用絕對位置了。

否則應該要用Width/10來算。


接著當滑鼠點擊結束,就抓取滑鼠位置來算值。
因此加入了MouseUp事件:

 

        int volumes = 0;
        private void trckbSpeaker_MouseUp(object sender, MouseEventArgs e)
        {
            int values = trckbSpeaker.Location.X + (trckbSpeaker.Width / 2);
            volumes = spVolume(values);
        }

來到這,我們真正要的值就是volumes了!因為是用來作音量控制,我取這個變數名angel

處理完拖拉後,再來就是直接點擊的部份,比較簡單。
因為拖拉實在太麻煩,能不能我點哪就是哪個數值?當然可以~

這次處理bar的部份,
加入MouseDown的動作事件:

         private void pb1_MouseDown(object sender, MouseEventArgs e)
        {
            int clickAt = e.X + pb1.Left;
            trckbSpeaker.Location = new Point(clickAt - trckbSpeaker.Width / 2, trckbSpeaker.Location.Y);
        }

clickAt是滑鼠的點擊位置,也就是e.X(滑鼠在bar的相對位置)加上pb1.Left(bar的左上角X座標)
所以thumb配合跑到那個位置,而那個位置對應的是thumb的中心點,所以就會改成上面那樣囉~
永遠記得thumb的中心點=Left+寬/2(以橫trackBar來說)
然後一樣要算值的部份,於是在bar又加入了MouseUp的事件:
 

        private void pb1_MouseUp(object sender, MouseEventArgs e)
        {
            int values = trckbSpeaker.Location.X + (trckbSpeaker.Width / 2);
            volumes = spVolume(values);
        }


然後我們的偽TrackBar就完成了!!!

我知道這樣很無聊,
不過我想到用這個可以拿來做遊戲也不錯yes
用這樣的原理可以做很有趣的遊戲介面呢~


嗯,我知道很蠢,不要打我broken heart
SV太久沒發文,所以PO這種很無聊的東西XDDDDDD

然而因為程序員美工不見得好,
若真的用trackBar程式碼下去改,也不見得可以改出很漂亮的元件,
所以......

pictureBox才是王道呀!!!(誤)

缺點是pictureBox是矩形,所以有圖形上的Bug(就是你的圖若是圓形,若你點左上角角還是代表有點到)
再來就是圖片刷新的部分。
大家都知道Repaint是很耗資源的,

所以若拖動的太快,圖片會類格......

目前這兩點是這種方法的大缺點Orz

 

SV的分享就到這了~

 

新增:

是聽說如果怕移動時會閃爍可以用Double buffer,

那麼就是在form加入以下控制:

 

            InitializeComponent();//原本就會自動產生的

            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

 

然後我的程式碼要給他控制:
 

        int movX = 0;
        private void trckbSpeaker_MouseDown(object sender, MouseEventArgs e)
        {
            movX = e.X;
            canMove = true;
        }
        int volumes = 50;
        bool canMove = false;
        private void trckbSpeaker_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if(canMove==true)
                    trckbSpeaker.Left += e.X - movX;

                int values = trckbSpeaker.Location.X + (trckbSpeaker.Width / 2);
                volumes = spVolume(values);
                
                ///speaker = Speaker.GetDefaultDevice();
                ///speaker.Volume = (float)volumes / 100.0f;

                if (trckbSpeaker.Left <= pb1.Location.X - (trckbSpeaker.Width / 2))
                {
                    trckbSpeaker.Left = pb1.Location.X - (trckbSpeaker.Width / 2);
                    canMove = false;
                }
                if (trckbSpeaker.Right >= pb1.Location.X + pb1.Width + (trckbSpeaker.Width / 2))
                {
                    trckbSpeaker.Left = pb1.Location.X + pb1.Width + (trckbSpeaker.Width / 2) - trckbSpeaker.Width;
                    canMove = false;
                }
            }
        }

 

差別就在於加入了canMove做控制,
否則他會不斷想移動到原本設定好的Location喔~

補充:要是希望在MouseMove時就抓值,修改一下程式碼就好囉~(因為有的會希望邊移動就邊改變設定)