2.让我们登录吧!
2.1 登录界面
在第一章我们研究了如何编写一个MDI的框架,以后我们就会利用这个框架来建立起我们的MIS应用,但这里有个问题,因为我们知道一般的MIS都不会只是单人使用的,而多人使用的应用程序也一般会有用户、权限等等的划分。因此,用户身份的确认应该是我们整个MIS应用开始的第一步,现在我们来看一下,如何实现用户身份的确认,或者说如何实现用户的登录。
我们可以从很多市面上优秀的MIS系统中了解到,MIS登录界面通常都会在程序起动后就弹出来,用户输入正确的用户名和密码后,登录界面消失,接着MIS的主界面才会真正的显示出来。基于这种流程的设计,我们可以知道的是用户登录的窗体一定是优先于主窗体的显示。那么代码该如何写呢?首先,我们继续打开我们在第一章里完成的程序,并在这个工程中添加一个新的窗体,并把这个窗体的BorderStyler设置为bsDialog,然后把Form命名为frmLogin,文件保存为LoginForm.pas,窗体中其它的控件的设置如下图所示:
好了,我们现在运行一下程序,可以发现程序一点变化都没有,这是因为我们的程序只是把这个窗体创建出来,但并没有把它Show来,但该在什么地方把它Show出来呢?我们打开MDI_Tutorial.dpr来研究一下。
我们可以看到有这样的两句话:
……
Application.CreateForm(TfrmMain, frmMain);
Application.CreateForm(TfrmLogin, frmLogin);
……
我们从第一章的研究中就可以知道,这两句话是把两个窗体创建出来,但这里有一点大家是必须先了解的:在Delphi的VCL框架中,会把第一个通过Application.CreateForm创建出来的窗体作为主窗体,主窗体经过这样的创建后,同时会自动的显示出来,而其它的窗体虽然也会被创建,但不会显示出来(除非其它的窗体是MDI的子窗体,就像我们在第一章中介绍的一样)。那么,沿着我们刚才的思路,我们想让登录窗体优先于主窗体显示出来,所以我们把这两句话的顺序换一下,变成是下面的形式:
……
Application.CreateForm(TfrmLogin, frmLogin);
Application.CreateForm(TfrmMain, frmMain);
……
改好以后,我们运行程序,可以看到现在的登录窗体能正确地显示出来,但另一个问题却出现了:当我们把登录窗体关闭后,程序并没有像我们所设想的那样子,它没有自动显示主窗体,而是自动退出了。这是什么原因呢?其实跟我们刚才所说的原因一样,Delphi会把第一个使用Application.CreateForm创建出来的窗体作为主窗体,当主窗体被关闭时,程序就理所当然的退出了。
放在后面不行,放在前面更不行,那我们该怎么办呢?
我们换个方式来解决这个问题,为什么我们一定要用Application.CreateForm来创建窗体,难道就没有其它的方法?当然不是,方法多得是,最简单的莫过于我们在第一章中所使用的frm := TFrom.Create(nil)的方法,现在,我们就在这里采用这种方式,现将程序改为
……
frmLogin := TfrmLogin.Create(Application);
frmLogin.ShowModal;
frmLogin.Free;
Application.CreateForm(TfrmMain, frmMain);
……
经过这样的改造,我们再来运行一下。程序运行后会显示出登录的窗体,当我们关闭这个窗体时,主窗体也能正常显示出来了。
有了上面的基础,我们继续来完善我们的代码。
因为到目前为止,我们还没有讨论数据库的事情,所以我们无法让用户输入的登录账号与密码跟数据库中的数据作一个真实的比对,但我们可以这样来模拟:我们想让用户点击OK按钮时就判断用户输入的用户名及密码是否为 user和pass ,如果正确,那么就退出这个登录窗体并打开主窗体;如果错误,就提示用户重新输入。而当用户点击Cancel时,我们就直接关闭登录窗体,并退出整个程序。
我们分两步来完成上述的目标。第一步,先来完善frmLogin中的代码,首先,我们希望frmLogin在关闭时能通过一个变量(RetValue)返回一个值,这个值是用来判断frmLogin究竟是因为登录成功的原因被关闭(true)还是因为用户点击了Cancel而被关闭(false)。
…
TfrmLogin = class(TForm)
…
private
FRetValue : boolean;
public
property RetValue : boolean read FRetValue;
….
当然,我们要为这个变量设定一个初始值,这个值应该是false,因为当登录窗体创建后,并没有包含任何的用户信息,如果这时候被关闭的话,那么一定是没有成功登录的。我们添加FormCreate事件来初始化这个变量。
procedure TfrmLogin.FormCreate(Sender: TObject);
begin
FRetValue := false;
end;
至于其它的代码比较简单,我们就不再详细讨论了,代码如下:
……
procedure TfrmLogin.btnCancelClick(Sender: TObject);
begin
Close;
end;
procedure TfrmLogin.btnOKClick(Sender: TObject);
begin
if (edtPassword.Text = 'pass') and (edtOperatorID.text = 'user') then
begin
FRetValue := true;
Close;
end
else
begin
MessageBox(Handle, '错误的用户名或密码!', 'MDI_Tutorial', MB_ICONWARNING or MB_OK);
edtOperatorID.SetFocus;
end;
end;
procedure TfrmLogin.FormCreate(Sender: TObject);
begin
FRetValue := false;
edtPassword.Text := '';
edtOperatorID.Text := '';
end;
……
第二步,我们接着来改造MDI_Tutorial.dpr中的代码。代码如下:
……
begin
Application.Initialize;
frmLogin := TFrmLogin.Create(Application);
frmLogin.ShowModal;
if frmLogin.RetValue then
begin
Application.CreateForm(TfrmMain, frmMain);
end;
frmLogin.free;
Application.Run;
GFormClassMgr.Free;
end.
以上的代码也是很简单的,我们通过判断frmLogin.RetValue的值来决定是否要创建frmMain,如果创建了frmMain,那么通过Application.Run就能正常把frmMain显示出来,并进行消息循环;如果没有创建frmMain的话,那么当调用Application.Run时,因为找不到主窗体,所以程序也就自行退出了。