Einzelnen Beitrag anzeigen

MorrisF

Registriert seit: 3. Apr 2019
41 Beiträge
 
#1

Delphi hängt bei klick auf Frame

  Alt 11. Apr 2019, 10:47
Hallo ihr Lieben,
Ich habe ein Testprogramm geschrieben, in dem ich Frames per Laufzeit in ein Formular lade. Ich habe jeden Frame so ausgestattet dass ich den angeklickten Frame 1. überall anklicken kann und das onClick Ereignis auf jeder Komponente ausgelöst wird(, ich weise also jeder Komponente bei OnClick eine von mir geschriebene Prozedur zu), und ihn 2. über die Vergabe eines einheitlichen Tags aller Komponenten, der Identisch mit dem Index des Frame-Arrays ist identifizieren kann.
Im Testprogramm funktioniert das alles einwandfrei. Hier der Code zum Erstellen der Frames und der Vergabe des Tags, sowie des OnClick Ereignises:
(Frame ist in beiden Programmen eine globale Variable: array of TFrame)
Delphi-Quellcode:
procedure TDialog_MainUnit.CreateFrames();
var
  i, j: Integer;
begin
  try
    for i := 0 to 2 do
    begin
      SetLength(Frame, length(Frame) + 1);

      //Frame bauen:
      Frame[i] := TFrame_ButtonTest.Create(Self);
      if Assigned(TFrame_ButtonTest(Frame[i])) then
      begin
        with Frame[i] do
        begin
          Name := 'Frame' + IntToStr(i);
          Parent := PnlFramesBack;
          Align := alLeft;
          Tag := i;
        end;
        TFrame_ButtonTest(Frame[i]).LblName.Caption := Frame[i].Name;
        for j := 0 to TFrame_ButtonTest(Frame[i]).ComponentCount - 1 do
        begin
          TFrame_ButtonTest(Frame[i]).Components[j].Tag := i;
          TButton(TFrame_ButtonTest(Frame[i]).Components[j]).OnClick := FrameClick;
          TButton(TFrame_ButtonTest(Frame[i]).Components[j]).Cursor := crHandPoint;
        end;
        TFrame_ButtonTest(Frame[i]).Show;
      end;
    end;
  except
    on e: Exception do
    begin
      ShowMessage('Fehler in CreateFrames(): ' + e.Message);
    end;
  end;
end;
Und hier die FrameClick-Prozedur, in der der Frame als angeklickt markiert wird:
Delphi-Quellcode:
procedure TDialog_MainUnit.FrameClick(Sender: TObject);
var
  tmpIdx, i: Integer;
begin
  try
    tmpIdx := TComponent(Sender).Tag;

    LblFramesAktiv.Caption := 'Aktiver Frame: ';
    for i := Low(Frame) to High(Frame) do
    begin
      TFrame_ButtonTest(Frame[i]).IsSelected := False;
      TFrame_ButtonTest(Frame[i]).PnlTop.BevelOuter := bvNone;
      TFrame_ButtonTest(Frame[i]).PnlTop.BevelWidth := 1;
    end;
    TFrame_ButtonTest(Frame[tmpIdx]).IsSelected := True;
    TFrame_ButtonTest(Frame[tmpIdx]).PnlTop.BevelOuter := bvRaised;
    TFrame_ButtonTest(Frame[tmpIdx]).PnlTop.BevelWidth := 3;

    LblFramesAktiv.Caption := 'Aktiver Frame: ' + TFrame_ButtonTest(Frame[tmpIdx]).Name;
  except
    on e: Exception do
    begin
      ShowMessage('Fehler in FrameClick(): ' + e.Message);
    end;
  end;
end;
Wie gesagt, funktioniert das alles ohne Probleme. Also wollte ich den Code meines Testprogrammes auf mein Hauptprogramm anwenden, was dann so für das Erstellen der Frames so aussieht:
Delphi-Quellcode:
function TDialog_Hauptprogramm.CreateFrames(): Boolean;
var
  i, j: Integer;

  function DeleteFrames(): Boolean;
  var
    i: Integer;
  begin
    Result := False;
    try
      for i := Low(Frame) to High(Frame) do
      begin
        if Assigned(Frame) then
          FreeAndNil(Frame[i]);
      end;
      Result := True;
    except
      on e: Exception do
      begin
        Result := False;
        ShowMessage('Fehler in DeleteFrames(): ' + e.Message);
      end;
    end;
  end;

begin
  Result := False;
  try
    //Erst alle Frames löschen
    if DeleteFrames() then
    begin
      TmpQuery.Close;
      TmpQuery.SQL.Clear;
      TmpQuery.SQL.Add('SELECT * FROM meine_tabelle');
      TmpQuery.SQL.Add('WHERE ID_meine_tablle2 = ' + IntToStr(SpinEdit.Value));
      TmpQuery.Open;
      try
        TmpQuery.First;
        i := 0;

        while not TmpQuery.Eof do
        begin
          SetLength(Frame, length(Frame) + 1);
          //Frame bauen:
          TMein_Frame(Frame[i]) := TMein_Frame.Create(self);
        if Assigned(TMein_Frame(Frame[i])) then
        begin
           with Frame[i] do
           begin
            Name := 'Mein_Frame'+IntToStr(i);
            Parent := PnlFramesBack;
            Tag := i;
            Align := alLeft;
           end;

           //Frame ausstatten:
           TMein_Frame(Frame[i]).IsSelected := False;
           TMein_Frame(Frame[i]).PnlBack.BevelOuter := bvNone;
           TMein_Frame(Frame[i]).PnlBack.BevelWidth := 1;
           //allen Frame-Komponenten den selben tag vergeben und anklickbar machen:
           for j := 0 to TMein_Frame(Frame[i]).ComponentCount - 1 do
           begin
            TMein_Frame(Frame[i]).Components[j].Tag := i;
            TButton(TMein_Frame(Frame[i]).Components[j]).OnClick := OnFrameClick;
            TButton(TMein_Frame(Frame[i]).Components[j]).Cursor := crHandPoint;
           end;
           Frame[i].Show;
        end;
          TmpQuery.Next;
          Inc(i);
        end;
      finally
        TmpQuery.Close;
      end;
      ScrollBoxFrames.Refresh;
    end
    else
    begin
      Result := False;
      Exit;
    end;
    Result := True;
  except
    on e: Exception do
    begin
      ShowMessage('Fehler in CreateFrames(): ' + e.Message);
    end;
  end;
end;
Diese Funktion ist also Quasi identisch mit der aus meinem Testprogramm, bis auf dass ich die Frames im richtigen Programm vorm Createn erst lösche und ich mit einer while schleife durch meine TmpQuery gehe und dabei i inkrementiere, anstatt wie im Testprogramm i direkt mit einer for-Schleife hochzuzählen. Aber das sollte ja keinen unterschied machen... Oder?
Das Createn der Frames funktioniert auch im Hauptprogramm einwandfrei. Aber jetzt kommt der Knackpunkt; Hier meine OnFrameClick Prozedur vom Hauptprogramm:
Delphi-Quellcode:
procedure TDialog_Hauptprogramm.OnFrameClick(Sender: TObject);
var
  tmpIdx, i: Integer;
begin
  try
    tmpIdx := TComponent(Sender).Tag;

    //alle Frames demarkieren:
    for i := Low(Frame) to High(Frame) do
    begin
      TMein_Frame(Frame[i]).IsSelected := False;
      TMein_Frame(Frame[i]).PnlBack.BevelOuter := bvNone;
      TMein_Frame(Frame[i]).PnlBack.BevelWidth := 1;
    end;

    //Den angeklickten Frame markieren:
    TMein_Frame(Frame[tmpidx]).IsSelected := True;
    TMein_Frame(Frame[tmpidx]).PnlBack.BevelOuter := bvRaised;
    TMein_Frame(Frame[tmpidx]).PnlBack.BevelWidth := 3;

    //mache anders Zeug...
  except
    on e: Exception do
    begin
      ShowMessage('Fehler in OnFrameClick(): ' + e.Message);
    end;
  end;
end;
Diese Prozedur ist sogar noch ähnlicher zu der FrameClick Prozedur vom Testprogramm.
Ich habe nun aber 2 Probleme in dieser Prozedur:
1. Das durchlaufen des Arrays, also folgende Code-passage erzeugt eine Zugriffsverletzung
Delphi-Quellcode:
    for i := Low(Frame) to High(Frame) do
    begin
      TMein_Frame(Frame[i]).IsSelected := False;
      TMein_Frame(Frame[i]).PnlBack.BevelOuter := bvNone;
      TMein_Frame(Frame[i]).PnlBack.BevelWidth := 1;
    end;
Wenn ich diesen Teil auskommentiere, Habe ich diesen Fehler schon mal nicht. Allerdings brauche ich diesen Code nunmal und im Testprogramm hat es ja einwandfrei funktioniert.
Nun zu Problem 2:
Als Progammierer denkt man sich nach dem Zugriffsverletzngsfehler natürlich: "Na gut, dann debugge ich die Prozedur halt mal und setze nen Haltepunkt an den Anfang." Wenn man das nun tut und auf den Frame klickt, hängt sich das ganze Programm auf und ich bekomme nichtmal eine Fehlermeldung. Ich kann dann weder Delphi, noch das Programm schließen und muss Delphi per Taskmanager abschießen.
Was ist da los???
Im Testprogramm hatte ich das alles nicht.
Woran könnte es liegen?
Danke nochmal im Voraus für eure Hilfe!

MFG
MorrisF
  Mit Zitat antworten Zitat