Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi hängt bei klick auf Frame (https://www.delphipraxis.net/200341-delphi-haengt-bei-klick-auf-frame.html)

MorrisF 11. Apr 2019 10:47

Delphi hängt bei klick auf Frame
 
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

Jumpy 11. Apr 2019 11:34

AW: Delphi hängt bei klick auf Frame
 
TMein_Frame(Frame[i]) := TMein_Frame.Create(self);

sieht mir falsch aus, oder?

Generell könnte man auch so arbeiten, dass man eine lokale TMein_Frame variable benutzt, diese füllt und setzt und am ende Frame[i] zuweist. Dann kann man sich das gehampel und gecaste sparen.

Und man könnte dann auch das i weglassen und Frame[High(Frame)] nehmen.

MorrisF 11. Apr 2019 11:52

AW: Delphi hängt bei klick auf Frame
 
Habe jetzt
Delphi-Quellcode:
TMein_Frame(Frame[i]) := TMein_Frame.Create(self);
durch
Delphi-Quellcode:
Frame[i] := TMein_Frame.Create(self);
ausgetauscht. Hat allerdings keinen unterschied gemacht

Morris

MorrisF 11. Apr 2019 11:54

AW: Delphi hängt bei klick auf Frame
 
Zitat:

Zitat von Jumpy (Beitrag 1430061)
Generell könnte man auch so arbeiten, dass man eine lokale TMein_Frame variable benutzt, diese füllt und setzt und am ende Frame[i] zuweist. Dann kann man sich das gehampel und gecaste sparen.

Und man könnte dann auch das i weglassen und Frame[High(Frame)] nehmen.

TMein_Frame ist die Frame Unit, die ich im Projekt habe, ich habe den Frame auch in den uses meines Haupformulars.
Ich bräuchte TMein_Frame außerdem als globlae Variable, da ich den Frame an mehreren Stellen im Programm brauche.
Hätte jemand mal ein kleines Beispiel, wie ich das mit einer globalen Variable vom Typ TMein_Frame machen könnte?

MorrisF 11. Apr 2019 12:19

AW: Delphi hängt bei klick auf Frame
 
Ich glaube ja eher, dass es irgenwas mit der von mir zugewiesenen Prozedur OnFrameClick zu tun hat, weil da bekomm ich ja den Fehler bzw wenn ich da nen Haltepunkt setze, hängt sich Delphi auf

Delphi.Narium 11. Apr 2019 12:36

AW: Delphi hängt bei klick auf Frame
 
Nur im Editor hingedattelt, daher keine Garantie für irgendwas ;-)
Delphi-Quellcode:
function TDialog_Hauptprogramm.CreateFrames(): Boolean;
var
  j: Integer;
  myFrame : TMein_Frame;

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

begin
  try
    // Erst alle Frames löschen
    Result := DeleteFrames();
    if Result 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;
        while not TmpQuery.Eof do
        begin
          SetLength(Frame, length(Frame) + 1);
          // Frame bauen:
          myFrame := TMein_Frame.Create(self);
          if Assigned(myFrame) then
          begin
            myFrame.Tag := tmpQuery.RecNo;
            myFrame.Name := Format('Mein_Frame_%d',[myFrame.Tag]);
            myFrame.Parent := PnlFramesBack;
            myFrame.Align := alLeft;
            // Frame ausstatten:
            myFrame.IsSelected := False;
            myFrame.PnlBack.BevelOuter := bvNone;
            myFrame.PnlBack.BevelWidth := 1;
            // allen Frame-Komponenten den selben tag vergeben und anklickbar machen:
            for j := 0 to myFrame.ComponentCount - 1 do
            begin
              myFrame.Components[j].Tag := myFrame.Tag;
              // Sicher, das alles nur TButtons oder deren Nachfahren sind?
              TButton(myFrame).Components[j]).OnClick := OnFrameClick;
              TButton(myFrame).Components[j]).Cursor := crHandPoint;
            end;
            myFrame.Show;
            Frame[High(Frame)] := myFrame;
          end;
          TmpQuery.Next;
        end;
      finally
        TmpQuery.Close;
      end;
      ScrollBoxFrames.Refresh;
    end;
  except
    on e: Exception do
    begin
      ShowMessage('Fehler in CreateFrames(): ' + e.Message);
      Result := False;
    end;
  end;
end;
Hier wurde für Frames TMein_Frame genutzt.
Im Folgenden wird für Frames TFrame_ButtonTest.

Sind die kompatibel oder ist das nur eine "BeispielquelltextZurProblemBeschreibungsdifferenz "?
Delphi-Quellcode:
procedure TDialog_MainUnit.FrameClick(Sender: TObject);
var
  tmpIdx, i: Integer;
begin
  if not Assigned(Sender) then begin
    MessageDlg('Vernünftige Fehlermeldung machen.',mtError,[mbOk),0);
  end else
  if not Sender is TComponent then begin
    MessageDlg('Noch ''ne vernünftige Fehlermeldung machen.',mtError,[mbOk),0);
  end else 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 := Format('Aktiver Frame: %s', [TFrame_ButtonTest(Frame[tmpIdx]).Name]);
    except
      on e: Exception do
      begin
        ShowMessage(Format('Fehler in FrameClick(): %s', [e.Message]));
      end;
    end;
  end;
end;
Wieso brauchst Du den Frame als globale Variabel? Du hast doch zur Laufzeit n Frames?

Jumpy 11. Apr 2019 12:45

AW: Delphi hängt bei klick auf Frame
 
Das DeleteFrames macht ja nur Sinn, wenn man das mehrfach neu aufbaut.
In dem Fall müsste man in DeleteFrames aber auch das Array wieder auf 0 setzen.

Und seh gerade, das hier macht in DeleteFrames doch auch keinen Sinn:
Delphi-Quellcode:
if Assigned(Frame) then
   FreeAndNil(Frame[i]);
Müsste doch eher sein:
Delphi-Quellcode:
if Assigned(Frame[i]) then
   FreeAndNil(Frame[i]);

haentschman 11. Apr 2019 12:51

AW: Delphi hängt bei klick auf Frame
 
Hallöle...:P
Delphi-Quellcode:
TmpQuery.Close;
TmpQuery.SQL.Clear;
TmpQuery.SQL.Add('SELECT * FROM meine_tabelle');
TmpQuery.SQL.Add('WHERE ID_meine_tablle2 = ' + IntToStr(SpinEdit.Value));
TmpQuery.Open;
...früher gabs dafür einen mit dem Rohrstock! :warn:

besser:
Delphi-Quellcode:
TmpQuery.SQL.Text := 'SELECT * FROM meine_tabelle';
TmpQuery.SQL.Add('WHERE ID_meine_tablle2 = :ID');
TmpQuery.ParamByName('ID').AsInteger := IntToStr(SpinEdit.Value);
TmpQuery.Open;
:thumb:

MorrisF 11. Apr 2019 12:55

AW: Delphi hängt bei klick auf Frame
 
Zitat:

Zitat von Jumpy (Beitrag 1430082)
Das DeleteFrames macht ja nur Sinn, wenn man das mehrfach neu aufbaut.
In dem Fall müsste man in DeleteFrames aber auch das Array wieder auf 0 setzen.

Und seh gerade, das hier macht in DeleteFrames doch auch keinen Sinn:
Delphi-Quellcode:
if Assigned(Frame) then
   FreeAndNil(Frame[i]);
Müsste doch eher sein:
Delphi-Quellcode:
if Assigned(Frame[i]) then
   FreeAndNil(Frame[i]);

In meinem Hauptprogramm baue ich die Frames mehrfach auf. Daher das DeleteFrames.
Mit der Code Verbesserung hast du schon mal recht! Vielen Dank!:thumb: Leider funktioniert das Programm immer noch nicht:|

Jumpy 11. Apr 2019 12:59

AW: Delphi hängt bei klick auf Frame
 
Setzt du denn jetzt die Array-Länge wieder zurück?


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:15 Uhr.
Seite 1 von 3  1 23      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz