Avatar billede skovjuul Nybegynder
31. maj 2007 - 23:58 Der er 12 kommentarer og
1 løsning

Kan jeg se om en form er oprettet?

Jeg har følgende kode:
procedure TfrmMain.mmBehandlingerClick(Sender: TObject);
var
  frmBehandlinger: TfrmBehandlinger;
  frmPasscheck: TfrmPasscheck;
  resultcode: string;
begin
  try
    frmPasscheck := TfrmPasscheck.Create(Application);
    resultcode := frmPasscheck.execute(RegBaseInfo.gsAdminPass);
    if(resultcode ='ADMIN') then begin
      frmBehandlinger := TfrmBehandlinger.Create(Application);
      frmBehandlinger.execute()
    end
    else if resultcode = 'NOTADMIN' then
      MessageDlg('Adgangskoden er forkert! Du har muligvis ikke adgang til den valgte programdel.', mtError, [mbOK], 0);
  finally
    frmPasscheck.Free;
    frmBehandlinger.Free;
  end;
end;


Der er som I kan se ikke altid at frmBehandlinger bliver lavet oprettet hvilket giver mig en access violation i finally-delen. Er der en måde jeg kan se om formen er oprettet og skal have en .free eller hvordan gør man sådan noget smart?
Avatar billede js_delphi Nybegynder
01. juni 2007 - 07:53 #1
Hvad med:

var
  frmBehandlinger: TfrmBehandlinger;
  frmPasscheck: TfrmPasscheck;
  resultcode: string;
begin
  try
    frmPasscheck := TfrmPasscheck.Create(Application);
    resultcode := frmPasscheck.execute(RegBaseInfo.gsAdminPass);
    if(resultcode ='ADMIN') then begin
      frmBehandlinger := TfrmBehandlinger.Create(Application);
      frmBehandlinger.execute()
    end
    else if resultcode = 'NOTADMIN' then
      MessageDlg('Adgangskoden er forkert! Du har muligvis ikke adgang til den  valgte programdel.', mtError, [mbOK], 0);
  finally
    frmPasscheck.Free;
    if(resultcode ='ADMIN') then
      frmBehandlinger.Free;
  end;
end;
Avatar billede martinlind Nybegynder
01. juni 2007 - 10:30 #2
Det løser du med en nested try finally block :)
---------------------------

procedure TfrmMain.mmBehandlingerClick(Sender: TObject);
var
  frmBehandlinger: TfrmBehandlinger;
  frmPasscheck: TfrmPasscheck;
  resultcode: string;
begin
  try
    frmPasscheck := TfrmPasscheck.Create(Application);
    resultcode := frmPasscheck.execute(RegBaseInfo.gsAdminPass);
    if(resultcode ='ADMIN') then
    begin
      frmBehandlinger := TfrmBehandlinger.Create(Application);
      try
        frmBehandlinger.execute()
      finally
        frmBehandlinger.Free;
      end;
    end
    else if resultcode = 'NOTADMIN' then
      MessageDlg('Adgangskoden er forkert! Du har muligvis ikke adgang til den valgte programdel.', mtError, [mbOK], 0);
  finally
    frmPasscheck.Free;
    //frmBehandlinger.Free;
  end;
end;
Avatar billede tolderlund Nybegynder
04. juni 2007 - 11:36 #3
Din try-finally er forkert opbygget, den skal se sådan ud:
begin
  frmPasscheck := TfrmPasscheck.Create(Application);
  try
Create skal ligge FØR try.

Og for at løse dit problem kan du til føje
  frmBehandlinger := nil;

Så det ender med at se sådan ud:
begin
  frmBehandlinger := nil;
  frmPasscheck := TfrmPasscheck.Create(Application);
  try
Avatar billede tolderlund Nybegynder
04. juni 2007 - 11:38 #4
Lige en forklaring til dem der ikke ved det.
hvis frmBehandlinger = nil så sker der ikke noget ved at kalde
  frmBehandlinger.Free;
Avatar billede martinlind Nybegynder
04. juni 2007 - 14:00 #5
Det er sku da noget vrøvl tolderlund :) man skal da ikke sidde og sætte alle sine Obj. til nil, fordi at man så kan lave sin køde "forkert" uden at det går ned :(

Man bruger en nesteed try finally som jeg skrev og ja man skal lave sin create før man laver sin try finally.
Avatar billede skovjuul Nybegynder
04. juni 2007 - 19:13 #6
Tak for de mange forslag. Jeg har ikke lige mulighed for at teste dem da min computer har haft en nedsmeltning :(
Umiddelbart duer det ikke at oprette formen før tid, da jeg har nogle erklæringer i OnFormCreate som der ikke er nogen grund til at lave hvis formen alligevel ikke skal bruges.
Der kommer point sidst på ugen når jeg har testet færdig.

Takker
Jesper
Avatar billede hrc Mester
04. juni 2007 - 22:43 #7
Fordi jeg er meget krakilsk har jeg valgt at rette yderligere så det ligner den den kode jeg bedst kan lide.

1. Alle tekststrenge er flyttet ud som konstanter. God praksis og hvis konsekvent brugt kan man spare SameText (eller AnsiSameText) som sikkert er tunge.

2. If's erstattes med Exceptions. Hvorfor? Egentlig synes jeg koden bliver lidt lettere at overskue. Jeg ved godt at det er en forklædt "Goto" men try-finally og try-except virker godt sammen.

3. Min egen valideringsexception fanges, mens andre kan føres videre til en "on e: exception" hvis man ønsker det (prøv i øvrigt: http://www.madshi.net)

4. Jeg bruger Release i stedet for Free på forme. Release sørger for at afslutte alle ventende messages på formen inden den frigives. Derved reducere risikoen for "freak" exceptions.

5. Formene frigives når de kan. Væk er de nestede try-finally

6. Bruger self i stedet for application. Det er den rigtige måde at gøre det på: Man bibeholder hierarkiet af ejerskaber og kan bruge formens position-property til at placere den eksempelvis centreret i forhold til ejeren.

7. Sålænge der ikke er nestede "with" kan jeg godt leve med objektinstanserne er lidt sværere at debugge.

const
  rcADMIN = 'ADMIN';
  rcNOTADMIN = 'NOTADMIN';

type
  EPasswordError = class(Exception);

procedure TfrmMain.mmBehandlingerClick(Sender: TObject);
var
  resultcode: string;
begin
  try
    with TfrmPasscheck.Create(self) do
      try
        resultcode := frmPasscheck.execute(RegBaseInfo.gsAdminPass);
      finally
        Release;
      end;
 
    if SameText(resultcode,rcNOTADMIN) then
      raise EPasswordError.Create('Adgangskoden er forkert! Du har muligvis ikke adgang til den valgte programdel.');

    if SameText(resultcode,rcADMIN) then
    begin
      with TfrmBehandlinger.Create(self) do
      try
        execute();
      finally
        Release;
      end;
    end;
   
  except
    on e: EPasswordError do
      MessageDlg(e.Message, mtError, [mbOK], 0);
  end;
end;


Martin: Jeg tror du misforstår Tolderlund mht. := nul. Med følgende konstruktion giver det fin logik at sætte form2 = nil:

begin
  form1 := TForm1.Create(self);
  form2 := nil;
  try
    ...
    form2 := TForm2.Create(self);
    ...
  finally
    form1.Release;
    if assigned(form2) then
      form2.release;
  end;
end;
Avatar billede martinlind Nybegynder
05. juni 2007 - 12:17 #8
hrc >> Nej :) Fordi man kan er det ikke det samme som at det er rigtigt :), og jeg mener IKKE det er god kode at din Class-var SKAL sættes til nil, det er langt rigtigere at kode så man kun free'er hvis classen har været createt, og løses jo fint med nested try .. finally
Avatar billede hrc Mester
05. juni 2007 - 12:51 #9
martin. Du kan ikke argumentere mod, at eksemplet med en try-finally fungerer ligeså godt og ligeså sikkert som en nested. Ved at sætte instansvariablen til nil (delphi garanterer at den er nil, så det er egentlig overflødigt) er det sikket den blive fanget i finally sektionen, skulle være blevet oprettet undervejs.

... men ja. Det er måske ikke er det eleganteste og jeg gør det ikke ret tit men når jeg gør, er det fordi jeg synes en try-except og to try-finally fylder for meget:

  try
    try
      try
      finally
      end;
    finally
    end;
  except
    on e: exception do
    begin
      ...
    end;
  end;

I skovjuuls tilfælde er nested try-finallys' slet ikke nødvendige.
Avatar billede martinlind Nybegynder
05. juni 2007 - 13:07 #10
(delphi garanterer at den er nil, så det er egentlig overflødigt)

det mener jeg kun gælder for de var's du laver i din klasse og ikke en procedure var, det er ihvertfald ikke rigtig hvis du laver en integer som en procedure var, den er ikke 0 fra start :)

Ha' en fortsat god "fridag"
Avatar billede hrc Mester
06. juni 2007 - 06:53 #11
Egentlig var jeg på arbejde ...
Avatar billede skovjuul Nybegynder
07. juni 2007 - 02:33 #12
Mange tak for svarene, det bliver en fin nestet
try
try
  try
  finally
finally
except

uden problemer.

Hrc, smider du også et svar, så deler dig og martin pointene.

Og på falderebet, er det en fejl at have sin form.create efter try? Eller er det bare en smagssag?

Tak for hjælpen, jeg har allerede et nyt spørgsmål hvis I mangler flere point :)

Hyg jer
Jesper
Avatar billede martinlind Nybegynder
15. juni 2007 - 09:45 #13
I Delphi foreskriver de at man "prøver" at allocere sin Object/Ram ( Create/GetMem osv ) sådan :

create()...-
Try
finally
  Free;
end;
 
og det er også det rigtige, for så er du sikker på at du har noget at free'e når du kommer ind i try finally :)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester