Login Dialog Using a Hash Table


 

Overview

We have seen how to create a login dialog box using a streamed file. In that article, we stored the user's credentials in a file that can be stored on disk. This time, we will use a "regular" list of strings.

The VCL provides various types of list classes, some of which we have also reviewed on this site, such as the TStrings and TStringList, THashedStringList, TList, and TIniFile. In the article on hash tables, we saw that a hashed list is created from the THashedStringList class, which itself derives from TStrings. This allows THashedStringList to use the properties and methods of TStrings. Particularly, THashedStringList is adapted to effectively deal with strings of the form Name=Value. This is how we will use it to store usernames and passwords in a file. Such a file can be automatically loaded when the application starts and saved when the application closes, in case a new account or some new accounts were created and added to the (hashed) list.

Start Borland C++ Builder with its default form. Save the project in a new folder called LoginHash

Save the unit as Main and save the project as LoginHash

Change the Name of the form to dlgLogin and design it as follows:

Employee Login

Open Notepad and type Account=Password on the first line. Then save it as credentials.cdt in the folder that contains the current project. Make sure you don't save it as text. Close Notepad.

Add another form. It would be used as the main form of the application. This form would display if the user successfully logs in. Change its Caption to Order Processing and save its unit as frmOrder

From the Dialogs tab of the New Items (File -> New -> Other...) dialog box, add a Standard Dialog (Vertical) from to the project. Change its Name to dlgNewAccount and save its unit as NewAccount.

Design it as follows:

New Account

Application Scripts

In the header file of the first form, declare a private THashedStringList variable named Credentials and a public method named CreateAccount

//---------------------------------------------------------------------------
#ifndef frmLoginH
#define frmLoginH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <Buttons.hpp>
#include <IniFiles.hpp>
//---------------------------------------------------------------------------
class TdlgLogin : public TForm
{
__published:	// IDE-managed Components
    TLabel *Label1;
    TLabel *Label2;
    TEdit *edtUsername;
    TEdit *edtPassword;
    TBitBtn *BitBtn1;
    TBitBtn *btnCreateAccount;
    void __fastcall BitBtn1Click(TObject *Sender);
    void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
    void __fastcall btnCreateAccountClick(TObject *Sender);
    void __fastcall FormCreate(TObject *Sender);
private:
    THashedStringList *Credentials;	// User declarations
public:
    void __fastcall CreateAccount(AnsiString NewAccount); // User declarations
    __fastcall TdlgLogin(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TdlgLogin *dlgLogin;
//---------------------------------------------------------------------------
#endif

Change the source file of the first form as follows:

//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "frmLogin.h"
#include "Main.h"
#include "NewAccount.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TdlgLogin *dlgLogin;
//---------------------------------------------------------------------------
__fastcall TdlgLogin::TdlgLogin(TComponent* Owner)
    : TForm(Owner)
{
    Credentials = new THashedStringList;
}
//---------------------------------------------------------------------------
void __fastcall TdlgLogin::CreateAccount(AnsiString NewAccount)
{
    Credentials->Add(NewAccount);
}
//---------------------------------------------------------------------------
void __fastcall TdlgLogin::BitBtn1Click(TObject *Sender)
{
    AnsiString Username, Password;
    Boolean Found = False;

    Username = edtUsername->Text;
    Password = edtPassword->Text;

    for(int i = 0; i < Credentials->Count; i++)
    {
        if( (Username == Credentials->Names[i]) &&
	    (Password == Credentials->Values[Credentials->Names[i]]) )
        {
            Hide();
            frmOrders->Show();
            Found = True;
            return;
        }
    }

    if( Found == False )
        ShowMessage("The credentials you entered "
		    "(Username and Password) are not correct");
}
//---------------------------------------------------------------------------
void __fastcall TdlgLogin::FormClose(TObject *Sender, TCloseAction &Action)
{
    Credentials->SaveToFile("credentials.cdt");
}
//---------------------------------------------------------------------------
void __fastcall TdlgLogin::btnCreateAccountClick(TObject *Sender)
{
    dlgNewAccount->edtUsername->Text = "";
    dlgNewAccount->edtPassword->Text = "";
    dlgNewAccount->edtConfirmPassword->Text = "";
    dlgNewAccount->ShowModal();
}
//---------------------------------------------------------------------------
void __fastcall TdlgLogin::FormCreate(TObject *Sender)
{
    Credentials->LoadFromFile("credentials.cdt");
}
//---------------------------------------------------------------------------

Just in case, here is the header file of the third form

//----------------------------------------------------------------------------
#ifndef NewAccountH
#define NewAccountH
//----------------------------------------------------------------------------
#include <vcl\ExtCtrls.hpp>
#include <vcl\Buttons.hpp>
#include <vcl\StdCtrls.hpp>
#include <vcl\Controls.hpp>
#include <vcl\Forms.hpp>
#include <vcl\Graphics.hpp>
#include <vcl\Classes.hpp>
#include <vcl\SysUtils.hpp>
#include <vcl\Windows.hpp>
#include <vcl\System.hpp>
//----------------------------------------------------------------------------
class TdlgNewAccount : public TForm
{
__published:
	TBevel *Bevel1;
    TLabel *Label1;
    TLabel *Label2;
    TEdit *edtUsername;
    TEdit *edtPassword;
    TBitBtn *BitBtn1;
    TLabel *Label3;
    TEdit *edtConfirmPassword;
    TBitBtn *BitBtn2;
    void __fastcall BitBtn1Click(TObject *Sender);
private:
public:
	virtual __fastcall TdlgNewAccount(TComponent* AOwner);
};
//----------------------------------------------------------------------------
extern PACKAGE TdlgNewAccount *dlgNewAccount;
//----------------------------------------------------------------------------
#endif

Implement the source file of the third form as follows:

//---------------------------------------------------------------------
#include <vcl.h>
#include <StrUtils.hpp>
#pragma hdrstop

#include "NewAccount.h"
#include "frmLogin.h"
//---------------------------------------------------------------------
#pragma resource "*.dfm"
TdlgNewAccount *dlgNewAccount;
//---------------------------------------------------------------------
__fastcall TdlgNewAccount::TdlgNewAccount(TComponent* AOwner)
	: TForm(AOwner)
{
}
//---------------------------------------------------------------------
void __fastcall TdlgNewAccount::BitBtn1Click(TObject *Sender)
{
    AnsiString Username, Password, ConfirmPassword;

    Username = edtUsername->Text;
    Password = edtPassword->Text;
    ConfirmPassword = edtConfirmPassword->Text;

    if( Username == "" )
    {
        ShowMessage("You must provide a username");
        edtUsername->SetFocus();
        ModalResult = mrNone;
    }
    if( AnsiContainsStr(Username, " ") )
    {
        ShowMessage("The username must not have space");
        edtUsername->SetFocus();
        ModalResult = mrNone;
    }

    if( Password == "" )
    {
        ShowMessage("You must provide a password");
        edtUsername->SetFocus();
        ModalResult = mrNone;
    }
    if( AnsiContainsStr(Password, " ") )
    {
        ShowMessage("The password must not have space");
        edtUsername->SetFocus();
        ModalResult = mrNone;
    }

    if( AnsiCompareStr(Password, ConfirmPassword) != 0 )
    {
        ShowMessage("The passwords do not match");
        edtPassword->SetFocus();
        ModalResult = mrNone;
    }

    AnsiString NewAccount = Username + "=" + Password;
    dlgLogin->CreateAccount(NewAccount);
}
//---------------------------------------------------------------------------
 

  Copyright 1998-2007 FunctionX, Inc.