cannot assign a nil to a font

Rund um die LCL und andere Komponenten
Antworten
Benutzeravatar
Maik81SE
Beiträge: 308
Registriert: Fr 30. Sep 2011, 14:07
OS, Lazarus, FPC: Debian 12 (L 3.0.0.3 FPC 3.2.2); Windows 10 (L 3.99.0.0 FPC 3.2.0)
CPU-Target: x86-64; arm; avr
Wohnort: Lübeck
Kontaktdaten:

cannot assign a nil to a font

Beitrag von Maik81SE »

Moin...

ich kann mir gerade mal net helfen.

Ich bin aktuell dabei ein Komblettes Programm so zu schreiben, das alle Kombonenten zur LZ erstellt werden.
Soweit passt auch alles, nur diese Zeile macht mir gerade etwas Ärger.

Code: Alles auswählen

SetLength(DB, 3);


hier mal noch ein weiterer Auszug aus meiner Definistion.

Code: Alles auswählen

  public
    { public declarations }
    CheckBox                  : TCheckBox;
    Logo                      : TImage;
 
    Col                       : Array of TColumn;
    Datum                     : Array of TDateEdit;
    DB                        : Array of TDBGrid;
    Directory                 : Array of TDirectoryEdit;
    LEdit                     : Array of TLabeledEdit;
    TB                        : Array of TComboBox;
    _Label                    : Array of TLabel;


Code: Alles auswählen

procedure TForm1.FormCreate(Sender: TObject);
begin
  SetLength(Col, 30);
  SetLength(Datum, 2);
 
  SetLength(Directory, 2);
  SetLength(LEdit, 20);
  SetLength(TB, 2);
  SetLength(_Label, 20);
 
  SetLength(DB, 3); // <--- Hier wird der Fehler "cannot assign a nil to a font" ausgelöst!
end;


Wäre ich da ggf besser beraten wenn ich diese 3 Datentabellen einzeln erstelle? Sprich das Array so ändere

Code: Alles auswählen

//    DB                        : Array of TDBGrid;
    ADB                       : TDBGrid;
    MDB                       : TDBGrid;
    RDB                       : TDBGrid;
 

Code: Alles auswählen

label.caption:= 'gnublin.no-ip.info'
Debian 12 (L 3.0.0.3 FPC 3.2.2);
windows 10 (L 3.99.0.0 FPC 3.2.0)

Benutzeravatar
Maik81SE
Beiträge: 308
Registriert: Fr 30. Sep 2011, 14:07
OS, Lazarus, FPC: Debian 12 (L 3.0.0.3 FPC 3.2.2); Windows 10 (L 3.99.0.0 FPC 3.2.0)
CPU-Target: x86-64; arm; avr
Wohnort: Lübeck
Kontaktdaten:

Re: cannot assign a nil to a font

Beitrag von Maik81SE »

Maik81SE hat geschrieben:Wäre ich da ggf besser beraten wenn ich diese 3 Datentabellen einzeln erstelle? Sprich das Array so ändere

Code: Alles auswählen

//    DB                        : Array of TDBGrid;
    ADB                       : TDBGrid;
    MDB                       : TDBGrid;
    RDB                       : TDBGrid;
 


Habe gerade mall meine Gedanken verfolgt und der Fehler scheint wohl doch an einer anderen Stelle zu liegen, als ich vermutet habe. :shock:

Code: Alles auswählen

    RDB                       := TDBGrid.Create(nil);

Würde ungern auf die Altertive zurückgreifen wollen

Code: Alles auswählen

label.caption:= 'gnublin.no-ip.info'
Debian 12 (L 3.0.0.3 FPC 3.2.2);
windows 10 (L 3.99.0.0 FPC 3.2.0)

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: cannot assign a nil to a font

Beitrag von Mathias »

Code: Alles auswählen

 RDB := TDBGrid.Create(nil);

Das nil gefällt mit nicht, normalerweise, gibt man dort die Klasse mit, in der die Komponente erstellt wird.

Hier ein Beispiel.

Code: Alles auswählen

procedure TForm1.FormCreate(Sender: TObject);
begin
  RDB := TDBGrid.Create(Self);
end;


Dies hat dann auch den Vorteil, wen das Form geschlossen wird, dann werden die Komponenten auch automatisch aufgeräumt.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: cannot assign a nil to a font

Beitrag von wp_xyz »

Da ist mit Sicherheit irgendetwas anderes faul. SetLength(DB, 3) dimensioniert das Array DB auf drei Elemente; die Elemente sind in deinem Beispiel DBGrids. Die Grids werden dadurch NICHT erzeugt. Du musst alse wirklich jedes Grid einzeln erzeugen, genauso wie bei deiner "Ausweichlösung", nur kannst du jedes Grid halt als Arrayelement ansprechen:

Code: Alles auswählen

var
  DB: array of TDBGrid;
...
  for i:=0 to High(DB) do
    DB[i] := TDBGrid.Create(...); // hier unbedingt einen Owner angeben, üblicherweise ist das das Formular!
    DB[i].Parent := ....  // das Formular oder oft ein Panel oder ein TabSheet o,ä. - das Element, das das Grid direkt enthält
    ...
  end;

Benutzeravatar
Maik81SE
Beiträge: 308
Registriert: Fr 30. Sep 2011, 14:07
OS, Lazarus, FPC: Debian 12 (L 3.0.0.3 FPC 3.2.2); Windows 10 (L 3.99.0.0 FPC 3.2.0)
CPU-Target: x86-64; arm; avr
Wohnort: Lübeck
Kontaktdaten:

RE: cannot assign a nil to a font [*gelöst]

Beitrag von Maik81SE »

Mathias hat geschrieben:Hier ein Beispiel.

Code: Alles auswählen

procedure TForm1.FormCreate(Sender: TObject);
begin
  RDB := TDBGrid.Create(Self);
end;


Dies hat dann auch den Vorteil, wen das Form geschlossen wird, dann werden die Komponenten auch automatisch aufgeräumt.


Darfst mich gerne Korrigieren, aber dies ist meines Wissens nach eher unter Delphi üblich.
Unter Larazus habe ich dies auch schon anfänglich versucht, bin ich aber bei der suche uA hier im Forum über den Hinweiß gestolpert, das da eher NIL verwendet werden sollte.

wp_xyz hat geschrieben:Da ist mit Sicherheit irgendetwas anderes faul.


Diese Zeile hat diesen Fehler ausgelöst

Code: Alles auswählen

    for i := 0 to 29 do Col[i]:= TColumn.Create(nil);

Sinn sollte es sein, ca 30 Zellen Blank aufzubauen und diese dann bei bedarf dem jeweiligen Grid zuordnen. aber da werd ich mir was anderes einfallen lassen.

ergo ich baue diese jetzt so auf.

Code: Alles auswählen

    RDB                       := TDBGrid.Create(nil);
    with RDB do begin
      Parent                  := Form1;
      Align                   := alBottom;
      for i := 0 to 8 do Columns.Add;
      with Columns do begin
        Items[0].FieldName:= 'R-ID';
      end;
    end;


somit nun offtropic

Code: Alles auswählen

label.caption:= 'gnublin.no-ip.info'
Debian 12 (L 3.0.0.3 FPC 3.2.2);
windows 10 (L 3.99.0.0 FPC 3.2.0)

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: RE: cannot assign a nil to a font [*gelöst]

Beitrag von wp_xyz »

Maik81SE hat geschrieben:Darfst mich gerne Korrigieren, aber dies ist meines Wissens nach eher unter Delphi üblich.
Unter Larazus habe ich dies auch schon anfänglich versucht, bin ich aber bei der suche uA hier im Forum über den Hinweiß gestolpert, das da eher NIL verwendet werden sollte.

Das hat nichts mit Delphi oder Lazarus zu tun, sondern damit, dass du offenbar nicht verstanden hast, was dieser Parameter macht. Alle Objekte, die von TComponent abgeleitet sind, haben einen "Owner", das ist das Objekt, das dafür verantwortlich ist, die Komponente zu löschen. Üblicherweise gibt man dafür das Formular an, auf dem die Komponente sitzt, denn wenn das Formular zerstört wird, dann soll es auch die Komponente mit löschen. Mit Hilfe dieses Mechanismus muss sich der Programmierer nicht mehr darum kümmern, die von ihm erzeugten Komponenten zu entfernen. Nur in Spezialfällen ist es sinnvoll, nil eintragen, also "kein anderes Objekte soll die Komponente zerstören" - wenn das niemand macht, dann muss man sich selbst darum kümmern (wie im richtigen Leben). Dieses Vorgehen ist nur dann sinnvoll, wenn es sich um eine kurze Prozedur handelt, so dass man die Lebensdauer des Komponente überblicken kann. Es gab bei Delphi einmal eine Zeit, in der es mit der Situation nicht klarkam, dass jemand anders als der eingetragene Owner eine Komponente gelöscht hat, daher wahrscheinlich dein aufgeschnapptes "eher unter Delphi üblich".

Hier ein Beispiel für diesen Spezialfall. Dabei den try-finally-Block nicht vergessen, damit bei einer Exception während der herrenlosen Komponente kein Speicherleck entsteht. Etwa so

Code: Alles auswählen

procedure TForm1.ShowDataDialog;
var
  F: TDataForm;
begin
  F := TDataForm.Create(nil);
  try
    F.ShowModal;
  finally
    F.Free;
  end;
end;


Maik81SE hat geschrieben:Diese Zeile hat diesen Fehler ausgelöst

Code: Alles auswählen

    for i := 0 to 29 do Col[i]:= TColumn.Create(nil);


Hier sind gleich zwei Fehler.

Zum einen dein allseits geliebtes "nil", das hier fatale Auswirkungen hat. Denn TColumn ist nicht von TComponent abgeleitet, sondern von TCollectionItem (das in der Komponentenhierachie von TPersistent abzweigt, dem Vorfahren von TComponent). All diese Elemente haben keinen "Owner" so wie die Komponenten. Das, was hier im Create eingetragen wird, ist die Collection, zu der das CollectionItem gehört. CollectionItem und Collection kommunizieren immer wieder miteinander, und wenn dann das Item die Liste nicht kennt, in der es hängt, kann das nur schief gehen.

Um den Benutzer von diesen internen Details zu schützen, werden CollectionItems nicht mit Create erzeugt - das ist der zweite Fehler -, sondern mit der Collection-Methode Add, die das Item erzeugt und auch auch gleich die Collection im Item einträgt.

Aus diesem Grund funktioniert dein Code am Ende richtig.

Antworten