Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Zugriffsverletzung, ich komm nicht drauf (https://www.delphipraxis.net/93630-zugriffsverletzung-ich-komm-nicht-drauf.html)

guidobrose 8. Jun 2007 14:31


Zugriffsverletzung, ich komm nicht drauf
 
Noch einmal ich, aber ich komm jetzt nicht mehr weiter... Der Quellcode ist etwas umfangreicher, aber ich habs mal (fast) komplett hinkopiert.

Grundsätzlich gibt es ein Datenmodul "DM", in dem die Imagliste für die Toolbuttons (unter anderem) liegt. Zusätzlich werden die einzelnen "Seiten", die im Programm aufgerufen werden können (momentan nur "Uebersicht" und "Einstellungen" auf einem Nachkommen von TPanel in eine eigene Unit ausgelagert. Die meisten Komponenten werden zur Lz auf dem Panel angeordnet (muss ich so machen, weil ich in der Explorerversion die visuellen Komponenten nicht erweitern kann und ein paar Schmankerl eingebaut habe). Zudem hoffe ich den Quelltext etwas übersichtlicher zu bekommen, wenn jede Seite ihre eigene Unit hat. Es funktioniert auch ganz gut und mit etwas Hilfe aus dem Forum, habe ich auch meinen untergeordneten Toolbar auf dem Panel untergebracht. Die Imageliste wird dem Toolbar aus dem Datenmodul zugeordnet (auch auf dem Hauptformular) und hier hakt es auch, denn sobald ich die Liste dem Toolbar zuweise (TEinstellungen.Enter), habe ich zwar einen Glyph auf dem Button, aber beim Beenden des Programmes bekomme ich eine Zugriffsverletzung. Kommentiere ich diese Zeile aus, dann läuft es wieder. Komischerweise scheint die Zuweisung der Imageliste an den Toolbar des Hauptformulars kein Problem zu verursachen. Die Zuweisung in "OnShow", bzw. "Enter" ist übrigens, weil das Datenmodul in der Create-Routine noch nicht erzeugt ist.

Kann mir jemand mal unterstützend unter die Arme greifen??

Gruß.


Delphi-Quellcode:
unit ULlesy;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ToolWin, ComCtrls, StdCtrls, ExtCtrls, XTCtrls, ImgList, UDM, UUebersicht, UEinstellungen;

type
  TLlesy = class(TForm)
    TlBr: TToolBar;
    LblInformation: TLabel;
    PnlStatus: TPanel;
    ImgStatusConnection: TImage;
    ImgStatusBenutzer: TImage;
    TlBtnUebersicht: TToolButton;
    TlBtnArchiv: TToolButton;
    TlBtnDatenbank: TToolButton;
    TlBtnEinstellungen: TToolButton;
    ToolButton5: TToolButton;
    TlBtnSeparator1: TToolButton;
    TlBtnInformation: TToolButton;
    TlBtnBeenden: TToolButton;
    TlBtnVollbild: TToolButton;
    procedure FormCanResize(Sender: TObject; var NewWidth, NewHeight: Integer;
      var Resize: Boolean);
    procedure FormCreate(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure TlBtnBeendenClick(Sender: TObject);
    procedure TlBtnInformationClick(Sender: TObject);
    procedure TlBtnEinstellungenClick(Sender: TObject);
    procedure TlBtnUebersichtClick(Sender: TObject);
    procedure TlBtnVollbildClick(Sender: TObject);
  private
    { Private-Deklarationen }
    Uebersicht: TUebersicht;
    Einstellungen: TEinstellungen;
    procedure SetPanel(VP: TVisiblePanel);
  public
    { Public-Deklarationen }
  end;

var
  Llesy: TLlesy;

implementation

uses UInfo;
{$R *.dfm}

procedure TLlesy.FormCreate(Sender: TObject);
begin
//Allgemeine Vorbesetzungen
Color:=clXTBackground;
//Weitere Fenster erzeugen
Uebersicht:=TUebersicht.Create(self,Llesy);
Einstellungen:=TEinstellungen.Create(self,Llesy);
end;

procedure TLlesy.FormShow(Sender: TObject);
begin
//Allgemeine Vorbesetzungen
TlBr.Images:=DM.ImgLst30x30;
//Wird beim Start auf TRUE gesetzt und im Infodialog wieder gelöscht.
DM.FirstStart:=True;
//Infodialog aufrufen
Information.Position:=poScreenCenter;
Information.ShowModal;
end;

procedure TLlesy.FormCanResize(Sender: TObject; var NewWidth,
  NewHeight: Integer; var Resize: Boolean);
begin
//Minimale Größe auf 800x600 begrenzen
  if (NewWidth<800) or (NewHeight<600) then
    Resize:=False;
end;

procedure TLlesy.TlBtnBeendenClick(Sender: TObject);
begin
Close;
end;

procedure TLlesy.TlBtnInformationClick(Sender: TObject);
begin
Information.Position:=poMainFormCenter;
Information.ShowModal;
end;

procedure TLlesy.SetPanel(VP: TVisiblePanel);
begin
  Uebersicht.Visible:=VP=vpUebersicht;
  Einstellungen.Visible:=VP=vpEinstellungen;
  case VP of
    vpUebersicht: LblInformation.Caption:='Übersicht: Fahrzeuge an- und abmelden';
    vpArchiv: ;
    vpDatenbank: ;
    vpEinstellungen:
      begin
        LblInformation.Caption:='Programm: Einstellungen bearbeiten';
        Einstellungen.SetFocus;
      end;
    vpSQLService: ;
  end;
end;

procedure TLlesy.TlBtnUebersichtClick(Sender: TObject);
begin
SetPanel(vpUebersicht);
end;

procedure TLlesy.TlBtnEinstellungenClick(Sender: TObject);
begin
SetPanel(vpEinstellungen);
end;

procedure TLlesy.TlBtnVollbildClick(Sender: TObject);
begin
  if not (Align=alClient) then
  begin
    DM.Anzeige.Top:=Top;
    DM.Anzeige.Left:=Left;
    DM.Anzeige.Width:=Width;
    DM.Anzeige.Height:=Height;
    Align:=alClient;
  end
  else
  begin
    Align:=alNone;
    Top:=DM.Anzeige.Top;
    Left:=DM.Anzeige.Left;
    Width:=DM.Anzeige.Width;
    Height:=DM.Anzeige.Height;
  end;
end;

end.
Delphi-Quellcode:
unit UEinstellungen;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ToolWin, ComCtrls, StdCtrls, ExtCtrls, XTCtrls, ImgList, UDM;

type
  TEinstellungen = class(TPanel)
  private
    { Private-Deklarationen }
    TlBr: TToolBar;
    TlBtnSichern: TToolButton;

    Information: TXTPanel;
    InfBenutzer: TXTEdit;
    InfComputer: TXTEdit;

    Datenbank: TXTPanel;
    DtbTreiber: TXTEdit;
    DtbServer: TXTEdit;
    DtbName: TXTEdit;

    Peripherie: TXTPanel;
    PerAmpelIP: TXTEdit;
    PerAmpelPort: TXTEdit;
    PerAnzeigeIP: TXTEdit;
    PerAnzeigePort: TXTEdit;
    procedure Enter(Sender: TObject);
  public
    { Public-Deklarationen }
    constructor Create(AOwner: TComponent; AParent: TWinControl);
  end;

implementation

constructor TEinstellungen.Create(AOwner: TComponent; AParent: TWinControl);
begin
  inherited Create(AOwner);
//Allgemeine Parameter vorbesetzen
  Parent:=AParent;
  BevelInner:=bvNone;
  BevelKind:=bkFlat;
  BevelOuter:=bvNone;
  ParentColor:=True;
  Top:=50; //Beliebiger Wert, der unterhalb vom Toolbar liegt
  Align:=alClient;
  AlignWithMargins:=True;
  Visible:=False;
  OnEnter:=Enter;
//Untergeordnete Elemente erzeugen
  TlBr:=TToolBar.Create(self);
  TlBr.Parent:=self;
  TlBr.DrawingStyle:=ComCtrls.dsGradient;
  TlBr.Height:=31;
  TlBr.ButtonHeight:=30;
  TlBr.ButtonWidth:=30;
  TlBtnSichern:=TToolButton.Create(self);
  TlBtnSichern.Parent:=TlBr;
  TlBtnSichern.ImageIndex:=6;

  Information:=TXTPanel.Create(self,self);
  Information.Caption:='Information';
  Information.Top:=35;
  Information.Height:=80;
  Information.Width:=260;
  Information.Enabled:=False;//Nur Information, keine Eingaben möglich
  InfBenutzer:=TXTEdit.Create(self,Information,30);
  InfBenutzer.Caption:='Benutzer';
  InfComputer:=TXTEdit.Create(self,Information,55);
  InfComputer.Caption:='Computer';

  Datenbank:=TXTPanel.Create(self,self);
  Datenbank.Caption:='Datenbank';
  Datenbank.Top:=125;
  Datenbank.Height:=105;
  Datenbank.Width:=260;
  DtbTreiber:=TXTEdit.Create(self,Datenbank,30);
  DtbTreiber.Caption:='Treiber';
  DtbServer:=TXTEdit.Create(self,Datenbank,55);
  DtbServer.Caption:='Server';
  DtbName:=TXTEdit.Create(self,Datenbank,80);
  DtbName.Caption:='Name';

  Peripherie:=TXTPanel.Create(self,self);
  Peripherie.Caption:='Peripherie';
  Peripherie.Top:=240;
  Peripherie.Height:=130;
  Peripherie.Width:=260;
  PerAmpelIP:=TXTEdit.Create(self,Peripherie,30);
  PerAmpelIP.Caption:='Ampel - IP';
  PerAmpelPort:=TXTEdit.Create(self,Peripherie,55);
  PerAmpelPort.Caption:='Ampel - Port';
  PerAnzeigeIP:=TXTEdit.Create(self,Peripherie,80);
  PerAnzeigeIP.Caption:='Anzeigetafel - IP';
  PerAnzeigePort:=TXTEdit.Create(self,Peripherie,105);
  PerAnzeigePort.Caption:='Anzeigetafel - Port';
end;

procedure TEinstellungen.Enter(Sender: TObject);
begin
  TlBr.Images:=DM.ImgLst24x24;
  InfBenutzer.Text:=DM.Benutzer;
  InfComputer.Text:=DM.Computer;
  DtbTreiber.Text:=DM.Datenbank.Treiber;
  DtbServer.Text:=DM.Datenbank.Server;
  DtbName.Text:=DM.Datenbank.Name;
end;

end.

Jürgen Thomas 8. Jun 2007 15:59

Re: Zugriffsverletzung, ich komm nicht drauf
 
Hallo,

ich verstehe (natürlich) nicht Deine ganze Konstruktion. Ich finde aber nirgends Maßnahmen, die Du beim Closing oder im Destruktor veranlasst. Für mich sieht es so aus, als ob das Programm "selbständig" zuerst das Datenmodul auflöst und erst danach das/die Panel(s); also geht die ImageList "flöten", aber ein Panel setzt ihre Existenz noch voraus.

Verfahrensvorschlag:
  1. Erzeuge zumindest Events, die beim Closing ausgelöst werden. (Bitte selbst suchen; ich habe ihre Delphi-Namen vergessen.)
  2. Löse dort per Befehl solche Verbindungen, die "gefährdet" sind.
  3. Steuere im MainForm und ggf. in der dpr-Datei selbst, was wann aufgelöst werden soll.
Ich hoffe, ich konnte helfen. Jürgen

SirThornberry 8. Jun 2007 16:03

Re: Zugriffsverletzung, ich komm nicht drauf
 
also mir fällt als erstes auf das du Object instanzierst aber diese nicht frei gibst. Dadurch können auch AV's auftreten.
Beispiel (trifft bei dir nicht zu verdeutlicht aber das es durch events passieren kann):
Man erstellt einen Timer der alle x millisekunden das OnTimer aufruft.
Dann schließt man das form welches auch frei gegeben wird und der Timer der nicht freigegeben wurde versucht weiterhin das Event aufzurufen was aber fehlschlägt da das Form frei gegeben ist wo die Eventmethode drin steckte.

Bevor solche leichtsinnigen Fehler nicht behoben sind ist es für mich verschenkte Zeit mir den Rest anzuschauen. Mir ist es lieber du opferst erstmal Zeit zum implementieren des Freigebens und für andere grundlegende Dinge.

Gremlin 8. Jun 2007 17:24

Re: Zugriffsverletzung, ich komm nicht drauf
 
@guidobrose

Sei mir nicht böse, aber es ist leider sehr schwierig, sich in deinem Code zurechtzufinden. Wär es eventuell möglich, den gesamten Code oder einen gekürzten Code mit einer "lauffähigen" AV als Attachment (Source keine Exe) beizulegen? Danke.

oldmax 10. Jun 2007 06:09

Re: Zugriffsverletzung, ich komm nicht drauf
 
Hi
Ok, ich weiß nicht, ob dir meine Antwort bei der Fehlerbeseitigung hilft, aber um das Datenmodul zuerst zu erzeugen und dann erst deine Form ist einfach unter Projekt->Optionen die Reihenfolge zu ändern. Erst das Datenmodul, dann die Form.
Das hilft dir zumindest, das du bei Form.Create ein gültiges Datenmodul hast.
Gruß oldmax

guidobrose 11. Jun 2007 06:03

Re: Zugriffsverletzung, ich komm nicht drauf
 
Danke für die Antworten bisher, da ich das hier auf der Arbeit mache (normalerweise programmiere ich Steuerungen) konnte ich bislang nicht antworten.

Ich gehe auch davon aus, dass es etwas damit zu tun hat, dass das Datenmodul zuerst freigegeben wird und darum etwas "fehlt". Ich versuche jetzt erst mal das DM zuerst zu erzeugen und anschließend den Rest.
Stimmt, ich gebe keine Objekte mehr frei, aber soviel ich jetzt gelernt habe, ist bei allen Objekten mit Owner, dieser zuständig und auch in der Lage, dies zu tun, wenn die Anwendung geschlossen wird. Irre ich mich hier? Einen Destruktor für TEinstellungen hatte ich übrigens schon einmal geschrieben, das hat aber nichts gefruchtet, darum habe ich ihn wieder entfernt.

Guido

hoika 11. Jun 2007 07:51

Re: Zugriffsverletzung, ich komm nicht drauf
 
Hallo,

kommentiere mal testweise die Zeile

TlBr.Images:=DM.ImgLst24x24;

aus.

Klar kommen jetzt Bildchen mehr,
aber ist dann die Scutzverletzung weg ?

Wenn ja, schreib in deinen Klassendestruktor (der zu Erzeuge ist) ein
TlBr.Images:=NIL rein


Heiko

guidobrose 11. Jun 2007 08:06

Re: Zugriffsverletzung, ich komm nicht drauf
 
@hoika: Das hatte ich schon gemacht und dann funktionierte es auch, die Sache mit dem Destruktor hatte ich ebenfalls schon probiert, allerdings ohne Erfolg.

Die gute Nachricht: Es funktioniert jetzt!

Ich lasse das Datenmodul jetzt nicht mehr automatisch erzeugen, sondern mache das in der Create-Methode des Hauptformulars selbst. Danach war die (oder eine) Zugriffsverletzung zwar immer noch vorhanden, aber es lag jetzt daran, dass die ADOConnection (im Datenmodul) noch geöffnet war. Jetzt wird diese im Destruktor des Hauptformular geschlossen und es geht.

Danke allen Helfern.


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:07 Uhr.

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