简单的实现QQ通信功能(四)
第四部分:主界面的设计及代码
一:效果图及界面设计
1. 效果图:
2. 界面设计:
(1)上面显示自己信息用一个PictureBox和两个Label,用来显示自己的头像和昵称备注名。
(2)下面用了一个FlowLayoutPanel来显示好友列表,FlowDirection设置为TopDown,从上到下流式布局。
(3)下面一个ComboBox用来选择自己的状态。
(4)一个imageList3存放用户头像,根据登录者的头像代号进来选择需要的头像。
(5)一个notifyIcon1来设置任务栏右下角显示小图标。
(6)朋友列表中每一个朋友信息的显示是用了一个自定义控件Friendsmode,专门来加载朋友信息。
(7)Friendsmode里面一个imageList2存放用户头像,imageList2存放用户离线头像,时钟Timer1控制头像抖动,时钟Timer2控制来消息声音,时钟controltx来控制朋友上线和下线的声音及头像变化。
3. 用到的各个控件的名称:
登录者头像metouxiang,登录者昵称menickname,登录者备注名mememoname,用户列表friendlist,右下角修改状态updatastate;
自定义控件Friendsmode,自定义控件里的头像touxiang,自定义控件里的昵称nicheng,自定义控件里的备注名beizhu。
二:代码设计:
1. MainForm里的代码:
//定义个_Uid记住登录者 private string _Uid; //创建adp1是查user表的适配器,下面经常要用,写在了外面。 UsersTableAdapter adp1 = new UsersTableAdapter(); //构造函数 public MainForm() { InitializeComponent(); } //构造函数重载,将登录者记录 public MainForm(string uid) { _Uid = uid; InitializeComponent(); } //加载 private void MainForm_Load(object sender, EventArgs e) { //根据登录者代号去数据库查找朋友 FriendsTableAdapter adp = new FriendsTableAdapter(); qqdata.FriendsDataTable table = new qqdata.FriendsDataTable(); table = adp.GetDataBy(_Uid); //逐个朋友查找出来并显示 foreach (qqdata.FriendsRow row in table.Rows) { qqdata.UsersDataTable tab = new qqdata.UsersDataTable(); tab = adp1.GetDataByUsername(row.FriendName); //造自定义控件,用到了自定义控件的构造函数传参数 Friendsmode friend = new Friendsmode(tab[0].PhotoCode, tab[0].NickName, tab[0].Memo, row.FriendName,_Uid); //将控件添加进主界面 friendlist.Controls.Add(friend); } //调用显示自己信息的方法 loadmeinfo(); //调用加载状态列表的方法 loadState(); } //显示自己的方法 private void loadmeinfo() { qqdata.UsersDataTable tab = new qqdata.UsersDataTable(); tab = adp1.GetDataByUsername(_Uid); metouxiang.Image = imageList3.Images[tab[0].PhotoCode-1]; menickname.Text = tab[0].NickName; mememoname.Text = tab[0].Memo; //加载右下角ico上的文字 notifyIcon1.Text = "QQ:"+tab[0].NickName; } //加载状态列表的方法 private void loadState() { qqdata.UsersDataTable tab = new qqdata.UsersDataTable(); tab = adp1.GetDataByUsername(_Uid); StateTableAdapter adp2 = new StateTableAdapter(); qqdata.StateDataTable tabs = new qqdata.StateDataTable(); tabs = adp2.GetData(); //绑定显示 updatastate.DataSource = tabs; updatastate.DisplayMember = "StateName"; updatastate.ValueMember = "State"; //默认状态设置为数据库内的状态 updatastate.SelectedValue = tab[0].State; } //窗体关闭后状态设置为离线 private void MainForm_FormClosed(object sender, FormClosedEventArgs e) { adp1.UpdateStateByCode(0,_Uid); } //当用户更改状态时将更改的状态传到数据库 private void updatastate_SelectionChangeCommitted(object sender, EventArgs e) { adp1.UpdateStateByCode((Int32)updatastate.SelectedValue, _Uid); } //双击任务栏右下角小图标显示主窗体 private void notifyIcon1_DoubleClick(object sender, EventArgs e) { this.Visible = true; this.WindowState = FormWindowState.Normal; } //最小化的时候隐藏窗体 const int WM_SYSCOMMAND = 0x112; const int SC_CLOSE = 0xF060; const int SC_MINIMIZE = 0xF020; const int SC_MAXIMIZE = 0xF030; protected override void WndProc(ref Message m) { if (m.Msg == WM_SYSCOMMAND) { if (m.WParam.ToInt32() == SC_MINIMIZE) { this.Visible = false; return; } } base.WndProc(ref m); }
2. 自定义控件下的代码:
//定义一个变量、属性来控制头像抖动和声音 private static int n = 0; public static int N { get { return Friendsmode.n; } set { Friendsmode.n = value; } } //定义变量、属性来接收MainForm传过来的自己的名字代号 private string _Mename; public string Mename { get { return _Mename; } set { _Mename = value; } } //定义变量、属性来接收MainForm传过来的朋友的名字代号 private string _Friendname; public string Friendname { get { return _Friendname; } set { _Friendname = value; } } private string _Nickname; private string _Memo; private int _Photo; //默认构造 public Friendsmode() { InitializeComponent(); } //构造函数重载,将头像代号,昵称,备注,朋友代号和自己的代号传过来接收 public Friendsmode(int photo,string nickname,string memo,string friendname,string mename):this() { _Mename = mename; _Friendname = friendname; _Photo = photo-1; _Nickname = nickname; _Memo = memo; } //加载 private void Friendsmode_Load(object sender, EventArgs e) { //加载的时候根据朋友代号查询数据库,如果在线头像显示彩色,如果离线或隐身显示头像灰色 //并将其加载到主界面 UsersTableAdapter adp = new UsersTableAdapter(); qqdata.UsersDataTable tab = adp.GetDataByUsername(_Friendname); if (tab[0].State == 0 || tab[0].State == 9) { touxiang.Image = imageList1.Images[_Photo]; } else { touxiang.Image = imageList2.Images[_Photo]; } nicheng.Text = _Nickname; beizhu.Text = _Memo; } //双击头像进入聊天窗口 private void touxiang_DoubleClick(object sender, EventArgs e) { Chat ch = new Chat(_Friendname, _Mename); ch.Show(); //此朋友的头像抖动在打开此聊天窗口时不可用 timer1.Enabled = false; //设置n为1,用来标识此朋友聊天窗口已打开 n = 1; } //控制头像抖动 int i = 0; private void timer1_Tick(object sender, EventArgs e) { //获取PictureBox当前的位置 int x = touxiang.Location.X; int y = touxiang.Location.Y; if (i == 0) { touxiang.Location = new Point(x + 3, y + 3); } else if (i == 1) { touxiang.Location = new Point(x - 6, y); } else if (i == 2) { touxiang.Location = new Point(x + 3, y - 3); } i++; if (i >= 3) { i = 0; } } //记录朋友最后发送时间,用来区别新的未读消息 DateTime tabx ; //控制来新消息的头像抖动和声音提示的时钟 private void timer2_Tick(object sender, EventArgs e) { //去数据库查询发送者是该朋友的接受者是自己的,状态未读的消息 ChatTableAdapter adp = new ChatTableAdapter(); qqdata.ChatDataTable tab = adp.GetDataBySenderAndReceiver(_Friendname, _Mename, 0); //判断如果查出来了,而且最后一条的发送时间与上次的不一样,且聊天窗口未打开时头像抖动和声音提示。 if (tab.Count > 0 && tab[tab.Count-1].Time != tabx && n==0) { timer1.Enabled = true; tabx =tab[tab.Count-1].Time;
//播放声音 string sound = Application.StartupPath + "/sound/msg.wav"; //Application.StartupPath:程序exe所在的位置 SoundPlayer player = new SoundPlayer(sound); player.Load(); //把声音加载到内存 //player.PlayLooping();//播放 player.Play(); } } //定义变量用来控制上线时声音只响一次 int sx = 0; //控制在线头像变化和声音 private void controltx_Tick(object sender, EventArgs e) { UsersTableAdapter adp = new UsersTableAdapter(); qqdata.UsersDataTable tab = adp.GetDataByUsername(_Friendname); if (tab[0].State == 0 || tab[0].State == 9) { touxiang.Image = imageList1.Images[_Photo]; sx = 0; } else { if (sx == 0) { touxiang.Image = imageList2.Images[_Photo]; sx = 1; string sound = Application.StartupPath + "/sound/Global.wav"; //Application.StartupPath:程序exe所在的位置 SoundPlayer player = new SoundPlayer(sound); player.Load(); //把声音加载到内存 //player.PlayLooping();//播放 player.Play(); } } }