测试程序用的是vs.net 2012 + ms sql 2008,实现的是winform的基本框架,测试内容是:
1.经过登录窗口从ms sql数据库验证登录信息后再打开MDI主窗口;
2.登录窗口图片重绘;
3.MDI主窗口和子窗口的设置;
4.主窗口中菜单、工具栏、状态栏的设置,工具栏纵向居左,大小自适应;状态栏显示登录人姓名及系统时间
实现的时候,总结起来就是:
一、经过登录验证再打开主窗口:
1.在Main程序里,用对话框模式打开登录窗口
if (fLogin.DialogResult != DialogResult.OK) return;
2.在登录窗口验证资料成功后,返回DialogResult.OK
this.DialogResult = DialogResult.OK;
3.在Main程序里,只有返回DialogResult.OK时,再打开主窗口
Application.Run(new FormMain());
二、登录窗口都带底图,要在Paint事件中重绘图片,占满窗口
三、子窗口要设置无边框,设置不显示窗口控制按钮,在Load事件里,设置占满父窗口
this.Dock = DockStyle.Fill;
四、主窗口中菜单、工具栏、状态栏设置好Dock属性
1.工具栏通过设置每个工具图标的ImageScaling属性是None,实现工具栏大小自适应,通过设置TextImageRelation属性是ImageAboveText,把图标放在文本上面
2.在工具栏里,通过添加Separator给工具图标分组
3.在状态栏里,通过设置StatusLabel的BorderSides属性,给状态栏设置分隔线
五、MDI主窗口要设置IsMdiContainer属性是True,在打开子窗口时要设置子窗口的MdiParent属性,这样的设置才可以形成主窗口和子窗口的关系
测试程序运行如下:
整个测试程序的编程过程如下:
一、数据库连接
webform的数据库连接字串记录在web.config,winform的记录在App.config,为了在程序中使用App.config里添加的节点,要在在引用中添加引用:System.Configuration
<connectionStrings>
<add name="ConStr" connectionString="Data Source=数据库ID;Initial Catalog=数据库名称;User ID=登录数据库的用户名;Password=登录密码" providerName="System.Data.SqlClient"/>
</connectionStrings>
二、用静态类记录整个应用运行过程中都要记录的资料,比如登录名,在这个测试程序里,登录后,登录名显示在主窗口状态栏的左下角
static class PosClass
{
private static readonly string dbConnectionString = ConfigurationManager.ConnectionStrings["ConStr"].ConnectionString;
public static string ConStr
{
get { return dbConnectionString; }
}
private static int userIDValue = 0;
public static int UserID
{
set { userIDValue = value; }
get { return userIDValue; }
}
private static string userLoginValue = "";
public static string UserLogin
{
set { userLoginValue = value; }
get { return userLoginValue; }
}
}
三、主界面FormMain.cs
主界面是一个MDI窗口,带一个菜单、一个工具条、一个状态栏、一个定时器,用于在状态栏显示系统时间,这个界面里,只有一个会让人困惑的地方,是工具栏ToolStrip的大小不允许修改,这是因为工具栏通过设置每个工具图标的ImageScaling属性是None值,工具栏就会自适应大小了,不需要手动修改Size值的
以下是主界面里每个控件的必须设置的属性列表
FormMain窗口 |
IsMdiContainer |
True |
设置窗口是MDI容器 |
|
WindowState |
Maximized |
进入窗口时就以最大化显示 |
|
|
|
|
menuStrip1 |
Dock |
Top |
设置菜单靠着窗口的上边框 |
|
|
|
|
toolStrip1 |
|
|
这里添加了4个工具图标,每一个工具图标之间添加了Separator(分隔线) |
|
Dock |
Left |
设置工具栏靠着窗口的左边框 |
toolStrip1.tsbClient |
ImageScaling |
None |
该工具图标大小自适应 |
|
TextImageRelation |
ImageAboveText |
图标在文本上面 |
|
Text |
会员信息 |
|
|
|
|
|
statusStrip1 |
|
|
这里添加3个StatusLabel |
|
Dock |
Bottom |
设置状态栏靠着窗口的下边框 |
statusStrip1.tsslLogin |
Text |
登录人:狼子 |
|
|
TextAlign |
MiddleLeft |
设置文本垂直居中,左对齐 |
statusStrip1.tsslDeclare |
Text |
美容美发收银系统 |
|
|
TextAlign |
MiddleCenter |
设置文本垂直居中,居中对齐 |
|
BorderSides |
Left, Right |
设置两边有分隔线 |
|
Spring |
True |
设置这个Label填满状态栏的剩余空间 |
statusStrip1.tsslTime |
Text |
系统时间 |
|
|
TextAlign |
MiddleRight |
设置文本垂直居中,右对齐 |
1.状态栏的操作,在进入窗口的时候,要显示当前登录人的名字,还要显示当前的系统时间
#region 状态栏
private void FormMain_Load(object sender, EventArgs e)
{
this.tsslLogin.Text = "登录人:" + PosClass.UserLogin;
this.tsslTime.Text = "系统当前时间:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");
this.timer1.Interval = 1000;
this.timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
this.tsslTime.Text = "系统当前时间:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");
}
#endregion
2.退出系统的按钮,退出系统时要先退出这个MDI窗口的活动窗口,要关闭这个MDI窗口,要退出这个应用,其实退出MDI窗口,所有已打开了的子窗口都会被退出的,我只是,喜欢手动关闭东西。。。
我的应用里,一次活动窗口只有一个,所以我每次都先关闭活动窗口,再打开子窗口,我把这个关闭窗口提成了一个方法,在退出系统和打开子窗口时调用
#region 退出系统
private void CloseActiveWindow(bool isExit, string newFormName)
{
if (this.ActiveMdiChild == null) return;
if (!isExit && this.ActiveMdiChild.Name.Equals(newFormName))
return;
else
this.ActiveMdiChild.Close();
}
private void tsmiExit_Click_1(object sender, EventArgs e)
{
CloseActiveWindow(true, null);
this.Close();
Application.Exit();
}
#endregion
3.打开一个子窗口,菜单和工具栏各一个事件,在工具栏里,我直接调用了菜单的事件,测试里,我打开的是客户资料,就是设置子窗口的MdiParent属性就可以了
#region 客户资料
private void tsmiClient_Click(object sender, EventArgs e)
{
CloseActiveWindow(false, "FormClient");
FormClient w = new FormClient();
w.MdiParent = this;
w.Show();
}
private void tsbClient_Click(object sender, EventArgs e)
{
tsmiClient_Click(null, null);
}
#endregion
四、子窗口FormClient.cs
必须设置的属性表
FormClient |
ControlBox |
False |
不显示窗口最上面带控制按钮的框 |
|
FormBorderStyle |
None |
不显示窗口的边框,这样子窗口可以很好的嵌入MDI窗口中 |
|
MaximizeBox |
False |
不显示最大化按钮 |
|
MinimizeBox |
False |
不显示最小化按钮 |
给窗口添加Load事件,设置Dock属性,让子窗口占满整个MDI窗口
private void FormClient_Load(object sender, EventArgs e)
{
this.Dock = DockStyle.Fill;
}
五、登录窗口FormLogin.cs
登录窗口有一个PictureBox,3个Label,两个按钮
下面是必须设置的属性
FormLogin |
BackColor |
Control |
这个是配着我的登录界面里的灰色条设置的,一般会用一个大图占满整个窗口,我只是用了一个条,别的用了窗口底色填充 |
|
MaximizeBox |
False |
登录窗口就是一个对话框窗口,没有必要允许最大化 |
|
StartPosition |
CenterScren |
窗口最开始在屏幕中间显示 |
|
Paint事件 |
|
用于重绘图片 |
pbBg |
Visible |
|
PictureBox控件,在FormLogin的Paint事件里,会根据比例重画这个图片,让图片横向占满整个窗口,所以这个图片不需要显示 |
1.重绘图片,使图片横向占满窗口,显示一个长条
private void FormLogin_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
//构造图像对象
Bitmap bitmap = new Bitmap(pbBg.Image);
//横向延长图片到窗口长度
g.DrawImage(bitmap, 0, 80, this.Width, 181);
}
2.退出按钮,在登录窗口中,退出即窗口,即退出应用
private void btExit_Click(object sender, EventArgs e)
{
this.Close();
Application.Exit();
}
3.在数据库中读取数据验证登录信息,如果成功,打开主窗口(MDI)窗口后,关闭登录窗口
这里数据库中用到表A_User
CREATE TABLE [dbo].[A_User](
[UserId] [int] IDENTITY(1,1) NOT NULL,
[UserLogin] [varchar](32) NOT NULL,
[UserPwd] [varchar](32) NOT NULL,
CONSTRAINT [PK_A_User] PRIMARY KEY CLUSTERED
(
[UserId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
验证登录的事件,用到两个PosClass类里的方法,一个是过滤非法字符的,一个是取MD5码
这里最重要的是下面那句this.DialogResult = DialogResult.OK;
这一句向应用返回一个值,如果是OK,则继续,看下一步修改应用主程序那里,在下面
private void btLogin_Click(object sender, EventArgs e)
{
string userLogin = PosClass.CleanTxt(tbName.Text.Trim());
string userPwd = PosClass.Md5(tbPwd.Text.Trim());
if (String.IsNullOrEmpty(userLogin) || String.IsNullOrEmpty(userPwd))
{
MessageBox.Show("请输入用户名和登录密码");
return;
}
bool ok = false;
try
{
using (SqlConnection dbConnect = new SqlConnection(PosClass.ConStr))
{
dbConnect.Open();
using (SqlCommand dbCommand = new SqlCommand("select UserID, UserPwd from A_User where UserLogin = @UserLogin", dbConnect))
{
dbCommand.Parameters.Add(new SqlParameter("@UserLogin", userLogin));
using (SqlDataReader dr = dbCommand.ExecuteReader())
{
if (dr.HasRows)
{
int rowCount = 0;
while (dr.Read())
{
rowCount++;
if (rowCount > 1) break;
if (userPwd.Equals(dr["UserPwd"].ToString()))
{
ok = true;
PosClass.UserID = Convert.ToInt32(dr["UserId"]);
PosClass.UserLogin = userLogin;
}
}
if (rowCount > 1) ok = false;
}
}
}
}
}
catch (Exception)
{ }
if (ok)
{
//借DialogResult返回登录成功
this.DialogResult = DialogResult.OK;
this.Close();
}
else
{
MessageBox.Show("用户名或密码错误");
}
}
六、修改应用主程序Main,设置只有登录窗口返回DialogResult.OK时,才打开主MDI窗口
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//在打开主窗口前,先调用登录窗口验证登录资料
Form fLogin = new FormLogin();
fLogin.ShowDialog();
if (fLogin.DialogResult != DialogResult.OK) return;
Application.Run(new FormMain());
}