摘要:C# 超簡單但無聊的自製Track Bar
網路上有很多換膚(skin)或者自製的UI設計,
然而SV很懶又很笨,於是只好用這種魚目混珠的方式。
因為客戶的設計,
只好想辦法用圖片兜出結果了
然後我發現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不然沒收合這一串實在很醜
總之就是將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了!因為是用來作音量控制,我取這個變數名
處理完拖拉後,再來就是直接點擊的部份,比較簡單。
因為拖拉實在太麻煩,能不能我點哪就是哪個數值?當然可以~
這次處理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就完成了!!!
我知道這樣很無聊,
不過我想到用這個可以拿來做遊戲也不錯
用這樣的原理可以做很有趣的遊戲介面呢~
嗯,我知道很蠢,不要打我
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時就抓值,修改一下程式碼就好囉~(因為有的會希望邊移動就邊改變設定)