ProtectorOfUbi
ProtectorOfUbi

Reputation: 327

Undeclared Identifier using listboxes

I have created a listbox and used it to add and remove/load and save items to a file which is all well and good. However when I try to use the listbox on another unit, I get an error: undeclared identifier.

The first Unit below MainUnit is where I am trying to use the listbox and getting the error undeclared identifier. Below the MainUnit is the ManageUsersUnit this is the unit in which the listbox is used and created. All the code works with the listbox on the ManageusersUnit but not on any other unit.

unit MainUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Menus, ExtCtrls;

implementation

uses AddTenantUnit, HomeUnit, MainMenuUnit;

{$R *.dfm}

{ the error im getting is in this procedure}

procedure TMainForm.FormCreate(Sender: TObject);.
begin                                    
  if fileExists('Newuser.dat')
  then
    begin
      UserListBox.Items.LoadFromFile('Newuser.dat');
    end
  {endif};
end;

unit ManageUsersUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, MainUnit, StdCtrls, Menus, ComCtrls;

type
  TManageUsersForm = class(TForm)
    AddUserButton: TButton;
    RemoveUserButton: TButton;
    ChangeUsernameButton: TButton;
    ChangePasswordButton: TButton;
    HomeButton: TButton;
    UserListBox: TListBox;
    UsernameEdit: TEdit;
    SaveButton: TButton;
    PasswordEdit: TEdit;
    SubText1Label: TLabel;
    SubText2Label: TLabel;
    PassListBox: TListBox;
    Button1: TButton;

  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  ManageUsersForm: TManageUsersForm;

implementation

uses PassWord, AddUserUnit, HomeUnit;

{$R *.dfm}

procedure TManageUsersForm.HomeButtonClick(Sender: TObject);
begin
  HomeForm.show;
  ManageUsersForm.Close;
end;

//Add UserName
procedure TManageUsersForm.AddUserButtonClick(Sender: TObject);

var
  i : integer;
  Found : Boolean;
  AddUser : string;

begin
  {ManageUsersForm.close;
  AddUserForm.ShowModal; }

  Found := false;
  AddUser := UsernameEdit.Text;

  i := 0;
  while i < userlistbox.Items.Count do
    begin
      if (UpperCase(AddUser) = Uppercase(userlistbox.Items[i]))
      then
        Found := True;
      inc(i);
    end;
  {endhwile};

  if Found = False then
    begin
      userlistbox.Items.Add(AddUser);
      UsernameEdit.Text := '';
      showMessage(AddUser + ' added');
    end
  else
    showMessage(AddUser + ' is already present.');
  {endif};
end;

procedure TManageUsersForm.RemoveUserButtonClick(Sender: TObject);
var
  deleted : string;
begin
  with UserListBox do
    begin
      if ItemIndex = -1
      then
        showMessage('You must select a User first.')
      else
        begin
          Deleted := Items.Strings[ItemIndex];
          Items.Delete(ItemIndex);
          showMessage(Deleted + ' deleted');
        end;
      {endif};
    end;
end;

procedure TManageUsersForm.Button1Click(Sender: TObject);
var
  i : integer;
  Found : Boolean;
  check : string;
begin
  check := PasswordEdit.Text;
  Found := false;

  i := 0;
  while i < userlistbox.Items.Count do
    begin
      if (UpperCase(check) = Uppercase(userlistbox.Items[i]))
      then
        Found := True;
      inc(i);
    end;
  {endhwile};

  if Found = False
  then
    begin
      showMessage(check + ' Incorrect Username');
    end
  else
    showMessage(' well done in file :).');
  {endif};
end;

procedure TManageUsersForm.SaveButtonClick(Sender: TObject);
begin
  assignfile (userFile,'Newuser.dat');
  UserListbox.Items.SaveToFile('Newuser.dat');
  showMessage('Saved to file');
end;

procedure TManageUsersForm.FormCreate(Sender: TObject);
begin
  if fileExists('Newuser.dat')
  then
    begin
      UserListBox.Items.LoadFromFile('Newuser.dat');
    end
  {endif};
end;

procedure TManageUsersForm.TestBtnClick(Sender: TObject);
begin
    AddUserForm.ShowModal;
end;

end.

Upvotes: 1

Views: 980

Answers (1)

Deltics
Deltics

Reputation: 23056

Your MainUnit needs to use the ManageUsersUnit unit. If the only references to the form in that other unit are in the implementation section then add it to the uses clause there. As a general rule you should only add to the interface uses clause if absolutely necessary.

unit MainUnit;

///  ...

implementation

  uses AddTenantUnit, HomeUnit, MainMenuUnit, ManageUsersUnit;

Your code then references the UserListBox directly, but this reference is a member variable of the TManageUsersForm class, so you must first identify an instance of that class before you access the members of that instance.

In this case you appear to have a public instance already available which you presumably intend to use: ManageUsersForm

So your code to load the file data into the list should be:

ManageUsersForm.UserListBox.Items.LoadFromFile('Newuser.dat');

This will fix your immediate issue. However, there is a lot wrong with this approach.

  1. MainUnit assumes that ManageUsersForm is a valid, existing form instance. If the form is set to AutoCreate in the project then this may be valid but is dangerous since it makes your code vulnerable to a change in the way that your forms are created.

  2. MainUnit is inappropriately responsible for some of the behaviour of the ManageUsers form. If the ManageUsers form truly manages users then this should include persistence of users to/from files itself.

  3. MainUnit is highly dependent upon the internal details of the ManageUsers form. We say it is "tightly coupled". If the ManageUsers form is modified to use, for example, a grid to a listview to present users, the MainUnit code will break since it relies on the intimate knowledge that the users list is specifically a listbox.

As a result of the way that the VCL works, the user interface controls on a form in Delphi are publicly accessible, but you should regard these as private (or, at most, protected). Your ManageUsers form should provide a public interface to the functionality that it provides to the "outside world" which deals in terms of user data.

There should be no references to the user interface elements of a form - including any event handlers - outside of the form itself (or descendant form classes if you are using an OO hierarchy of form classes).

Upvotes: 4

Related Questions