經過十多天的艱苦奮戰,MyKTV點歌系統終於成型,從剛開始接到項目的茫然,到完成項目時的喜悅,整個過程的艱辛和付出只有自己知道.雖然這個項目還有許多需要完善的地方,譬如添加歌詞信息,實現窗體的美化等,這些在後續時間里我再一一進行一個完善吧!首先呢,我先將整個項目所能實現的功能做一個簡單的介紹,K.....
經過十多天的艱苦奮戰,MyKTV點歌系統終於成型,從剛開始接到項目的茫然,到完成項目時的喜悅,整個過程的艱辛和付出只有自己知道.雖然這個項目還有許多需要完善的地方,譬如添加歌詞信息,實現窗體的美化等,這些在後續時間里我再一一進行一個完善吧!
首先呢,我先將整個項目所能實現的功能做一個簡單的介紹,KTV點歌系統包括了前臺和後臺兩大部分,前臺的功能就是能夠根據客戶的需求來實現點歌操作,後臺主要是管理員來添加歌手信息和歌手信息
前臺
這是前臺的主界面,通過主界面上的一系列操作,分別可以進入相對應的界面
這是當我播放歌曲後的主界面,添加歌曲後,主界面就能顯示該歌手的圖片信息,正在播放和下一首也會顯示相應的文本信息,並且,當我切歌後,歌手圖片和文本框也能隨之變化
這是通過金榜排行進入的界面,歌曲的排列順序都是通過點擊的次數降序排列
這是類型點歌,當客戶點擊任意一個類型時都會根據客戶所選的類型,到資料庫中進行篩選,然後將篩選後的結果在歌曲列表中展示出來
這是字數點歌,其中每個文字都是通過代碼動態生成的,如何生成將在後面寫詳細代碼.當用戶點擊相應的字數時也會在資料庫中進行篩選,然後在歌曲列表中顯示出來,大家可以很清楚的感覺到,歌曲列表這個窗體其實是幾個功能塊共用的一個窗體.
這是拼音點歌,可以根據用戶輸入的拼音或者是歌曲名字進行模糊查詢.
這是已點列表,這裡面我加了一個右鍵菜單,可以根據用戶的需求來進行立即播放和刪除
這是歌星點歌,這三張圖其實不是三個窗體,而是一個窗體,只是用了三個listview控制項,當我需要顯示哪一個控制項時就將其他兩個控制項給隱藏了.如何操作也將在後面通過代碼進行詳細介紹.
最後這就是我在主界面通過娛樂添加的一個猜數小游戲.它能產生一個隨機數,跟你輸入的數進行一個比較,如果大了或者是小了都會有相應的提示,直到你猜中後,又會顯示你一共猜了多少次,用戶就可以根據你猜的次數的多少來進行相應的懲罰了.而且界面上的圖是可動的,當程式運行起來後就好像一個少女在那兒跳舞.
這些基本上就是我整個前臺所能實現的所有功能了,後臺的話在後面再跟大家一一展示了.
下麵就給大家展示一些相對應的代碼了
一:怎樣實現無邊框窗體的拖動
1 private Point mouseOffset; //記錄滑鼠指針的坐標 2 private bool isMouseDown = false; //記錄滑鼠按鍵是否按下 3 private void MainMenu_MouseDown(object sender, MouseEventArgs e) 4 { 5 int xOffset; 6 int yOffset; 7 if (e.Button == MouseButtons.Left) 8 { 9 xOffset = -e.X - SystemInformation.FrameBorderSize.Width; 10 yOffset = -e.Y - SystemInformation.CaptionHeight - SystemInformation.FrameBorderSize.Height; 11 mouseOffset = new Point(xOffset, yOffset); 12 isMouseDown = true; 13 } 14 15 } 16 17 private void MainMenu_MouseMove(object sender, MouseEventArgs e) 18 { 19 if (isMouseDown) 20 { 21 Point mousePos = Control.MousePosition; 22 mousePos.Offset(mouseOffset.X + 5, mouseOffset.Y + 30); 23 Location = mousePos; 24 } 25 26 } 27 28 private void MainMenu_MouseUp(object sender, MouseEventArgs e) 29 { 30 // 修改滑鼠狀態isMouseDown的值 31 // 確保只有滑鼠左鍵按下並移動時,才移動窗體 32 if (e.Button == MouseButtons.Left) 33 { 34 isMouseDown = false; 35 } 36 37 }
在窗體中找到相對應的事件,然後copy代碼便可實現
二:實現窗體抖動的代碼
//實現窗體抖動的效果 Point first = this.Location; for (int i = 0; i < 8; i++) { Random ran = new Random(); Point p = new Point(this.Location.X + ran.Next(20) - 4, this.Location.Y + ran.Next(20) - 4); System.Threading.Thread.Sleep(25);//當前線程掛起15毫秒 this.Location = p; System.Threading.Thread.Sleep(25);//當前線程再掛起15毫秒 } this.Location = first; //將窗體還原為原來的位置
整個KTV點歌系統中,我們需要定義幾個輔助類.
1:Help類
public class Help { public static string str = "data source=.;initial catalog=MyKTV;uid=sa;"; public static string ways = ""; //保存歌手圖片路徑 public static string songurl = ""; //保存歌曲路徑 }
2:PlayBackStatus(播放狀態類)
public enum PlayBackStatus { PlayBack, //已播 NotBroadcast, //未播 NowBroadcast, //正在播放 Repeat, //重播 baoji, //右鍵菜單的標記 Cut //切歌 }
3:Song(歌曲類)
public class song { public string SongName; //歌曲名稱 public string SongURL; //歌曲存放路徑 public PlayBackStatus playback; //歌曲播放狀態 public string singerphotourl; //歌手圖片路徑 }
4:PlayList(播放列表類)
public class PlayList { public static song[] songlist = new song[100]; //定義一個歌曲數組 public static int SongIndex = 0; //當前播放歌曲在數組中的索引 public static string NextSongName = ""; //下一首歌曲 public static string zhuangtai = ""; //保存是切歌還是重播 //將歌曲增加到歌曲數組中去 public static bool AddSong(song song) { bool Result = false; //記錄歌曲是否添加成功 for (int i = 0; i < songlist.Length;i++ ) { if (songlist[i] == null) { songlist[i] = song; Result = true; break; } } return Result; } //切歌 public static void CutSong() { //獲取到當前播放的歌曲改變播放狀態 if (songlist[SongIndex] != null) { songlist[SongIndex].playback = PlayBackStatus.Cut; ChargeInde(); //改變歌曲索引,播放下一首 } } //重唱 public static void ListenAgain() { if (songlist[SongIndex] != null) { songlist[SongIndex].playback = PlayBackStatus.Repeat; //改變歌曲播放狀態 } } //獲取下一首歌曲的名稱 public static string GetNextSongName() { if (songlist[0]!=null && songlist[SongIndex + 1] == null) { NextSongName = "待添加...."; return NextSongName; } else { if (songlist[0] != null) { NextSongName = songlist[SongIndex + 1].SongName; return NextSongName; } else { return string.Empty; } } } //獲得當前播放的歌曲 public static song GetPlaySong() { if (songlist[SongIndex] != null) { return songlist[SongIndex]; } else { return null; } } //播放下一首 public static void ChargeInde() { SongIndex++; } //點擊重播時根據歌曲名稱查找該歌曲在歌曲列表中的位置並改變其狀態 public static void SelectFromSongName(string name) { for (int i = 0; i < songlist.Length;i++ ) { if (songlist[i] != null) { if (songlist[i].SongName.Equals(name)) { if (zhuangtai.Equals("重播")) { songlist[i].playback = PlayBackStatus.Repeat; //將該歌曲狀態修改成重播 break; } else { if (songlist[i + 1] != null && songlist[i].playback == PlayBackStatus.NowBroadcast) { songlist[i].playback = PlayBackStatus.Cut; //將該歌曲狀態修改成切歌 songlist[i + 1].playback = PlayBackStatus.NowBroadcast; //將下一首歌狀態改成正在播放 } else { MessageBox.Show("親,最後一首歌曲和不是正在播放的歌曲不能切喲~~^_^"); } break; } } } else { break; } } } public static bool isRight=false; //記錄當isRight等於true時就播放選中歌曲 //點擊已點列表中的播放時,根據歌曲名找到索引 public static void SelectIndexBySongName(string name) { for (int i = 0; i < songlist.Length; i++) { if (songlist[i] != null) { if (songlist[i].SongName.Equals(name)) { songlist[i].playback = PlayBackStatus.baoji; //為選中歌曲做一個標記 songlist[SongIndex].playback=PlayBackStatus.PlayBack; //將當前播放歌曲改為已播狀態 SongIndex = i; //將歌曲索引改變為所選中的歌曲 isRight = true; break; } } else { break; } } } //刪除右鍵菜單選中的歌曲 public static bool delete(string name) { for (int i = 0; i < songlist.Length; i++) { if (songlist[i] != null) { if (songlist[i].SongName.Equals(name)) { if (songlist[i].playback == PlayBackStatus.NowBroadcast) { return false; } while(true) { if (songlist[i + 1] != null) { songlist[i] = songlist[i + 1]; i++; } else { songlist[i] = null; break; } } for (int l = 0; l < songlist.Length;l++ ) { if (songlist[l] != null) { if (songlist[l].playback == PlayBackStatus.NowBroadcast) { SongIndex = l; } } } } } else { break; } } return true; } }
當我們將這些輔助類創建好之後,我們就可以開始實現其他功能塊的書寫了.
首先在一進入主界面的時候我們就要保存歌手圖片路徑和歌曲路徑
private void Form1_Load(object sender, EventArgs e) { //保存歌手圖片前半部分路徑 string sql = "select ways from Ways where id=1"; Help.ways = retunURL(sql); //保存歌曲前半部分路徑 string sql2 = "select ways from Ways where id=2"; Help.songurl = retunURL(sql2); } //返回前半部分路徑的方法 public string retunURL(string sql) { SqlConnection con = new SqlConnection(Help.str); con.Open(); SqlCommand com = new SqlCommand(sql, con); string URL = com.ExecuteScalar().ToString(); con.Close(); return URL; }
第一步完成後,我們就可以進如歌星點歌界面,實現歌星圖片的動態載入了,我們上面歌星點歌的圖片中,第一張是手動添加的,第二張半動態添加的(也可跟第一張一樣手動添加,在這裡是為了熟練動態載入的代碼),第三張是全動態添加的,手動添加的部分就是,準備一個listview,imagelist 選擇大圖標模式,直接添加圖片索引和Text文本即可,在這裡只展示全動態載入時所寫的代碼
第一步,在load事件中顯示第一個listview隱藏第二第三個listview
//Load事件 private void SingerStar_Load(object sender, EventArgs e) { //隱藏第二第三個窗體 listView2.Visible = false; listView3.Visible = false; }
第二步,當我點擊第一個listview時保存所點的記錄的文本或Tag並展示第二個listview
public string singertype = ""; //保存用戶選擇的歌星類型(男,女,組合) public int singerdistrictID; //保存用戶選擇的歌星地區的ID(香港...大陸...臺灣.....) public string singerdistrict; //保存用戶選擇的歌星地區(香港...大陸...臺灣.....) public int Number; //返回時更具Number的值來判斷顯示哪個控制項,隱藏哪個控制項 //從第一個控制項跳轉到第二個控制項,第二個控制項的文本和圖像都是動態載入的 public void ShowListView2() { Number = 2; if (listView1.SelectedItems[0] != null) { listView1.Visible = false; //隱藏第一個控制項 listView2.Location = listView1.Location; //讓兩個控制項出現的位置相同 listView2.Visible = true; //顯示第二個控制項 singertype = listView1.SelectedItems[0].Tag.ToString(); } SqlConnection con = new SqlConnection(Help.str); string sql = "select * from singer_type "; SqlCommand com = new SqlCommand(sql, con); listView2.Items.Clear(); //清空上次點擊載入的數據 try { con.Open(); SqlDataReader read = com.ExecuteReader(); if (read != null) { if (read.HasRows) { int index = 0; while (read.Read()) { int TypeId = Convert.ToInt32(read["singertype_id"]); string TypeName = read["singertype_name"].ToString(); ListViewItem list = new ListViewItem(); list.Text = TypeName; list.Tag = TypeId; list.ImageIndex = index; listView2.Items.Add(list); index++; } } } } catch (Exception) { MessageBox.Show("網路錯誤!"); } finally { con.Close(); } }
第三步,保存第二個listview中用戶所選擇的記錄,並且顯示第三個listview
//從第二個控制項跳轉到第三個控制項,第三個控制項的歌星圖片是從電腦硬碟上載入的 public void ShowListView3() { Number = 3; if (listView2.SelectedItems[0] != null) { listView2.Visible = false; //隱藏第二個控制項 listView3.Location = listView2.Location; //兩個控制項的出現位置相同 listView3.Visible = true; //第三個控制項顯示 singerdistrictID = Convert.ToInt32(listView2.SelectedItems[0].Tag); //獲得用戶點擊的地區ID singerdistrict = listView2.SelectedItems[0].Text; //獲得用戶點擊的歌手地區 } SqlConnection con = new SqlConnection(Help.str); con.Open(); try { //查詢符合用戶選擇的地區和歌手的類型的歌手名字 string sql = @"select singer_name ,siinger_photo_url from singer_info where singer_sex='" + singertype + "' and singertype_id=" + singerdistrictID + ""; SqlCommand com = new SqlCommand(sql,con); SqlDataReader reader= com.ExecuteReader(); listView3.Items.Clear(); //清除上次點擊載入的數據 imageList3.Images.Clear(); //清除imagelist中上一次保存的圖片數據 if (reader != null) { if (reader.HasRows) { int index=0; while (reader.Read()) { string singerName = reader["singer_name"].ToString(); string singer_phone = reader["siinger_photo_url"].ToString(); //獲得圖片名字(後半部分路徑) string lujing = Help.ways + singer_phone; //獲得圖片完整路徑 imageList3.Images.Add(Image.FromFile(lujing)); //通過完整路徑將圖片保存到imagelist3中 ListViewItem list = new ListViewItem(); list.ImageIndex = index; list.Text = singerName; listView3.Items.Add(list); index++; } } else { DialogResult result= MessageBox.Show("沒有" + singerdistrict+"地區 " + singertype + "歌手信息!!!!","用戶提示",MessageBoxButtons.YesNo,MessageBoxIcon.Information); if (result == DialogResult.Yes) { fanhui(); } } } } catch (Exception) { MessageBox.Show("網路異常!!"); } finally { con.Close(); } }
這樣就能將我們的三個listview展示出來,並且能夠實現動態載入數據了,到這裡然後我們就可以根據用戶第一次,第二次的條件來查找資料庫中的歌手信息,當用戶點擊歌手信息的時候就可以在歌曲列表中根據歌手名字顯示所有的歌曲信息了
//獲取選中歌星的名字,並將其值傳遞給歌曲列表然後顯示歌曲列表 private void listView3_Click(object sender, EventArgs e) { SongList song = new SongList(); song.SingerName = listView3.SelectedItems[0].Text; song.singer = this; song.Show(); this.Hide(); } //這是在歌曲列表中定義的一個歌手名字信息,然後通過窗體傳值實現 public string SingerName; //保存從歌星列表中傳遞過來要查詢其歌曲信息的歌手的名字 string sql = @"select siinger_photo_url,song_name,singer_name , song_url from song_info,singer_info where singer_info.singer_id=song_info.singer_id and singer_name='" + SingerName + "'"; //根據歌手的名字將用戶選擇的歌手信息展示在LIstView控制項中 public void ShowUserByName(string sql) { dataGridView1.AutoGenerateColumns = false; SqlConnection con = new SqlConnection(Help.str); try { SqlDataAdapter da = new SqlDataAdapter(sql,con); DataSet dt = new DataSet(); da.Fill(dt,"user"); dataGridView1.DataSource = dt.Tables["user"]; } catch (Exception) { MessageBox.Show("網路異常!!"); } finally { con.Close(); } }
這樣,我就可以通過歌曲列表中的歌曲信息來點歌了,當我每點擊一首歌,我就將所點的歌增加到我事先定義好的Song類裡面的歌曲數組當中去
//添加歌曲的方法 public void AddSong() { if (dataGridView1.SelectedRows[0].Cells[0].Value.ToString() != "") { song Song = new song(); Song.SongName = dataGridView1.SelectedRows[0].Cells["songname"].Value.ToString(); Song.SongURL = dataGridView1.SelectedRows[0].Cells["songurl"].Value.ToString(); Song.playback = PlayBackStatus.NotBroadcast;//播放狀態為未播 Song.singerphotourl = dataGridView1.SelectedRows[0].Cells["siinger_photo_url"].Value.ToString(); //添加歌手圖片路徑 bool result = PlayList.AddSong(Song); //將歌曲增加到播放列表裡面 if (result) { MessageBox.Show("添加成功!!"); AddSongCount(dataGridView1.SelectedRows[0].Cells["songname"].Value.ToString()); } else { MessageBox.Show("添加失敗!"); } } else { MessageBox.Show("請選擇正確的歌曲名稱!"); } }
並且,為了實現金榜排行,用戶每添加一首歌,都在資料庫中將歌曲的點擊次數加1
//每次點擊歌曲後都在資料庫中將該歌曲的點擊次數增加1 public void AddSongCount(string song_name) { SqlConnection con = new SqlConnection(Help.str); string sql = "update song_info set song_play_count=song_play_count+1 where song_name='"+song_name+"'"; SqlCommand com = new SqlCommand(sql,con); con.Open(); com.ExecuteNonQuery(); con.Close(); }
一旦當我們的歌曲數組中有了歌曲之後,我們就可以進行歌曲的播放了,在播放器控制項所在的界面(我的是主界面)就可以通過獲取到歌曲的完整路徑來播放歌曲
並且動態的給pictureBox添加歌手圖片
public song CurrentSong; //定義當前播放歌曲 //獲得當前播放的歌曲 public void PlaySong() { CurrentSong = PlayList.GetPlaySong();//事先定義的類里的方法 if (CurrentSong != null) { CurrentSong.playback = PlayBackStatus.NowBroadcast; //將歌曲改成正在播放狀態 Player1.URL = Help.songurl + CurrentSong.SongURL; //獲得歌曲的路徑 singerimage.Image = Image.FromFile(Help.ways + CurrentSong.singerphotourl); textBox1.Text = CurrentSong.SongName; } else { //給文本框賦值 textBox1.Text = ""; textBox2.Text = ""; } }
為了可以實現連續播放,並且能夠自動播放下一首,我們可以加一個計時器控制項,每隔一秒掃描一次歌曲信息,判斷時候為空,如果為空則進行播放下一首歌曲
public song NextSong; //定義下一首播放的歌曲 //獲得下一首播放的歌曲名稱 public void NextPlay() { textBox2.Text= PlayList.GetNextSongName(); //事先定義的類 } private void timer1_Tick(object sender, EventArgs e) { NextPlay(); //獲得下一首歌曲的名稱 if (CurrentSong == null) { PlaySong(); } if (Player1.playState == WMPLib.WMPPlayState.wmppsStopped) //判斷歌曲的播放狀態是否為快要停止也就是是否快要播放完 { if(CurrentSong!=null) { CurrentSong.playback = PlayBackStatus.PlayBack; //將該歌曲狀態改成已播放 } CurrentSong = null; PlayList.ChargeInde(); //Playlist中定義的方法 } }
這樣就基本實現了整個播放歌曲的全過程了,並且你的歌曲數組中有多少歌曲都能夠依次順序播放,以上代碼實現瞭如何通過歌星點歌進行歌曲的播放,但是並沒有實現切歌和重唱的功能,
切歌和重唱功能是根據歌曲的狀態,在計時器控制項中來進行判定操作的,根據歌曲狀態來執行相對應的方法(這是主界面的切歌和重唱)
//切歌 private void pictureBox2_Click(object sender, EventArgs e) { // PlayList.CutSong(); if (CurrentSong != null) { CurrentSong.playback = PlayBackStatus.Cut; } else { MessageBox.Show("親~已經沒歌了哦~~"); } } //重唱 private void lenago_Click(object sender, EventArgs e) { if (CurrentSong != null) { PlayList.ListenAgain(); } else { MessageBox.Show("親,