MyKTV项目,走起!

第一部分:这个项目对于新手来说有一点难度,但是当你理清类之间的关系和怎样去实现功能后就会感觉轻松很多。

话不多说,先上类图:

接着是数据库表间关系:

本项目要实现以下功能:

  1. 明星点歌
  2. 拼音点歌
  3. 类型选择
  4. 金榜排行
  5. 字数点歌

一共五大块,那么明星点歌下还有一个播放的功能。

在主页面有一个正在播放和下一首的提示功能。

这是ktv主页面:

在下边还有重唱,切歌,已点,服务和退出功能

相信大家都去过KTV,所以这些功能就不说了,比我都清楚!

这里我把播放控件放在了主页面,位置随意,放在哪都行,也可以单独开一个窗体进行播放。

点击明星点歌进入到明星点歌页面:

组合,女歌手和男歌手都放在listView中,这里要注意的是在这一个窗体中一共有三个listView,先在窗体中隐藏后两个,

那么点击第一个进入到第二个时要把第一个listView隐藏。

隐藏listView只需把它的Visible属性设置成false就ok了:

             lvCountry.Visible = false;
lvSinger.Visible = false;

第二个listView就是供用户一个更精确的选择歌曲或歌手了:

第三个listView就是显示歌手对应的图片:

这个图片要从数据库中取,不能写死,还有很多功能,像金榜排行,都不能写死。

再次点击就进入播放列表:

刷新歌曲列表代码:

         /// <summary>
/// 刷新歌曲列表
/// </summary>
private void RefreshSongList()
{
lvSongList.Items.Clear(); // 清空原列表
int i = ;
while (PlayList.SongList[i] != null)
{
ListViewItem item = new ListViewItem();
item.Text = PlayList.SongList[i].SongName;
item.Tag = i;
string playState = PlayList.SongList[i].PlayState== SongPlayState.unplayed?"未播放":"已播放";
item.SubItems.Add(playState);
lvSongList.Items.Add(item);
i++;
}
}

明星点歌代码:

      string singertype = "组合";
int singertypid = ;      /// <summary>
/// 第一层listView
/// </summary>
public void LoadSingerArea()
{
if (lvType.SelectedItems[]!=null)
{
lvType.Visible = false;
lvCountry.Visible = true;
lvCountry.Location = lvType.Location;
lvCountry.Dock = DockStyle.Fill;
this.singertype = Convert.ToString(lvType.SelectedItems[].Text);
}
string sql = "select singertype_id,singertype_name from singer_type";
SqlCommand cmd = new SqlCommand(sql,db.Connection );
try
{
db.OpenConnection();
SqlDataReader dr = cmd.ExecuteReader();
lvCountry.Items.Clear();
if (dr.HasRows)
{
int index = ;
while (dr.Read())
{
ListViewItem lvitem = new ListViewItem();
int typeid = Convert.ToInt32(dr["singertype_id"]);
string typename = Convert.ToString(dr["singertype_name"]);
lvitem.Text = typename;
lvitem.Tag = typeid;
lvitem.ImageIndex = index;
lvCountry.Items.Add(lvitem);
index++;
}
}
dr.Close();
}
catch (Exception ex)
{ MessageBox.Show(ex.Message);
}
finally
{
db.CloseConnection();
}
}
/// <summary>
/// 第二层listView
/// </summary>
public void LoadSingerName()
{
if (lvCountry.SelectedItems[]!=null)
{
//隐藏歌手地区,显示歌手的姓名
lvCountry.Visible = false;
lvSinger.Visible = true;
lvSinger.Location = lvCountry.Location;
singertypid = Convert.ToInt32(lvCountry.SelectedItems[].Tag);
StringBuilder sql = new StringBuilder();
string result = singertype;
if (result!="组合")
{
result = singertype == "女歌手" ? "女" : "男";
}
sql.AppendFormat("select singe_id,singer_name,singer_photo_url from Singer_info where singertype_id={0}and singer_gemder='{1}'",singertypid,result);
SqlCommand cmd = new SqlCommand(sql.ToString(), db.Connection);
try
{
db.OpenConnection();
SqlDataReader dr = cmd.ExecuteReader();
int imageIndex = ; //代表歌手头像的索引
imageList1.Images.Clear();
lvSinger.Items.Clear();
if (dr.HasRows)
{
while (dr.Read())
{
string photoURL = KTVUtil.singerPhotoPath + "\\" + Convert.ToString(dr["singer_photo_url"]);
imageList1.Images.Add(Image.FromFile(photoURL));
ListViewItem item = new ListViewItem();
item.Text = Convert.ToString(dr["singer_name"]);
item.Tag = Convert.ToString(dr["singer_id"]);
item.ImageIndex = imageIndex;
lvSinger.Items.Add(item);
imageIndex++;
}
}
dr.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
db.CloseConnection();
}
}
} private void tsplMenu_Click(object sender, EventArgs e)
{
MainForm mf = new MainForm();
mf.Show();
this.Close(); }
/// <summary>
/// 第三层listView
/// </summary>
public void SongList()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("select song_id,song_name, singer_name='{0}',song_url from SongInfo,Singer_Info where singer_id={1}",
lvSinger.SelectedItems[].Text, Convert.ToInt32(lvSinger.SelectedItems[].Tag)); SongListForm songList = new SongListForm();
songList.Sql = sb.ToString();
songList.Show();
this.Close();
}

之后一定要在listView的Click事件中调用方法:

      private void lvType_Click(object sender, EventArgs e)
{
LoadSingerArea();
} private void lvSinger_Click(object sender, EventArgs e)
{
SongList();
} private void lvCountry_Click(object sender, EventArgs e)
{
LoadSingerName();
}

播放过程:

当选中某首歌曲后,点击一下,那么就会将各个列的值拼接成一个Song对象,

 Song song=new Song();
song.songName="值";
song.songUrl="地址";

歌曲列表中数据来源于数据库!所以我们要将喜欢的歌曲添加到数据库中!

当我们点击已点的时候就会循环遍历数组,然后每遍历一项,就会创建一个 ListViewItem对象。

刚才忘了说了,每个页面下面的菜单我用的是ToolStrip控件。

接下来是拼音点歌

拼音点歌相对来说就简单多了,就是一个模糊查询,页面如下:

拼音点歌部分代码:

         // 查询歌曲显示在窗体中
private void btnSearch_Click(object sender, EventArgs e)
{
DBHelper dbHelper = new DBHelper();
DataSet dataSet = new DataSet();
StringBuilder sb = new StringBuilder();
sb.Append("select song_id,song_name,singer_name,song_url from song_info inner join singer_info on singer_info.singer_id=song_info.singer_id ");
sb.AppendFormat("where song_name like '%{0}%' or song_ab like '{0}'",this.txtSongName.Text); Console.WriteLine(sb.ToString()); SqlDataAdapter adapter = new SqlDataAdapter(sb.ToString(), dbHelper.Connection); // 清空当前列表
if (dataSet.Tables["songList"] != null)
{
dataSet.Tables["songList"].Clear();
} adapter.Fill(dataSet, "songList");
this.dgvSong.DataSource = dataSet.Tables["songList"];
}

类型点歌:

这个和酷狗里的如下页面功能类似:

点击某一个项进入到相应的歌曲页面,部分代码如下:

  // 窗体加载时,显示歌曲类别
private void OrderBySongTypeForm_Load(object sender, EventArgs e)
{
// 读取歌曲类别
DBHelper dbHelper = new DBHelper();
string sql = "select * from song_type";
try
{
// 查询数据库
SqlCommand command = new SqlCommand(sql, dbHelper.Connection);
dbHelper.OpenConnection();
SqlDataReader reader = command.ExecuteReader(); // 循环将类别读取出来添加到ListView中
this.lvSongType.Items.Clear();
int i = ;
while (reader.Read())
{
ListViewItem item = new ListViewItem();
item.Text = Convert.ToString(reader["songtype_name"]);
item.Tag = Convert.ToInt32(reader["songtype_id"]);
item.ImageIndex = i;
this.lvSongType.Items.Add(item);
i++;
}
reader.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
MessageBox.Show("系统错误,请联系服务人员!"); }
finally
{
dbHelper.CloseConnection();
}
}

金榜排行和字数点歌大家可以尝试着写一下,都不难!字数点歌这里要注意一下:

上边的那12个Label不是拖12个Label控件,而是利用二重数组进行控制Label的:

         for (int i = ; i <= ; i++)//行数
{
for (int j = ; j <= ; j++)
{
Label label = new Label();
label.Text = i+"-"+j;
//自身大小(重点)
label.Size = new Size(, );
//背景颜色
label.BackColor = Color.Yellow;
//相对于窗体0,0点的位置
label.Location = new Point(+*j, +*i);
//文本居中
label.TextAlign = ContentAlignment.MiddleCenter;
//字体大小
label.Font=new Font("Bradley Hand ITC",20); //触发Click事件
label.Click += label_Click;
//让Label对象归属于当前窗体
this.Controls.Add(label);
}
} } void label_MouseMove(object sender, MouseEventArgs e)
{
this.Text = e.X + "," + e.Y;
} void label_Click(object sender, EventArgs e)
{
Label label = (Label)sender; MessageBox.Show(label.Text); } private void Form1_MouseMove(object sender, MouseEventArgs e)
{
this.Text = e.X + "," + e.Y;
}

要记住:每一个控件都是一个类。

第二部分:

部分关键代码如下:

1.重唱:

 // 重新播放当前歌曲
private void tsbtnAgain_Click(object sender, EventArgs e)
{
PlayList.PlayAgain();
}

就是调用PlayList中的PlayAgain()方法。PlayList类我会在下面给出。

2.切歌:

         // 切歌
private void tsbtnCut_Click(object sender, EventArgs e)
{
if (MessageBox.Show("确定要切歌吗?", "操作提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK)
{
int songId = -; // 切歌的编号
if (this.lvSongList.SelectedItems.Count > )
{
songId = Convert.ToInt32(this.lvSongList.SelectedItems[].Tag);
}
PlayList.CutSong(songId);
this.RefreshSongList();
}
}

3.播放:

         private Song song;//当前播放的歌曲
//播放歌曲
private void PlaySong()
{
this.song = PlayList.GetPlaySong();//获取当前播放的歌曲
if (song != null)
{
this.song.SetSongPlayed();//已播放
//D:\song\恋爱新手.mp3
Player1.URL = KTVUtil.songPath + "\\" + this.song.SongURL;//得到当前播放歌曲的路径
txtNext.Text = this.song.SongName;
}
}

4.PlayList类:

 /// <summary>
/// 播放列表管理
/// </summary>
class PlayList
{
private static Song[] songList = new Song[]; // 歌曲播放列表数组
private static int songIndex = ; // 当前播放的歌曲在数组中的索引 /// <summary>
/// 播放列表数组
/// </summary>
public static Song[] SongList
{
get { return PlayList.songList; }
} /// <summary>
/// 当前播放歌曲的索引
/// </summary>
public static int SongIndex
{
get { return PlayList.songIndex; }
} /// <summary>
/// 当前播放的歌曲名称
/// </summary>
/// <returns>歌曲名称</returns>
public static string PlayingSongName()
{
string songName = ""; // 歌曲名称
if (SongList[SongIndex] != null)
{
songName = SongList[SongIndex].SongName;
} return songName;
} /// <summary>
/// 获取当前播放的歌曲
/// </summary>
/// <returns>当前要播放的歌曲</returns>
public static Song GetPlayingSong()
{
if (SongList[songIndex] != null)
{
return SongList[songIndex];
}
else
{
return null;
}
} /// <summary>
/// 下一首要播放的歌曲名称
/// </summary>
/// <returns>歌曲名称</returns>
public static string NextSongName()
{
string songName = ""; // 歌曲名称
if (SongList[SongIndex+] != null)
{
songName = SongList[SongIndex+].SongName;
} return songName;
} /// <summary>
/// 点播一首歌曲
/// </summary>
/// <param name="song">新点播的歌曲</param>
public static bool AddSong(Song song)
{
bool success = false;
for (int i = ; i < SongList.Length; i++)
{
if (SongList[i] == null)
{
SongList[i] = song;
Console.WriteLine(song.SongName);
success = true;
break;
}
} return success;
} /// <summary>
/// 切歌
/// </summary>
/// <param name="index">要切歌曲的编号,如果是切当前播放的歌曲传入-1</param>
public static void CutSong(int index)
{
int i; // 循环变量,代表切歌的位置
if (index == -)
{
i = SongIndex;
}
else
{
i = index; // 从切歌的位置开始,将歌曲逐个向前移一个位置
} SongList[i].SetSongCut();
while (SongList[i] != null)
{
SongList[i] = SongList[i + ];
i++; // 如果到达数组最后一个元素,就将最后一个元素指向空
if (i == SongList.Length)
{
SongList[i] = null;
}
}
} /// <summary>
/// 重放当前歌曲
/// </summary>
public static void PlayAgain()
{
if (SongList[songIndex] != null)
{
SongList[songIndex].SetPlayAgain();
}
} /// <summary>
/// 播放下一首
/// </summary>
public static void MoveOn()
{
if (SongList[songIndex] != null && SongList[songIndex].PlayState == SongPlayState.again)
{
SongList[songIndex].SetSongPlayed();
}
else
{
songIndex++;
}
}
}

5.Song类:

     enum SongPlayState
{
unplayed,played,again,cut
} /// <summary>
/// 歌曲类
/// </summary>
class Song
{
/// <summary>
/// 歌曲名称
/// </summary>
public string SongName
{
get { return songName; }
set { songName = value; }
} /// <summary>
/// 歌曲存放路径
/// </summary>
public string SongURL
{
get { return songURL; }
set { songURL = value; }
} /// <summary>
/// 歌曲播放状态
/// </summary>
internal SongPlayState PlayState
{
get { return playState; }
set { playState = value; }
} private string songName;
private string songURL;
private SongPlayState playState = SongPlayState.unplayed; // 歌曲播放状态 /// <summary>
/// 将歌曲状态改为已播放
/// </summary>
public void SetSongPlayed()
{
this.playState = SongPlayState.played;
} /// <summary>
/// 将歌曲状态改为再拨放一次
/// </summary>
public void SetPlayAgain()
{
this.playState = SongPlayState.again;
} /// <summary>
/// 将歌曲状态改为切歌
/// </summary>
public void SetSongCut()
{
this.playState = SongPlayState.cut;
}
}

6.KTVUtil类:

这里主要存的就是路径

         public static string singerPhotoPath = "";  // 歌手照片路径
public static string songPath = ""; // 歌曲路径

7.SongList类:

 public enum PalySongState
{
//未播放 , 播放, 重播,切歌
unplayed,played,again,cut
}
/// <summary>
/// 歌曲播放类
/// </summary>
public class SongList
{
//歌曲名称
private string SongName;
//歌曲路径
private string SongUl;
//歌曲状态
private string SongState; public string SongState1
{
get { return SongState; }
set { SongState = value; }
} public string SongUl1
{
get { return SongUl; }
set { SongUl = value; }
} public string SongName1
{
get { return SongName; }
set { SongName = value; }
} //把当前的播放状态设置为未播放状态
private PalySongState playSong = PalySongState.unplayed; public PalySongState PlaySong
{
get { return playSong; }
set { playSong = value; }
}
/// <summary>
/// 将未播放状态改为播放状态
/// </summary>
public void PalyState()
{
this.PlaySong = PalySongState.played;
}
/// <summary>
/// 将歌曲重新播放
/// </summary>
public void AgainState()
{
this.PlaySong = PalySongState.again;
}
/// <summary>
/// 切歌状态
/// </summary>
public void CutState()
{
this.PlaySong = PalySongState.cut;
}
}

那么以上就是本次的KTV项目了,这个只是前台,那么大家也可以写一个后台进行管理和维护前台,通过数据库就可以

把前台和后台连在一起。

MyKTV项目,走起!的更多相关文章

  1. MyKTV项目总结

    今天和大伙分享一下我的KTV系统,我想大家都有自己独特的魅力,都有自己的风采,都有自己骄傲的一部分. 在这里我就抛砖引玉,聊聊我的KTV项目,希望大家能给出自己的建议.. 首先,我们先了解一下:当我们 ...

  2. C#Windows窗体应用程序MyKTV项目

    后台管理其中有一个添加歌手信息和歌曲信息的窗体要点击按钮并上传文件,因为对那些文件流什么的不懂,所以用了老师教的最简单的判断方法,但此方法只是按后缀名判断文件的样式,如果后缀名乱改就不行了! 此时需要 ...

  3. 一个P2P点播直播开源项目:P2PCenter

    最近跟着公司的项目走,我也研究了不少东西,尤其是在P2P方面,广泛涉猎各种开源项目,尤其是国外的开源项目,意外的发现了一个国内的项目,做的还不错,推荐一下.---------------------使 ...

  4. VS2013 MVC Web项目使用内置的IISExpress支持局域网内部机器(手机、PC)访问、调试

    VS2013内置了IISExpress.做asp.net MVC的web项目开发时,Ctrl+F5和F5启动项目运行(后者是调试模式)的同时都会打开IISExpress,事实上本机对该web项目走的就 ...

  5. 【转并修改】VS2013 MVC Web项目使用内置的IISExpress支持局域网内部机器(手机、PC)访问、调试

    转:http://www.cnblogs.com/ShaYeBlog/p/4072074.html VS2013内置了IISExpress.做asp.net MVC的web项目开发时,Ctrl+F5和 ...

  6. 迈向angularjs2系列(8):angular cli和angular2种子项目

    文章目录 1.angular cli快速搭建项目 2.angular2-seed 3.手动配置 题外话:如何更好的阅读本篇文章 一: angular cli的安装 Angular-cli(命令行界面, ...

  7. 手把手教你从零开始搭建SpringBoot后端项目框架

    原料 新鲜的IntelliJ IDEA.一双手.以及电脑一台. 搭建框架 新建项目 打开IDE,点击File -> New Project.在左侧的列表中的选择Maven项目,点击Next. 填 ...

  8. 转一篇做BI项目的好文

    首先,我们有一个大的假设前提,集团报表平台是服务于大型公司,比如有很多分公司,子公司,多部门等,并且有BI需求的访问人群超过1000以上的公司. 这样,我们的关键词是:集团 平台 运营 集团:意味着, ...

  9. maven 项目加载本地JAR

     将jar安装到本地的maven仓库 1.首先确定本地有maven环境. 2.安装本地jar 模板: mvn install:install-file -Dfile=<path-to-file& ...

随机推荐

  1. Linux系统配置成简单的路由器

    一.两个不同网段的子网相互访问或通信 废话不多说了,直接上图,一目了然吧. 按照如图配置,就可以实现两个不同网段的子网相互通信. 二.连接上网的配置: 如果想让这两个子网,不仅可以相互通信,而且还可以 ...

  2. 深入浅出理解QTimeLine类

    网上找了下QTimeLIne类的介绍,要么就是代码一贴自己看去,要么就是说不到重点,正巧自己项目遇到这个类,在这里写一下,给需要的同学看下. 因为我最近需要有动画方面配合时间间隔触发QGraphics ...

  3. chromedriver 与 chrome关联关系

    ----------ChromeDriver v2.22 (2016-06-06)---------- Supports Chrome v49-52 Resolved issue 1348: Time ...

  4. winform 剔除空格与换行显示

    string strTeachingPlan = this.txtTeachingPlan.Text.ToString().Trim();  string[] maarr = strTeachingP ...

  5. maven3.0

    Maven入门教程 1.1. 介绍.环境配置 1.1.1. Maven介绍 Maven是一个采用纯Java编写的开源项目管理工具, Maven采用了一种被称之为Project Object Model ...

  6. iOS项目管理:目录结构和开发流程

    iOS项目管理:目录结构和开发流程     最近正在做一个大版本的更新,现在在重构中.... 发现很多人在一个项目的开始不知道开发流程是什么,也不是非常清晰的知道一个项目该有目录结构.如果项目小或者是 ...

  7. 使用putty登陆cygwin出现server unexpectedly ...error.解决方案

    将cygwin安装目录下/etc/passwd中的passwd文件中user:unused:32707:10513:U-CYOU-INC\user,S-1-5-21-2645613570-259884 ...

  8. grunt serve Fatal error: Port 35729 is already in use by another process.

    y@y:~$ lsof | grunt y 0t0 TCP *: (LISTEN) Optimizin y 0t0 TCP *: (LISTEN) v8:Sweepe y 0t0 TCP *: (LI ...

  9. 台积电16nm工艺为什么好过三星14nm

    最近,关于iPhone6s A9处理器版本的事情的话题很热,最后都闹到苹果不得不出来解释的地步,先不评判苹果一再强调的整机综合续航差2~3%的准确性,但是三星14nm工艺相比台积电16nm工艺较差已经 ...

  10. POJ1321 棋盘问题(dfs)

    题目链接. 分析: 用 dfs 一行一行的搜索,col记录当前列是否已经放置. AC代码如下: #include <iostream> #include <cstdio> #i ...