上一篇文章分析了如何利用socket通訊,并用示例程序演示了通訊過程,那么今天我們就開始按照用戶使用步驟逐漸完善CIM項目。
首先,我們打開CIM項目,熟悉一下項目目錄。下圖是項目列表,共有六個windows窗體。
注冊、登錄等功能需要進行數據庫操作,因此,我們需要封裝一個操作數據庫的工具類,以便更方便調用。新建一個SqlHelper.cs類,然后對目錄結構進行簡單的修改,如下圖:
接著我們在SqlHelper類中對數據庫操作進行封裝。將SqlHelper類中的方法全部寫成靜態,這樣使用的時候直接用類名就可以調用,非常方便。我們根據CIM項目的實際需求進行方法的封裝。因為現在還沒有涉及到具體的業務邏輯,所以我們先封裝兩個通用的方法。
首先需要定義一個連接字符串:
public static string connectionString="server=.;database=CIM;uid=sa;pwd=123456";
注意登錄SQLServer數據庫的用戶名和密碼,這里需要根據你的實際情況填寫。
通用讀取方法:
///
/// 根據sql語句讀取數據
///
/// sql語句
/// sqldatareader
public static SqlDataReader ExecuteReader(string strSQL)
{
SqlConnection connection=new SqlConnection(connectionString);
SqlCommand cmd=new SqlCommand(strSQL, connection);
try
{
connection.Open();
SqlDataReader myReader=cmd.ExecuteReader(CommandBehavior.CloseConnection);
return myReader;
}
catch (SqlException e)
{
throw e;
}
}
通用執行sql語句方法,用于增、刪、改:
///
/// 執行sql插入、刪除、修改語句
///
///
/// 影響記錄的行數
public static int ExecuteSql(string SQLString)
{
using (SqlConnection connection=new SqlConnection(connectionString))
{
using (SqlCommand cmd=new SqlCommand(SQLString, connection))
{
try
{
connection.Open();
int rows=cmd.ExecuteNonQuery();
return rows;
}
catch (SqlException e)
{
connection.Close();
throw e;
}
}
}
}
目前只寫這兩個方法就行了。后面如果用到更復雜的再繼續添加即可。
實現注冊功能
封裝好數據庫操作類,我們開始實現注冊和登錄操作。
1.注冊按鈕的點擊事件中實現新用戶注冊
private void btn_register_Click(object sender, EventArgs e)
{
//簡單的數據驗證
if(tb_nickName.Text==""||tb_pwd1.Text=="" || tb_pwd2.Text=="")
{
MessageBox.Show("請將注冊信息填寫完整!");
return;
}
if(tb_pwd1.Text !=tb_pwd2.Text)
{
MessageBox.Show("密碼不一致!");
return;
}
//隨機分配CIM賬號
string register_account=getRandomAccount();
//向Users表中新增數據
int len=SqlHelper.ExecuteSql("insert into Users (Account,Password,Nickname) values
('"+register_account+"','"+tb_pwd1.Text+"','"+tb_nickName.Text+"')");
if(len > 0)
{
MessageBox.Show("注冊成功!CIM賬號為:"+register_account+",請牢記此賬號!");
//注冊成功后返回到登錄界面
tb_Account.Text=register_account;
panel1.Visible=false;
}
else
{
MessageBox.Show("注冊失敗!請重試");
}
}
///
/// 隨機生成8位賬號
///
///
private string getRandomAccount()
{
int account;
//do-while循環驗證生成的賬號是否已經存在
//如果存在就重新隨機生成
do
{
Random r=new Random(int.Parse(DateTime.Now.ToString("HHmmssfff")));
//限制生成的賬號為8位數
account=r.Next(00000000, 99999999);
} while (ExitAccount(account));
return account.ToString();
}
///
/// 驗證是否已經存在該賬號
///
///
///
private bool ExitAccount(int account)
{
SqlDataReader sdr=SqlHelper.ExecuteReader("select * from Users where Account='"+account+"'");
if (sdr.Read())
{
sdr.Close();
return true;
}
else
{
sdr.Close();
return false;
}
}
注意代碼中的TextBox控件的Name屬性已經修改。可以看到,使用了SqlHelper類進行數據庫操作就很簡單了。
實現登錄功能
注冊成功后,點擊“確定”將從注冊界面切換到登錄界面。
1.登錄按鈕的點擊事件
///
/// 登錄按鈕的點擊事件
///
///
///
private void button1_Click(object sender, EventArgs e)
{
//簡單的數據驗證
if (tb_Account.Text==""|| tb_pwd.Text=="")
{
MessageBox.Show("請正確填寫賬號和密碼!");
return;
}
//判斷賬號是否存在
if (ExitAccount(int.Parse(tb_Account.Text))){
//判斷密碼是否正確
if (pwdIsOk(tb_Account.Text,tb_pwd.Text))
{
//隱藏該窗體
this.Visible=false;
//new出主界面
new Major().Show();
}
else
{
MessageBox.Show("密碼不正確!");
}
}
else
{
MessageBox.Show("賬號不存在");
}
}
///
/// 驗證密碼是否正確
///
///
///
///
private bool pwdIsOk(string account,string pwd)
{
SqlDataReader sdr=SqlHelper.ExecuteReader("select * from Users where account
='"+account+"' and password='"+pwd+"'");
if (sdr.Read())
{
sdr.Close();
return true;
}
else
{
sdr.Close();
return false;
}
}
到目前為止就可以實現注冊和登錄了。
接下來實現一個記住密碼的小功能。
記住密碼功能實現
1.在登錄成功之前,用文件記錄賬號和密碼
if (checkBox1.Checked==true)
{
if (!File.Exists(userinfopath))
{
File.Create(userinfopath).Close();
File.WriteAllLines(userinfopath, new string[] { tb_Account.Text,tb_pwd.Text } );
}
else
{
File.Delete(userinfopath);
File.Create(userinfopath).Close();
File.WriteAllLines(userinfopath, new string[] { tb_Account.Text, tb_pwd.Text });
}
}
else
{
if (!File.Exists(userinfopath))
{
File.Create(userinfopath).Close();
File.WriteAllLines(userinfopath, new string[] { tb_Account.Text, "" });
}
else
{
File.Delete(userinfopath);
File.Create(userinfopath).Close();
File.WriteAllLines(userinfopath, new string[] { tb_Account.Text, "" });
}
}
this.Visible=false;
new Major().Show();
2.需要添加一個userinfopath字段:
string userinfopath="user.ini";
3.窗體加載事件回顯用戶名和密碼
if (!File.Exists(userinfopath))
{
}
else
{
string[] data=File.ReadAllLines(userinfopath);
tb_Account.Text=data[0];
tb_pwd.Text=data[1];
checkBox1.Checked=true;
if(data[1]=="")
{
checkBox1.Checked=false;
}
}
這里的checkBox1就是設計界面上的記住密碼CheckBox控件。到這里就能夠實現記住密碼操作了。
好了,本篇文章內容就到這里。下一篇文章將制作服務端程序,并對登錄操作添加連接服務端程序的代碼。
本文系小博客網站原創,轉載請注明文章鏈接地址
上一篇文章,我們搭建好了主界面的布局。本文將實現頁面的交互邏輯,比如如何移動窗體、調整窗體大小、點擊消息和聯系人切換下方的panel面板、動態加載消息列表panel和好友列表panel等,并且左下角的按鈕改成了添加好友的入口。
移動窗體
因為設置FormBorderStyle屬性為None,所以目前無法移動窗體,要通過代碼的方式移動。
鼠標按住窗體上部分移動窗體
要實現這個效果,需要使用上面面板splitContainer1_Panel1的三個事件:MouseDown、MouseMove、MouseUp。具體實現過程:
1.定義兩個本地變量
private Point mousepoint;//鼠標的位置
private bool mouseflag=false;//鼠標是否按下的標志
2.實現三個事件
private void splitContainer1_Panel1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button==MouseButtons.Left)
{
mousepoint.X=e.X;
mousepoint.Y=e.Y;
mouseflag=true;
}
}
private void splitContainer1_Panel1_MouseMove(object sender, MouseEventArgs e)
{
if (mouseflag)
{
this.Left=MousePosition.X - mousepoint.X;
this.Top=MousePosition.Y - mousepoint.Y;
}
}private void splitContainer1_Panel1_MouseUp(object sender, MouseEventArgs e)
{
mouseflag=false;
}這樣就可以實現按住上部分移動窗體。
調整窗體大小
通過對窗體邊緣進行判斷,配合鼠標事件,可以完成調整窗體大小的操作。注意,此時窗體的padding值為6。此法也是參考網友的方法,并進行了優化。下面便是放大的窗體效果:
調整Major窗體大小
第一步,定義枚舉,表示拖動方向
public enum MouseDirection { Herizontal,//水平方向拖動,只改變窗體的寬度 Vertical,//垂直方向拖動,只改變窗體的高度 Declining,//傾斜方向,同時改變窗體的寬度和高度 None//不做標志,即不拖動窗體改變大小 }
第二步,添加四個全局變量
bool isMouseDown=false; //表示鼠標當前是否處于按下狀態,初始值為否
MouseDirection direction=MouseDirection.None;//表示拖動的方向,起始為None,表示不拖動
Point mouseOff;//鼠標移動位置變量
bool declinning=false;//寬高同時拖動時的標志
第三步,鼠標按下事件
private void Major_MouseDown(object sender, MouseEventArgs e)
{
mouseOff=new Point(-e.X, -e.Y); //記錄鼠標位置
//當鼠標的位置處于邊緣時,允許進行改變大小。
if (e.Location.X >=this.Width - 10 && e.Location.Y > this.Height - 10)
{
isMouseDown=true;
}
else if (e.Location.X >=this.Width - 10)
{
isMouseDown=true;
}
else if (e.Location.Y >=this.Height - 10)
{
isMouseDown=true;
}
else
{
this.Cursor=Cursors.Arrow;//改變鼠標樣式為原樣
isMouseDown=false;
}
}
第四步:鼠標移動事件
private void Major_MouseMove(object sender, MouseEventArgs e)
{
//鼠標移動到邊緣,改變鼠標的圖標
if (e.Location.X >=this.Width - 2 && declinning==false)
{
this.Cursor=Cursors.SizeWE;
direction=MouseDirection.Herizontal;
}
else if (e.Location.Y >=this.Height - 2 && declinning==false)
{
this.Cursor=Cursors.SizeNS;
direction=MouseDirection.Vertical;
}
else
{
this.Cursor=Cursors.Arrow;
}
if (e.Location.X >=this.Width-10&& e.Location.Y >=this.Height - 4)
{
this.Cursor=Cursors.SizeNWSE;
direction=MouseDirection.Declining;
declinning=true;
}
else
{
declinning=false;
}
//設定好方向后,調用下面方法,改變窗體大小
ResizeWindow();
}
private void ResizeWindow()
{
if (!isMouseDown)
return;
if (direction==MouseDirection.Herizontal)
{
this.Cursor=Cursors.SizeWE;
this.Width=MousePosition.X - this.Left + 1;//改變寬度
}
else if (direction==MouseDirection.Vertical)
{
this.Cursor=Cursors.SizeNS;
this.Height=MousePosition.Y - this.Top + 1;//改變高度
}else if(direction==MouseDirection.Declining)
{
this.Cursor=Cursors.SizeNWSE;
this.Width=MousePosition.X - this.Left + 1;//改變寬度
this.Height=MousePosition.Y - this.Top + 1;//改變高度
}
//鼠標不在窗口右和下邊緣,把鼠標變回小箭頭
else
{
this.Cursor=Cursors.Arrow;
isMouseDown=false;
}
}
第五步,鼠標松開事件
private void Major_MouseUp(object sender, MouseEventArgs e)
{
isMouseDown=false;
declinning=false;
direction=MouseDirection.None;
if (isMouseDown)
isMouseDown=false;
}
根據這五步,就可以實現窗體大小的調整,再配合設置窗體的寬度、高度限制,可以滿足CIM主窗體的需求。
切換消息和聯系人面板
實現消息和聯系人label的點擊事件,配合下方panel的visible屬性就可以實現。重要的是下面的動態加載一個個會話panel和一個個聯系人panel。
切換兩個大panel
注意我的代碼里都已經給控件改了Name屬性的值了。比如會話列表的大panel改成了leftPanel。
1.消息panel的點擊事件
private void changeLeftButton_Click(object sender, EventArgs e)
{
//打開左邊panel,關閉右邊panel
leftPanel.Visible=true;
rightPanel.Visible=false;
//改變下方指示線的顏色
left_line.BackColor=Color.YellowGreen;
right_line.BackColor=Color.Transparent;
}
2.聯系人panel的點擊事件
private void changeRightButton_Click(object sender, EventArgs e)
{
//打開右邊panel,關閉左邊panel
leftPanel.Visible=false;
rightPanel.Visible=true;
//改變下方指示線的顏色
left_line.BackColor=Color.Transparent;
right_line.BackColor=Color.YellowGreen;
}
動態加載控件
因為一個會話列表就是一個小的panel,上面有多個控件,所以需要動態加載它們,并放到外層的大panel中顯示。
動態加載會話小panel
我們在窗體的load事件中模擬加載100個會話
private void Major_Load(object sender, EventArgs e)
{
for (int i=0; i < 100; i++)
{
loadtalk(i,loadTalkMessageList());
}
}
///
/// 填充會話列表對象到list
///
///
private List loadTalkMessageList()
{
return null;
}
///
/// 加載會話列表
///
/// 會話列表的個數
/// 會話列表實體對象list
private void loadtalk(int talknum,List talkMessage)
{
//模擬加載會話列表
Panel talkPanel=new Panel();
talkPanel.Anchor=((AnchorStyles.Top | AnchorStyles.Left)
| AnchorStyles.Right);
talkPanel.Size=new Size(346, 58);
talkPanel.Location=new Point(3, talknum*58);
talkPanel.MouseEnter +=TalkPanel_MouseEnter;
talkPanel.MouseLeave +=TalkPanel_MouseLeave;
//頭像
PictureBox pb=new PictureBox();
pb.Size=new Size(35, 35);
pb.Location=new Point(8, 11);
pb.Image=Properties.Resources.知了;
pb.SizeMode=PictureBoxSizeMode.StretchImage;
pb.MouseEnter +=TalkPanel_MouseEnter;
pb.MouseLeave +=TalkPanel_MouseLeave;
talkPanel.Controls.Add(pb);
//昵稱
Label nickname=new Label();
nickname.AutoSize=true;
nickname.Font=new Font("微軟雅黑", 12F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(134)));
nickname.Location=new Point(56, 10);
nickname.Text="小龍蝦";
nickname.MouseEnter +=TalkPanel_MouseEnter;
nickname.MouseLeave +=TalkPanel_MouseLeave;
talkPanel.Controls.Add(nickname);
//消息
Label message=new Label();
message.AutoSize=true;
message.ForeColor=SystemColors.ControlDarkDark;
message.Location=new Point(58, 34);
message.Size=new Size(277, 15);
message.Text="上課了好呀";
message.MouseEnter +=TalkPanel_MouseEnter;
message.MouseLeave +=TalkPanel_MouseLeave;
talkPanel.Controls.Add(message);
//時間
Label time=new Label();
time.Anchor=((AnchorStyles)((AnchorStyles.Top | AnchorStyles.Right)));
time.AutoSize=true;
time.ForeColor=SystemColors.ControlDarkDark;
time.Location=new Point(220, 11);
if (talknum > 5)
{
time.Location=new Point(204, 11);
}
time.Text="18:48";
time.MouseEnter +=TalkPanel_MouseEnter;
time.MouseLeave +=TalkPanel_MouseLeave;
talkPanel.Controls.Add(time);
leftPanel.Controls.Add(talkPanel);
}
private void TalkPanel_MouseLeave(object sender, EventArgs e)
{
if (sender is Panel)
{
((Panel)sender).BackColor=Color.Transparent;
}
else
{
((Control)sender).Parent.BackColor=Color.Transparent;
}
}
private void TalkPanel_MouseEnter(object sender, EventArgs e)
{
if(sender is Panel)
{
((Panel)sender).BackColor=Control.DefaultBackColor;
}
else
{
((Control)sender).Parent.BackColor=Control.DefaultBackColor;
}
}
注意loadtalk這個函數的參數,第一個只是臨時測試用的,第二個才是主要的,后面加載數據會用到。動態加載控件最重要的調整控件位置和大小,也就是Size和Location屬性,這兩個值需要從事先設計好的界面中獲取,但是動態生成的和事先設計好的不一樣,動態生成的位置會有差距,需要開發者手動調節。注意if(talknum > 5)這個判斷,因為到第7個的時候,大panel不能容納生成的小panel了,time控件的位置又不一樣了,所以需要特殊處理。
還有,loadTalkMessageList這個方法也是后面加載數據時才實現的,這里需要定義TalkMessage實體模型,在項目里面,添加這個類,并加上三個屬性。
internal class TalkMessage
{
private string _NickName;
private string _SubMessage;
private string _Time;
public string NickName
{
get
{
return _NickName;
}
set
{
_NickName=value;
}
}
public string SubMessage
{
get
{
return _SubMessage;
}
set
{
_SubMessage=value;
}
}
public string Time
{
get
{
return _Time;
}
set
{
_Time=value;
}
}
}
加載會話和加載好友列表原理是一樣的,代碼也非常相似,只不過是改改變量名稱、添加不同的實體列,這里就不再多數,讀者請自行實現動態添加好友列表。
到這里,主界面的邏輯交互就全部實現了。還缺的就是數據了,等到后面實現功能的時候再細論。下一篇文章將介紹其余的窗體。當然,有了這篇文章的鋪墊,其余窗體將會非常好搭建。
本文系小博客網站原創,轉載請注明文章鏈接地址 查看更多內容請點擊閱讀更多