I am having an Access Violation when my project tries to open up a separate form using the .Show
command.
The code is supposed to open the login
form. But just outputs an Access Violation error.
This is the code from the main form, and is run on its activation:
procedure TForm4.FormActivate(Sender: TObject);
begin
label1.BringToFront;
DBMatch.Enabled := false;
DBContestants.Enabled := false;
btncreate.Enabled := false;
DbNav.Enabled := false;
login.Show;
end;
The below code is the start of the login
form:
unit login_form;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs ,StdCtrls, ExtCtrls, unit4,pngimage;
type
Tlogin = class(TForm)
edit_username: TEdit;
edit_password: TEdit;
btnlogin: TButton;
btnForgotten: TButton;
lUsername: TLabel;
LPassword: TLabel;
Imageside: TImage;
procedure btnloginClick(Sender: TObject);
procedure FormActivate(Sender: TObject);
private
{ Private declarations }
public
end;
var
login: Tlogin;
password,result:string;
implementation
{$R *.dfm}
uses dmChess_u;
This is one of the errors on the main form
CodePudding user response:
Your Form4
(MainForm) object is being created before the login
object is created. Chances are, the TForm.OnActivate
event is also being fired before the login
object is created, too. Thus, the login
pointer would still be nil
when you try to call Show
on it. You can easily verify that by using the debugger.
A Form's OnActivate
event is not a good place to display a login form. That event is fired whenever a Form gains input focus, which can happen many times during the Form's lifetime.
Also, it is generally best to not auto-create your Form objects at program startup, except for the MainForm. Create your Form objects dynamically via their Create
constructor only when actually needed, and free them when no longer needed, eg:
login := Tlogin.Create(nil);
try
login.ShowModal;
finally
login.Free;
end;
Alternatively:
login := Tlogin.Create(Self);
login.Show;
...
// OnClose event handler
procedure TloginClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
However, in this particular case, if you want the user to login before interacting with the MainForm, I would suggest displaying the login form before the MainForm is even created, eg:
Application.Initialize;
login := Tlogin.Create(nil);
try
if login.ShowModal <> mrOk then
Exit;
finally
login.Free;
end;
Application.CreateForm(TForm4, Form4);
Application.Run;
CodePudding user response:
The other answer is really good. I will just add to one of the points. Don't create the form manually. Just create it in the project and then call it when needed. After you've created the form in your project you can do whatever you want on the form interface and code what you need. Then when you need the form, you can have a button on the main form. When the button is clicked make it show the form.
frmLogin.ShowModal;
Make that button invisible. Add this code to your mainForm on create code block, or just manually do it on the button properties by unchecking the visible property.
btnLogin.Visible := false;
Then go to your main form events and go to On Show. Double click and in the code block that appears just write
btnLogin.Click;
This means that before the form shows it will click the existing button. Since the show event is executed after the create event and you already have both forms created in the project, you won't have that problem.