[Delphi] Component met timer en default waarden

Pagina: 1
Acties:
  • 107 views sinds 30-01-2008
  • Reageer

  • jelmervos
  • Registratie: Oktober 2000
  • Niet online

jelmervos

Simple user

Topicstarter
Ik had even een paar vraagjes. Ik heb een component daar zit een timer in, deze wordt bij de constructor van het component gemaakt:
code:
1
2
3
4
5
  TimerRefresh := TTimer.Create(Self);
  TimerRefresh.Enabled := False;
  TimerRefresh.Interval := FRefreshInterval;
  TimerRefresh.Enabled := FRefreshEnabled;
  TimerRefresh.OnTimer := TimerRefreshTimer;

Nou heeft het component dus 2 properties die hier mee te maken hebben, namelijk RefreshInterval (interval van de timer) en RefreshEnabled (enabled van de timer). Alleen hoe geeft ik hier nou default waardes aan, zodat als je een nieuw component plaatst gelijk die default waardes heeft. Natuurlijk moeten de waardes die je insteld gebruikt worden.

Nog een vraag: je kunt bij properties in je component een default opgeven (directive), maar je kunt zo ook in de constructor zetten door de FName variabelen te zetten, wat is het verschil en wat is het beste?

"The shell stopped unexpectedly and Explorer.exe was restarted."


  • whoami
  • Registratie: December 2000
  • Laatst online: 14:36
Met 2 constructors werken?
Eentje met en eentje zonder argumenten? Als je de constructor zonder args gebruikt, worden de waarden op een bepaalde default waarde ingesteld, en in het andere geval geef je de waarden door aan de constructor.

https://fgheysels.github.io/


  • jelmervos
  • Registratie: Oktober 2000
  • Niet online

jelmervos

Simple user

Topicstarter
En hoe werkt dat dan precies? Hij gebruikt toch altijd constructor Create?

Eigenlijk moet hij design-time de waarden standaard instellen en run-time moet hij de waarden gebruiken die de gebruiker heeft gezet.

"The shell stopped unexpectedly and Explorer.exe was restarted."


  • whoami
  • Registratie: December 2000
  • Laatst online: 14:36
Je kan toch de constructor overloaden?
code:
1
2
3
4
5
6
7
8
9
constructor Create()
begin
end;

constructor Create(Waarde1 : Integer; Waarde2 : Integer)
begin
 property := Waarde1;
 property := Waarde2;
end;

en in je code kan je dan toch hetvolgende doen:
code:
1
2
Object := TClass.Create(); // default constr.
Object2 := TClass.Create(StrToInt(Edit1.Text), StrToInt(Edit2.Text));

https://fgheysels.github.io/


  • jelmervos
  • Registratie: Oktober 2000
  • Niet online

jelmervos

Simple user

Topicstarter
Maar het gaat er niet om dat ik run-time de properties kan zetten. Het gaat erom dat als je een nieuw component op je form zet dat bepaalde properties standaard zijn ingevuld. Dus bijvoorbeelde de RefreshInterval op 3000 en de RefreshEnabled op False.
Dat is opzich geen probleem, maar bij de Create van het component moet ook een timer worden aangemaakt. Deze moet de opties hebben die je in de properties hebt ingesteld.

Ik heb nu dus dit:
code:
1
2
3
4
5
6
7
8
  FRefreshInterval := 30000;
  FRefreshEnabled := False;

  TimerRefresh := TTimer.Create(Self);
  TimerRefresh.Enabled := False;
  TimerRefresh.Interval := FRefreshInterval;
  TimerRefresh.Enabled := FRefreshEnabled;
  TimerRefresh.OnTimer := TimerRefreshTimer;

Maar dan is de RefreshInterval ALTIJD 30000, ook al vul je in de Object Inspector iets anders in. Dit is ook wel logisch. Maar hoe geeft ik nu aan dat het standaard 30000 moet zijn, maar dat als de gebruiker iets anders invult dat hij dit run-time toch goed doorvoert.

"The shell stopped unexpectedly and Explorer.exe was restarted."


Verwijderd

misschien zoiets:
code:
1
2
3
4
5
6
7
8
9
10
IF (csDesigning IN ComponentState) THEN
BEGIN
  FRefreshInterval := 30000;
  FRefreshEnabled := False;
END;
TimerRefresh := TTimer.Create(Self);
TimerRefresh.Enabled := False;
TimerRefresh.Interval := FRefreshInterval;
TimerRefresh.Enabled := FRefreshEnabled;
TimerRefresh.OnTimer := TimerRefreshTimer;

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 09-09 21:25

Creepy

Tactical Espionage Splatterer

code:
1
2
3
4
5
6
7
constructor TTimer.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FEnabled := True;
  FInterval := 1000;
  FWindowHandle := AllocateHWnd(WndProc);
end;

Dit is de TTimer.create (Delphi 5)
Dus een afgeleide maken, en dan de Finterval zetten zou genoeg moeten zijn. Waarschijnlijk vangt het form waar je je timer op zet het 1 en ander af (past de properties na de create aan..)

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • jelmervos
  • Registratie: Oktober 2000
  • Niet online

jelmervos

Simple user

Topicstarter
Dat is idd waar, de properties zoals deze gezet zijn in de Object Inspector worden na de create gezet. Daarom kun in de Create de standaard waarden van de properties instellen.

Alleen gaat het nu dus niet helemaal goed. Ik zal de boven genoemde oplossing zo even testen.

"The shell stopped unexpectedly and Explorer.exe was restarted."


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 04-09 14:38

curry684

left part of the evil twins

Je antwoord staat gewoon in de help bij 'Creating properties':
Note: Declaring a default value does not set the property to that value. The components constructor method should initialize property values when appropriate. However, since objects always initialize their data members to 0, it is not strictly necessary for the constructor to set integer properties to 0, string properties to null, or Boolean properties to false.

Professionele website nodig?


  • jelmervos
  • Registratie: Oktober 2000
  • Niet online

jelmervos

Simple user

Topicstarter
(csDesigning in ComponentState) werkt helaas niet, hij zet dan de properties niet op die waarde zodra je een nieuw component op je form plaatst.

Hoe moet ik het dan precies doen met die afgeleide van TTimer. Ik heb een afgeleide gemaakt, en de Create overrided maar wat moet ik er dan precies mee?

"The shell stopped unexpectedly and Explorer.exe was restarted."


Verwijderd

Hiervoor moet je de "loaded" procedure voor gebruiken. Standaard kom je hem niet tegen, maar bij "component creation" dus wel. De "loaded" wordt na create aangeroepen om de object inspector waarden te laden...

  • jelmervos
  • Registratie: Oktober 2000
  • Niet online

jelmervos

Simple user

Topicstarter
Dus ik override de Loaded procedure en ga daar mijn Timer maken?

"The shell stopped unexpectedly and Explorer.exe was restarted."


Verwijderd

Nee, als je een property "published" maakt (ik neem aan dat je dat weet?), zou hij (delphi) hem automatisch moeten overnemen na de create.
Evt in "loaded" kun je hem overriden.

Meer hierover, zie borland help "Creating properties: Overview"

  • jelmervos
  • Registratie: Oktober 2000
  • Niet online

jelmervos

Simple user

Topicstarter
Hehe, ik heb dit gedaan:
code:
1
2
3
4
5
6
7
8
9
procedure TMyComp.Loaded;
begin
  inherited;
  TimerRefresh := TTimer.Create(Self);
  TimerRefresh.Enabled := False;
  TimerRefresh.Interval := FRefreshInterval;
  if not (csDesigning in Self.ComponentState) then  TimerRefresh.Enabled := FRefreshEnabled;
  TimerRefresh.OnTimer := TimerRefreshTimer;
end;

En in de Create van TMyComp:
code:
1
2
  FRefreshEnabled := False;
  FRefreshInterval := 30000;

En dat werkt goed, maar is het slim?

"The shell stopped unexpectedly and Explorer.exe was restarted."


Verwijderd

Hier een voorbeeld van een panel met een timer, panel heeft published propertys (zie object inspector), zodat je ze zelf kunt instellen, en deze neemt hij als het goed is mee. Als je hier iets anders insteld dan de default in de create, zou hij de nieuwe waarde moeten overnemen tijdens de "loaded" (merk je nix van).

// edit: test procedure toegevoegd en HET WERKT!
// na instellen in object inspector op 3000 geeft netjes
// 3000 aan...

unit Panel1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls;

type
TPanel1 = class(TPanel)
private
{ Private declarations }
FTimer: TTimer;
FMijnInterval: integer;
FMijnEnabled: boolean;
procedure SetMijnInterval(const Value: integer);
procedure SetMijnEnabled(const Value: boolean);
protected
{ Protected declarations }
public
constructor Create(AOwner: TComponent);
procedure test;
{ Public declarations }
published
{ Published declarations }
property MijnInterval:integer read FMijnInterval write SetMijnInterval;
property MijnEnabled:boolean read FMijnEnabled write SetMijnEnabled;
end;

procedure Register;

implementation

procedure Register;
begin
RegisterComponents('Samples', [TPanel1]);
end;

constructor TPanel1.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FMijnInterval:= 1000;
FMijnEnabled:= true;

FTimer := TTimer.Create(self);
Ftimer.Enabled := FMijnEnabled;
FTimer.Interval := FMijnInterval;
end;

procedure TPanel1.SetMijnEnabled(const Value: boolean);
begin
FMijnEnabled := Value;
end;

procedure TPanel1.SetMijnInterval(const Value: integer);
begin
FMijnInterval := Value;
end;


procedure TPanel1.test;
begin
self.caption := inttostr(FMijnInterval);
end;

end.

  • jelmervos
  • Registratie: Oktober 2000
  • Niet online

jelmervos

Simple user

Topicstarter
Die Timer wordt dan ook in design time al ge-enabled, dus als je dan een ShowMessage ofzo hebt in de OnTimer event dan krijg je die ook in de IDE. :)

"The shell stopped unexpectedly and Explorer.exe was restarted."


Verwijderd

Is natuurlijk maar een vb, de destroctor moet nog bij, natuurlijk een afhandeling van of in designtime of runtime ed.

  • jelmervos
  • Registratie: Oktober 2000
  • Niet online

jelmervos

Simple user

Topicstarter
Maar ik kom nergens meer de overrided procedure Loaded tegen.

"The shell stopped unexpectedly and Explorer.exe was restarted."


Verwijderd

Die heb je ook niet nodig (sorry voor de eerdere posting van wel). Gaat allemaal auto, als je tenminste maar published propertys gebruikt.

  • jelmervos
  • Registratie: Oktober 2000
  • Niet online

jelmervos

Simple user

Topicstarter
Het werkt nu ook aardig, alleen wordt de timer in design time ook gemaakt + ge-enabled, dit is niet echt de bedoeling. Ik doe nu dit:
code:
1
2
3
4
5
  TimerRefresh := TTimer.Create(Self);
  TimerRefresh.Enabled := False;
  TimerRefresh.Interval := FRefreshInterval;
  if not (csDesigning in Self.ComponentState) then TimerRefresh.Enabled := FRefreshEnabled;
  TimerRefresh.OnTimer := TimerRefreshTimer;

Maar toch wordt hij ge-enabled.

"The shell stopped unexpectedly and Explorer.exe was restarted."


Verwijderd

Dan waarschijnlijk toch loaded gebruiken en daar
"als desiging -> enabled := false"

Komt natuurlijk door published property "mijnenabled"
dom dom dom van mijn... ;)

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 09-09 21:25

Creepy

Tactical Espionage Splatterer

Op woensdag 17 april 2002 16:16 schreef jelmervos het volgende:
Het werkt nu ook aardig, alleen wordt de timer in design time ook gemaakt + ge-enabled, dit is niet echt de bedoeling. Ik doe nu dit:
code:
1
2
3
4
5
  TimerRefresh := TTimer.Create(Self);
  TimerRefresh.Enabled := False;
  TimerRefresh.Interval := FRefreshInterval;
  if not (csDesigning in Self.ComponentState) then TimerRefresh.Enabled := FRefreshEnabled;
  TimerRefresh.OnTimer := TimerRefreshTimer;

Maar toch wordt hij ge-enabled.
Een TTimer is default altijd enabled na een TTimer.Create

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Verwijderd

Waarschijnlijk ben je er al uit, maar ik zou een method StartTimer en StopTimer maken.

Als de ComponentState loading of designing is doe je niets in die methods.

In de Loaded method roep je eventueel StartTimer aan.

In de StartTimer method wordt een TTimer object gemaakt als die nog niet bestaat.

In de Create zet je de default properties.

Code ziet er dan zoiets uit:
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
85
86
87
88
89
90
91
92
93
94
95
96
97
type
  TMyComp = class(TComponent)
  private
    FTimer: TTimer;
    FRefreshEnabled: Boolean;
    FRefreshInterval: Integer;
    procedure SetRefreshEnabled(const Value: Boolean);
    procedure SetRefreshInterval(const Value: Integer);
  protected
    procedure Loaded; override;
    procedure StartTimer;
    procedure StopTimer;
    procedure TimerEvent(Sender: TObject);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property RefreshInterval: Integer read FRefreshInterval write
    SetRefreshInterval;
    property RefreshEnabled: Boolean read FRefreshEnabled write
    SetRefreshEnabled;
  end;

[..]

constructor TMyComp.Create(AOwner: TComponent);
begin
  inherited;
  FRefreshEnabled := False;
  FRefreshInterval := 1000;
end;

destructor TMyComp.Destroy;
begin
  FTimer.Free;
  inherited;
end;

procedure TMyComp.Loaded;
begin
  inherited;
  if RefreshEnabled then
    StartTimer;
end;

procedure TMyComp.SetRefreshEnabled(const Value: Boolean);
begin
  if FRefreshEnabled <> Value then
  begin
    FRefreshEnabled := Value;
    if FRefreshEnabled then
    StartTimer
    else
    StopTimer;
  end;
end;

procedure TMyComp.SetRefreshInterval(const Value: Integer);
begin
  if FRefreshInterval <> Value then
  begin
    StopTimer;
    FRefreshInterval := Value;
    if RefreshEnabled then
    StartTimer;
  end;
end;

procedure TMyComp.StartTimer;
begin
  if ComponentState * [csDesigning, csLoading] <> [] then
    Exit;
  if not Assigned(FTimer) then
  begin
    FTimer := TTimer.Create(Self);
    FTimer.Enabled := False;
    FTimer.OnTimer := TimerEvent;
  end;
  FTimer.Interval := RefreshInterval;
  FTimer.Enabled := True;
end;

procedure TMyComp.StopTimer;
begin
  if ComponentState * [csDesigning, csLoading] <> [] then
    Exit;
  if not Assigned(FTimer) then
    Exit;
  FTimer.Enabled := False;
end;

procedure TMyComp.TimerEvent(Sender: TObject);
begin
  { Doe iets }
end;

end.
Pagina: 1