Toon posts:

[Delphi] Problemen met constructor/destructor in classes

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik heb de volgende classes:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
unit Unit1;

interface

type
  TFormDropDown = class(TForm)
  private
    ...
  private
    ...
  protected
    ...
  public
    constructor Create(AOwner: TComponent); override;
    ...
  end;

  TComboboxMultiColumn = class(TEdit)
  private
    ...
  protected
    ...
  public
    constructor Create(AOwner: TComponent); override;
  published
    ...
  end;

implementation

constructor TFormDropDown.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ...
end;

constructor TComboboxMultiColumn.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ControlStyle := ControlStyle + [csReplicatable];

  FButton := TSpeedButton.Create(Self);
  FButton.Width := cButtonWidth;
  FButtonWidth := cButtonWidth;
  FButton.ParentFont := false;
  FButton.Glyph.LoadFromResourceName(HInstance, 'IMGARROWDOWN');
  FButton.Cursor := crArrow;
  FButton.OnClick := ButtonClick;
  FButton.OnMouseDown := ButtonMouseDown;

  SetButtonBounds;

  FButton.Parent := Self;

  SetEditRect;
  Invalidate;

  FDropDown := False;

  FDropDownForm := TFormDropDown.Create(Self);

  FListViewDropDownList := TListView.Create(FDropDownForm);
  with FListViewDropDownList do
  begin
    ViewStyle := vsReport;
    Ctl3D := False;
    Align := alClient;
    Parent := FDropDownForm;
    ParentFont := True;
    OnMouseMove := ListView1MouseMove;
    with Columns.Add do
      Caption := 'Naam';
  end;
end;

destructor TComboboxMultiColumn.Destroy;
begin
  FButton.Free;
  FListViewDropDownList.Free;
  FDropDownForm.Free;
  inherited Destroy;
end;

end.


Volgens mij is er niks mis met deze code. Maar tijdens run-time gaat er iets verkeerd.

Ik heb op mijn form een component staan van het type TComboBoxMultiColumn.

Dus de constructor van TComboBoxMultiColumn wordt aangeroepen. In deze constructor gaat het fout bij het aanmaken van het DropDownForm.

De constructor van de klasse TFormDropDown wordt dus aan geroepen.
Vevolgens staat daar als eerste regel inherited Create(AOwner). Dit zou dus de constructor van de TForm moeten aanroepen. Maar het gekke is dat die de destructor van TComboBoxMultiColumn aanroept.

Hoe kan dat?

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Geen idee. Ik zou nog even verder/beter debuggen, want wat je verteld zou nooit kunnen en mogen. Maar het ziet er allemaal wel goed uit wat je gemaakt hebt.

We adore chaos because we like to restore order - M.C. Escher


  • Delphi32
  • Registratie: Juli 2001
  • Laatst online: 31-08 21:58

Delphi32

Heading for the gates of Eden

Yep, debuggen. Het enige wat ik zo kan zien (het ziet er verder goed uit hoor), is dat er iets fout gaat in de constructor van TFormDropDown. Dan wordt er een exception geraised in TFormDropDown.Create, als je die niet afhandelt doet ie eerst TFormDropDown.Destroy, vervolgens gaat de unhandled exception de TComboBoxMultiColumn in, dus gaat die ook naar de Destroy.

Verwijderd

Topicstarter
Ik weet inmiddels wat voor fout er op treedt. Het is de volgende:

1814 The specified resource name cannot be found in the image file. ERROR_RESOURCE_NAME_NOT_FOUND

In de source gebruik ik een resource bestand waarin de bitmap staat met het pijltje:

code:
1
2
3
{$R ImgArrow.res}

FButton.Glyph.LoadFromResourceName(HInstance, 'IMGARROWDOWN');


Maar dit heeft gewoon altijd gewerkt. Echter sinds ik de classe TFormDropDown er in hebt staan, werkt het niet meer en ontstaat dus deze error.

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

HInstance wijst waarschijnlijk naar iets anders dan waar het vroeger heen wees?

We adore chaos because we like to restore order - M.C. Escher


Verwijderd

Topicstarter
Als ik deze 2 regels uitschakel dan krijg ik nog een resource error.

Resource TFormDropDown not found

Waar kan dat nou aan liggen? Ik kan er nergens iets over vinden.

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Hij probeert de TFormDropDown resource te lezen (waar de properties enzo instaan), maar dat lukt kennelijk niet.

Heeft je form wel een bijbehorende .dfm?
{$R *.dfm} vergeten?
Het lijkt me zoiezo netter om je form in een aparte unit te zetten.

Er zit ook een help bij. Heb je die al doorgekeken of ben je als een echte techneut zonder te lezen eerst aan het werk gegaan? ;)

We adore chaos because we like to restore order - M.C. Escher


  • Delphi32
  • Registratie: Juli 2001
  • Laatst online: 31-08 21:58

Delphi32

Heading for the gates of Eden

Bij een form hoort altijd een {$ form.RES} file, anders weet ie niet wat ie moet laden :) Probeer je TDropDownForm als normaal form in een andere unit te maken, die je dan uset in je component, dan ben je van het probleem af.

Verwijderd

Topicstarter
Ik heb het form nu in een aparte unit gezet en het werkt.

Bedankt.

Verwijderd

FButtonWidth := cButtonWidth; hoe kan het dat dit wel goed gaat dan? "FButtonWidth" is niet gedeclareerd als variabele. :?

Er boven heb je het wel goed staan: FButton.Width := cButtonWidth;

  • Delphi32
  • Registratie: Juli 2001
  • Laatst online: 31-08 21:58

Delphi32

Heading for the gates of Eden

Verwijderd schreef op 10 augustus 2002 @ 20:50:
FButtonWidth := cButtonWidth; hoe kan het dat dit wel goed gaat dan? "FButtonWidth" is niet gedeclareerd als variabele. :?

Er boven heb je het wel goed staan: FButton.Width := cButtonWidth;
Dat FButtonWidth niet gedeclareerd is, is waarschijnlijk schijn. In Delphi is het gebruikelijk om private 'variabelen' in een class, te declareren met prefix F. Dus zo:
code:
1
2
3
4
type TMyObjectWithPrivateMember = class(TObject)
  private
    FButtonWidth: integer;
  end;

De variable (member, volgens sommigen, of attribute of hoe je het ook noemt) is binnen de class te gebruiken. Aangezien de class declaratie niet in dit topic staat, heb je dus ook niet gezien dat ie gedeclareerd werd :) Maar hij is er wel. Zo te zien wil TS de width van de button bijhouden buiten de button zelf (ivm resizing, gok ik zo).
Dus
code:
1
2
FButton.Width := cButtonWidth; //verandert de width van FButton
FButtonWidth  := cButtonWidth; //zet private var naar de constante cButtonWidth

Verwijderd

Delphi32 schreef op 11 augustus 2002 @ 00:09:
[...]

Dat FButtonWidth niet gedeclareerd is, is waarschijnlijk schijn. In Delphi is het gebruikelijk om private 'variabelen' in een class, te declareren met prefix F. Dus zo:
code:
1
2
3
4
type TMyObjectWithPrivateMember = class(TObject)
  private
    FButtonWidth: integer;
  end;

De variable (member, volgens sommigen, of attribute of hoe je het ook noemt) is binnen de class te gebruiken. Aangezien de class declaratie niet in dit topic staat, heb je dus ook niet gezien dat ie gedeclareerd werd :) Maar hij is er wel. Zo te zien wil TS de width van de button bijhouden buiten de button zelf (ivm resizing, gok ik zo).
Dus
code:
1
2
FButton.Width := cButtonWidth; //verandert de width van FButton
FButtonWidth  := cButtonWidth; //zet private var naar de constante cButtonWidth
Ik d8 laat ik het toch maar ff vermelden. IIg bedankt voor je repley. Jammer dat het geen nieuwe info opleverde, maar dan kon / kun jij ook niet weten :)

  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 01-09 21:18

Tomatoman

Fulltime prutser

Wat er gebeurt is heel logisch. Als een constructor van een bepaalde class een niet afgehandelde exception tegenkomt, is blijkbaar het creëren van de class niet goedgegaan. Daarom wordt meteen de destructor aangeroepen om de puinhopen van de half opgebouwde class op te ruimen.

Ik heb even een voorbeeldje in elkaar geklust om dat duidelijk te maken. Het is een component die alleen op een form mag worden geplaatst - dit wordt in de constructor afgedwongen. Als de owner van TMyComponent een descendant is van TCustomForm, gaat alles goed. Pas als de component later wordt vernietigd, wordt de class name van de owner getoond. Maar als de owner geen TCustomForm descendant is, wordt er een exception gemaakt (EAbort in dit geval) en wordt de destructor direct aangeroepen.
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
type
  class TMyComponent = class(TComponent)
  private
    FString: string;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

constructor TMyComponent.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  if AOwner is TCustomForm then
    FString := 'Owner is een ' + AOwner.ClassName
  else
  begin
    FString := 'Owner is geen descendant van TCustomForm';
    Abort;   // maak een EAbort exception
  end
end;

destructor TMyComponent.Destroy;
begin
  ShowMessage(FString);
  inherited;
end;

[ Voor 0% gewijzigd door Tomatoman op 11-08-2002 15:16 . Reden: typo ]

Een goede grap mag vrienden kosten.


Verwijderd

Topicstarter
Verwijderd schreef op 10 augustus 2002 @ 20:50:
FButtonWidth := cButtonWidth; hoe kan het dat dit wel goed gaat dan? "FButtonWidth" is niet gedeclareerd als variabele. :?

Er boven heb je het wel goed staan: FButton.Width := cButtonWidth;
Er staat inderdaad het volgende in de classe:

code:
1
2
private
    FButtonWidth: Integer;

(Deze code heb ik niet zelf geschreven en het lijkt er op dat deze classe variabele niet nodig is, maar dat gewoon FButton.Width gebruikt kan worden).
Pagina: 1