Reputation: 327
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
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.
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.
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.
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