Delphi 4 Objekte zur Laufzeit

Hallo!

Gerade versuche ich in Delphi ein Objekt zur Laufzeit in mein Programm einzubinden. Leider ist es bisher noch nicht gelungen. Ich versuchte ein Objekt vom Typ TTimer einzubinden. Soweit auch gelungen: mit Create habe ich es geschafft. Doch nun kam die Frage: „Wie schreibe ich jetzt eine Ereignisbehandlung?“. Das muß dann natürlich auch zur Laufzeit geschehen, in der Entwurfszeit gibt es diesen Timer ja noch nicht.
Wer kann mir helfen. Für ein kurzes Beispiel wäre ich sehr dankbar.

Mit bestem Dank im Voraus
Guido

Hallo!

Gerade versuche ich in Delphi ein Objekt zur Laufzeit in mein
Programm einzubinden. Leider ist es bisher noch nicht
gelungen. Ich versuchte ein Objekt vom Typ TTimer einzubinden.
Soweit auch gelungen: mit Create habe ich es geschafft.

…und die Zeile lautet tatsächlich „Timer1 := TTimer.Create“ und NICHT „Timer1.Create“! Als Delphi-Anfänger ist es mir selbst oft passiert, daß ich versucht habe, Klassen a la „Timer1.Create“ zu intantiieren. Das Heimtückische daran ist, daß dies a) nicht funktioniert und (viel schlimmer) b) vom Compiler nicht als Fehler angezeigt, sondern anstandslos übersetzt wird.

Doch nun kam die Frage: „Wie schreibe ich jetzt eine
Ereignisbehandlung?“. Das muß dann natürlich auch zur Laufzeit
geschehen, in der Entwurfszeit gibt es diesen Timer ja noch
nicht.

Folgendes Minibeispiel sollte selbsterklärend sein. Die Zeile, die Deine Frage mit der Ereignisbehandlung beantwortet, ist die letzte in der Prozedur „FormCreate“. Noch ein Hinweis: Dir fällt vielleicht auf, daß die Prozedur „ZaehleEinsHoch“ als Parameter ein „Sender: TObject“ hat, obwohl der innerhalb der Prozedur gar nicht verwendet wird. Auf diesen Parameter kann nicht verzichtet werden, weil der Typ der Methode „OnTimer“ intern (in der TTimer-Klassendefinition) so festgelegt ist.

unit Unit1;

interface

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

type
 TForm1 = class(TForm)
 Label1: TLabel;
 PROCEDURE ZaehleEinsHoch(Sender: TObject);
 procedure FormCreate(Sender: TObject);
 procedure FormDestroy(Sender: TObject);
 private
 { Private-Deklarationen }
 public
 { Public-Deklarationen }
 end;

var
 Form1 : TForm1;
 Timer1: TTimer;
 k : INTEGER;

implementation

{$R \*.DFM}

PROCEDURE TForm1.ZaehleEinsHoch(Sender: TObject);

VAR s: STRING;

begin
 Inc(k);
 Str(k,s);
 Label1.Font.Color := Random($FFFFFF);
 Label1.Caption := s
end;


procedure TForm1.FormCreate(Sender: TObject);

begin
 (\* Timer1 intantiieren \*)
 Timer1 := TTimer.Create(Self);

 (\* Eigenschaften von Timer1 festlegen \*)
 (\* (hier nur "Interval") \*)
 Timer1.Interval := 500;

 (\* Ereignisverknüpfung für Timer1 festlegen \*)
 (\* (hier nur "OnTimer") \*)
 Timer1.OnTimer := ZaehleEinsHoch;
end;


procedure TForm1.FormDestroy(Sender: TObject);

begin
 (\* Timer1 lebewohl sagen \*)
 Timer1.Destroy
end;


begin
 k := 0
end.

Mit freundlichem Gruß
Martin

Hallo Martin,

danke für die schnelle Hilfe.
Leider habe ich Dein Beispiel auch nicht zum Laufen bekommen. Ich habe ein neues Prejekt erzeugt. Auf die Form habe ich dann ein Objekt „Label1“ gebracht. Danach habe ich das Beispiel 1:1 in die Unit1 kopiert. Beim kompilieren bekomme ich keinen Fehler. Wenn ich den Programmcode richtig verstanden habe, müßte nach dem Start des Programms ein Zähler hochlaufen. Das geschieht aber nicht. Auf dem Formular bleibt die Schrift „Label1“ stehen. Muß ich villeicht noch eine Umgebungsvariable setzen?

Mit bestem Dank
Guido

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Hi Guido,

Leider habe ich Dein Beispiel auch nicht zum Laufen bekommen.
Ich habe ein neues Prejekt erzeugt. Auf die Form habe ich dann
ein Objekt „Label1“ gebracht. Danach habe ich das Beispiel 1:1
in die Unit1 kopiert. Beim kompilieren bekomme ich keinen
Fehler. Wenn ich den Programmcode richtig verstanden habe,
müßte nach dem Start des Programms ein Zähler hochlaufen.

Ja!

Das geschieht aber nicht. Auf dem Formular bleibt die Schrift
„Label1“ stehen. Muß ich villeicht noch eine Umgebungsvariable
setzen?

nein, nein, mit Umgebungsvariablen hat das gar nichts zu tun - der Grund liegt woanders. Wenn Du so vorgehst, wie Du es beschrieben hast, dann stehen zwar in der Unit „Unit1“ schön brav die Prozeduren „TForm1.Create“ und „TForm1.Destroy“, aber die werden gar nicht durchlaufen, weil die Prozedurzeiger „OnCreate“ und „OnDestroy“ des Formulars „Form1“ nicht belegt sind. Als ich das Beispiel zusammengehackt habe, habe ich diese beiden Prozeduren wie üblich mit je einem Doppelklick in die Felder namens „Create“ und „Destroy“ im Objektinspektor (Registertab „Ereignisse“, rechte Spalte) erzeugt. Deshalb sind bei mir dort dann automatisch die Einträge „FormCreate“ und „FormDestroy“ erzeugt worden, wohingegen sie bei Dir fehlen.

Du mußt also die Verknüpfungen zu FormCreate und FormDestroy einfach noch nachträglich im Objektinspektor eintragen. Also: Formular anklicken, im Objektinspektor auf Registertab „Ereignisse“ gehen, bei „Create“ rechts klicken (wird weiß), Box runterklappen und „FormCreate“ unter den dreien auswählen. Dieselbe Aktion wiederholen für „Destroy“ (diesen Zeiger auf „FormDestroy“ setzen). Jetzt kannst Du den Zähler bestaunen :wink:.

Beim Quelltext-Kopieren in Delphi muß man eigentlich immer (auch) mit solchen Problemen rechnen - das ist ganz normal und kein Grund zur Panik. Wenn Dir noch was unklar ist, dann frag mich ruhig.

Bye
Martin

PS: Wenn Du das Proggi zum Laufen gekriegt hast, und noch Lust zum experimentieren hast, dann versuch mal dies. Ergänze das Formular „Form1“ um die Prozedur (Achtung: auch in Formuladeklaration eintragen!)

PROCEDURE TForm1.ZaehlerReset(Sender: TObject);
begin
 k := 0;
end;

…und belege z. B. den Zeiger „OnClick“ von Form1 mit dieser Prozedur, indem Du so wie oben vorgehst. Jeder Mausklick auf das Formular (zur Laufzeit) läßt dann den Zähler zurückspringen.
Alternativ kannst Du auch einen Button ins Formular setzen und dessen OnClick-Zeiger auf „ZaehlerReset“ setzen… Dem Erfindungsreichtum sind hier keine Grenzen gesetzt, wie Du siehst :wink:.

Hallo Martin,

danke für Deine Geduld. Jetzt läuft das Beispiel auch bei mir.
Ich hatte versucht den Zeitgeber in einem Programm für die serielle Schnittstelle zu benutzen. Ich wollte damit eine Timeoutüberwachung machen. Jetzt hat sich allerdings herausgestellt, daß die Komponente für die serielle Schnittstelle wahrscheinlich fehlerhaft ist. Ich kann Daten vom Typ String ohne Probleme einlesen. Damit kann ich ohne weiteres ein Terminalprogramm schreiben.
Wenn ich allerdings die Prozedur zum lesen von Daten benutze, bekomme ich die Daten nicht. Die Prozedur selbst läuft ohne Fehlermeldung. Jetzt muß ich mir erst einmal eine neue Komponente für die serielle Schnittstelle suchen. Vielleicht habe ich mich ja nur wieder dumm angestellt. Mit den Zeigern habe ich so meine Schwierigkeiten.

Ich möchte Dir nochmals Danken
Guido

Hallo,

für RS232 kann ich eine Komponente
empfehlen, die „ComPort“ heißt.
Bin selber erst seit kurzem Delphi-Fan,
bin damit prima zureckgekommen!

Gruß Uwi

Hi Guido,

Ich hatte versucht den Zeitgeber in einem Programm für die
serielle Schnittstelle zu benutzen. Ich wollte damit eine
Timeoutüberwachung machen.

also ich denke, der Delphi-Timer ist eher für unkritische Aufgaben wie Blinklichter oder Repeat-Funktionen bei Spinbuttons oder dergleichen gedacht. Ob er qualitätsmäßig für Deinen Zweck ausreicht, hängt wohl von der Art der Anwendung ab. Wenn Du z. B. nur eine Datenlogger-Anwendung schreiben willst, das ein Digitalvoltmeter mit einem Zeittakt von 10 s (meinetwegen auch 1 s) abfragt, und das Proggi ne Fehlermeldung bringen soll, wenn das Gerät aus irgendeinem Grund nix (mehr) sendet, dann könnte das möglicherweise noch mit dem Timer hinzukriegen sein (rein gefühlsmäßige Einschätzung :wink:). Allgemein kann man sagen, daß es sicher umso kritischer wird, je kleiner die Zeiten sind, die Du „beherrschen“ willst.

Jetzt hat sich allerdings
herausgestellt, daß die Komponente für die serielle
Schnittstelle wahrscheinlich fehlerhaft ist. Ich kann Daten
vom Typ String ohne Probleme einlesen. Damit kann ich ohne
weiteres ein Terminalprogramm schreiben.
Wenn ich allerdings die Prozedur zum lesen von Daten benutze,
bekomme ich die Daten nicht. Die Prozedur selbst läuft ohne
Fehlermeldung. Jetzt muß ich mir erst einmal eine neue
Komponente für die serielle Schnittstelle suchen.

Ohne genaue Kenntnis der Sachlage kann ich dazu nichts konkretes sagen. Nur soviel: Es sind mehrere freie Serielle-Schnittstellen-Komponenten für Delphi im Internet verfügbar (bekannteste Adresse: Die „Delphi Super Page“). Ich denke, man tut gut daran, bei einer Auswahl unter mehreren gleichartigen Komponenten soweit wie irgend möglich die Spreu vom Weizen zu trennen zu versuchen. Ein Blick auf den Quelltext ist meistens recht aufschlußreich. Die „TComPort“-Komponente, die mein Vorredner bereits lobte, kenne ich übrigens auch. Ich habe sie mal zur Kommunikation mit einem Digitalvoltmeter verwendet, und das funzte so problemlos, wie man’s sich nur wünschen kann.

Mit den Zeigern habe ich so meine Schwierigkeiten.

Vielleicht beruht das ja auf Gegenseitigkeit? :wink: Also im Ernst: Da müßtest Du schon konkreter werden. Sollten Deine Schwierigkeiten aber eher allgemeiner Natur sein, kann ich Dir auch nur empfehlen, das entsprechende Kapitel in einem schlauen Delphi-Buch durchzuackern. Für sehr schlau halte ich übrigens „Delphi [x]“ (x = 2, 3, 4, 5) von E. Warken aus dem Addison-Wesley-Verlag. Da werden alle Grundlagen meiner Meinung nach wirklich gut erklärt.

Mit freundlichem Gruß
Martin