cannot assign a nil to a font

Rund um die LCL und andere Komponenten

cannot assign a nil to a font

Beitragvon Maik81SE » 10. Nov 2017, 17:19 cannot assign a nil to a font

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'
Maik81SE
 
Beiträge: 70
Registriert: 30. Sep 2011, 13:07
Wohnort: Lübeck
OS, Lazarus, FPC: Win7/(en)Debian/Ubuntu 14:10 (L 1.2.4+dfsg-1. FPC 2.6.x) | 
CPU-Target: 64bit; arm; avr
Nach oben

Beitragvon Maik81SE » 10. Nov 2017, 17:37 Re: cannot assign a nil to a font

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'
Maik81SE
 
Beiträge: 70
Registriert: 30. Sep 2011, 13:07
Wohnort: Lübeck
OS, Lazarus, FPC: Win7/(en)Debian/Ubuntu 14:10 (L 1.2.4+dfsg-1. FPC 2.6.x) | 
CPU-Target: 64bit; arm; avr
Nach oben

Beitragvon Mathias » 10. Nov 2017, 18:12 Re: cannot assign a nil to a font

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 gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3201
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon wp_xyz » 10. Nov 2017, 19:11 Re: cannot assign a nil to a font

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;
wp_xyz
 
Beiträge: 2253
Registriert: 8. Apr 2011, 08:01

Beitragvon Maik81SE » 10. Nov 2017, 20:09 RE: cannot assign a nil to a font [*gelöst]

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'
Maik81SE
 
Beiträge: 70
Registriert: 30. Sep 2011, 13:07
Wohnort: Lübeck
OS, Lazarus, FPC: Win7/(en)Debian/Ubuntu 14:10 (L 1.2.4+dfsg-1. FPC 2.6.x) | 
CPU-Target: 64bit; arm; avr
Nach oben

Beitragvon wp_xyz » 11. Nov 2017, 13:41 Re: RE: cannot assign a nil to a font [*gelöst]

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.
wp_xyz
 
Beiträge: 2253
Registriert: 8. Apr 2011, 08:01

• Themenende •

Zurück zu Komponenten und Packages



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 3 Gäste

porpoises-institution
accuracy-worried