![]() |
Event für Fehlercode-Übergabe
Hallo an alle DPler,
habe ein Problem, mit welchem ich mich noch nie so beschäfftigt hab und würde mal gerne eine Art BrainStorming durchführen mit eurer Hilf. Die Aufgabe ist ein Fehler Protokoll zu erstellen. Ich habe mehrere Komponenten, die ich in Klassen kapsel. Möchte mich hier auf eine Klasse Tische begrenzen. Diese führt mehrere interne Prüfungen durch (z.B. ist die benötigte DLL vorhanden, ist der Tisch angeschlossen(gibt es einen ComPort, der mit dem Tisch kommuniziert), ...). Wenn ein Fehler auftritt möchte ich jetzt in meinem Hauptprogramm diesen detektieren. Eine Möglichkeit ist ein Event. Habe mich hier auch schon schlau gemacht und folgendes:
Delphi-Quellcode:
Dies ist nicht auf meinem eigenen Mist gewachsen sondern wurde so übernommen von folgendem Threat:
type
TNameDeinesEventTypes = procedure(Sender: TObject; AParameterXYZ: String) of Object; TDeineKlasse = class(TIrgendwas) [...] fDeinEvent: TNameDeinesEventTypes; [...] property OnDeinEvent: TNameDeinesEventTypes read fDeinEvent write fDeinEvent; [...] end; implementation [...] procedure TDeineKlasse.LoeseEventAus(MitZuGebenderParameter); begin if Assigned(fDeinEvent) then fDeinEvent(Self, MitZuGebenderParameter); end; ![]() Zu dieser Variante ergeben sich jetzt folgende Fragen: 1.) Wenn die Tisch-Klasse in einer extra Unit liegt und mein Hauptprogramm in einer weiteren, wo sollte ich dieses Event reinschreiben? Logisch wäre sicherlich in die Klasse, allerdings hier schließt auch gleich meine 2.) Frage von mir an, aber wie kommuniziert dies dann mit meinem Hauptprogramm? Hierbei meine ich einen sicheren Zugriff von Hauptprogramm auf den eventuell erstellten Fehlercode in der Klasse und einem eventuell sich änderenden Fehlerwert in der Klasse (es werden ja mehrere Proceduren hintereinander durchgeführt, die diesen Fehlercode ändern können. 2.) leider hab ich noch nirgendswo mal gefunden, wie die "Event-Procedure" wirklich dargestellt wird. Für mich als jemand, der sowas noch nicht wirklich benutz hat, wäre es logisch, dass im Implementationsteil irgendwo steht:
Delphi-Quellcode:
3.) Habt ihr vieleicht bessere Vorschläge mit Lösungsansätzen, wie ich vieleicht diese Fehlerbehandlung am besten durchführen kann. Leider fehlen mir hier noch das Verständnis für Möglichkeiten (ohne dass es zu einer Spagetti-Programmierung oder weiteren Fehlern führt) da ich bisher soetwas nie benutzt habe.
procedure TDeineKlasse.fDeinEvent(Sender: TObject; AParameterXYZ: String) of Object;
begin ... end; Vieleich hat jemand mal beispielhaft einen Code. Vielen Dank BAMatze |
Re: Event für Fehlercode-Übergabe
Mahlzeit,
der Code, der bei dem Event ausgeführt werden soll, liegt eben nicht in der Klasse ;), sondern da wo er passieren soll (dann klappts auch mit dem Nachbarn ... äh ... mit der Verbindung). Also du hast dein HauptForm:
Delphi-Quellcode:
cu
type
TMainForm = class( TForm ) private procedure OnCreate( Sender : TObject ); public procedure WennDatEventKommt(Sender: TObject; AParameterXYZ: String); end; implementation procedure TMainForm.WennDatEventKommt(Sender: TObject; AParameterXYZ: String); begin // Hier mach ich mal was ... end; procedure TMainForm.OnCreate( Sender : TObject ); begin with TDeineKlasse.Create do begin OnDeinEvent := WennDatEventKommt; end; end; Oliver |
Re: Event für Fehlercode-Übergabe
Wann werden die Prüfungen denn durchgeführt? Ggf. würde ja auch ein simpler Funktionsaufruf, der zurückgibt ob alles in Ordnung ist oder nicht ausreichend :gruebel: Natürlich nur, wenn sich das vor dem Ausführen der Methoden feststellen lässt.
Wenn man das erst in der laufenden Methode feststellen kann würde ich entweder wie du vorgeschlagen hast einen Callback machen oder einfach eine Exception werfen und vom Hauptprogramm fangen lassen. |
Re: Event für Fehlercode-Übergabe
Also es soll im Hauptprogramm immer "gelauscht" werden, ob Fehler an Geräten anliegen. Von daher machen Events an sich schon mal Sinn. Es kann ja sein, dass der Tisch beim verschieben irgendwo aneckt (dies wird mit Anschlagsschaltern detektiert) und darauf muss natürlich sofort reagiert werden. Das ist der Sinn dahinter. Weiterhin müssen in dem Fall auch andere Komponenten sofort deaktiviert werden und sobald das Problem behoben ist, soll auch per Fehlercode dies wieder alles aktiviert werden.
|
Re: Event für Fehlercode-Übergabe
Dann auf jeden Fall die Ereignisse. Da gibt's keine große Alternativen.
|
Re: Event für Fehlercode-Übergabe
Wenn tatsächlich ein Fehler vorliegt, dann nimm eine Exception. Wenn aber dein "Fehler" ein erwartetes Ereignis ist, mit dem man ganz normal weiterarbeiten kann, dann nimm Ereignisse.
Entweder alle deine Objekte haben eine strikte Parent-Child Struktur, sodass du die events zum einen an das Parent hochleiten kannst und dieses das Ereignis an alle weiteren Child Objekte verteilt. Oder du machst eine Art Container für Ereignisse. Bei dem kanns ich jedes Objekt anmelden (oder stammt halt davon ab) und hier wird die weiterleitung der Ereignisse organisiert. |
Re: Event für Fehlercode-Übergabe
Der zweite Vorschlag von Sirius findet sich übrigens als Subject-Observer-Pattern in der Suchmaschine deiner Wahl wieder.
|
Re: Event für Fehlercode-Übergabe
Also habe jetzt ein Event erstellt, welches seine Tätigkeit an sich erstmal tun sollte. Leider hat sich dabei aber ein riesiger Fehler eingeschlichen, den ich selber nicht mehr erkennen kann. Das Kompilieren erfolgt ohne Probleme, allerdings gibt es bei der Erstellung der Tischkomponente eine Exception, die das gesamte Programm abschießt. könntet ihr vieleicht mal schauen, woran dies liegen kann?
Die TischUnit
Delphi-Quellcode:
hier die Hauptfunktion
unit VT_Funktionen;
interface uses Windows, SysUtils, Hilfsfunktionen, ExtCtrls; const constMillimeter = 6400; //type TFehlerevent = procedure(iFehlercode: integer) of object; type TV_Tische = class //Fehlerevent: TFehlerevent; private Tischbmp: TBitmap; TischDLL: TDLL_Datei; DLL_Handle: THandle; bBewegung, bkalibriert,bAngeschlossen: boolean; iaktuelleTischposition, iZielTischposition, iComport: integer; Bewegungsueberwachung: TTimer; function DLLFunktionen_laden: boolean; function Bewegtsich(const Kanal: integer): boolean; function Bremsen: boolean; function Geschwindigkeit_festlegen(const iGeschwindigkeit: integer): boolean; function Beschleunigung_festlegen(const iBeschleunigung: integer): boolean; function VTische_verbinden(Comport: integer): boolean; function Kalibrierung(const Kanal: integer): boolean; function Verfuegbarkeit: boolean; // Diese Funktioen müssen überprüft werden, ob sie wirklich private sein sollen function BewegenABS(dneuPos: double): boolean; overload; function BewegenABS(const KaliPos: string): boolean; overload; function BewegenABS(dneuPos: double; iGeschwindigkeit: integer): boolean; overload; function BewegenABS(dneuPos: double; iGeschwindigkeit, iBeschleunigung: integer):boolean; overload; public constructor create; destructor Destroy; override; property Handle: THandle read DLL_Handle; //property Verfuebar: boolean read Verfuegbarkeit; // property Fehlerevent_ausloesen: TFehlerevent read Fehlerevent write Fehlerevent; end; // Typdeklaration für die aus der dynamisch eingebundenen MMC.DLL zu ladenen // Funktionen. type TMMC_COM_open = function(portnumber,bautrate: integer):integer; stdcall; type TMMC_close = function: integer; stdcall; type TMMC_sendCommand = function(pCmd: pChar): integer; stdcall; type TMST_moving = function: integer; stdcall; // Variablendeklaration der aus der dynamisch eingebundenen MMC.DLL zu ladenen // Funktionen var MMC_COM_open: TMMC_COM_open; MMC_close: TMMC_close; MMC_sendCommand: TMMC_sendCommand; MST_moving: TMST_moving; {////////////////////////////////////////////////////////////////////////////////////} {/ Funktionen der DLL /} {////////////////////////////////////////////////////////////////////////////////////} {function MMC_COM_open(portnumber,baudrate:integer):integer; stdcall external ExtLib; function MMC_COM_close:integer; stdcall external ExtLib; // function MMC_COM_setBuffer:integer; stdcall external ExtLib; // function MMC_sendString(pCmd:pChar):integer; stdcall external ExtLib; // function MMC_sendCommand(pCmd:pChar):integer; stdcall external ExtLib; // function MMC_getPos:integer; stdcall external ExtLib; // function MDC_getPosErr:integer; stdcall external ExtLib; // function MMC_getVal(query:integer):integer; stdcall external ExtLib; // function MMC_getReport(pCmd,psRead:PChar):integer; stdcall external ExtLib; // function MMC_getStringCR(psRead:PChar):integer; stdcall external ExtLib; // function MDC_moving:integer; stdcall external ExtLib; // function MST_moving:integer; stdcall external ExtLib; // function MMC_initNetwork(maxaxis:integer):integer; stdcall external ExtLib; // function MMC_select(newaxis:integer):integer; stdcall external ExtLib; // function MMC_setDevice(newaxis:integer):integer; stdcall external ExtLib; // function MMC_COM_clear:integer; stdcall external ExtLib; // function MMC_COM_EOF:integer; stdcall external ExtLib; // function MMC_getSTB(byteno:integer):integer; stdcall external ExtLib; // function MDC_waitStop:integer; stdcall external ExtLib; // function MST_waitStop:integer; stdcall external ExtLib; // function MMC_getDLLversion:integer; stdcall external ExtLib; function MMC_moveA(axis,position:integer):integer; stdcall external ExtLib; function MMC_moveR(axis,shift:integer):integer; stdcall external ExtLib; function MMC_getMacro(macno:integer;content:PChar):integer; stdcall external ExtLib; function MMC_globalBreak:integer; stdcall external ExtLib; } {////////////////////////////////////Ende Funktionen//////////////////////////////////} implementation constructor TV_Tische.create; begin inherited create; // <--- in jeder Zeile des Constructors tritt ein Fehler auf, sogar wenn alles bis zum end; auskommentiert wird tritt bei dem end; die Exception auf bBewegung := false; bkalibriert := false; bAngeschlossen := false; Bewegungsueberwachung := TTimer.Create(nil); DLLFunktionen_laden; //if assigned(Fehlerevent) then Fehlerevent(1); end; function TV_Tische.Verfuegbarkeit: boolean; begin end; destructor TV_Tische.Destroy; begin {TischDLL.Destroy; Bremsen; MMC_COM_close; inherited Destroy; } end; end.
Delphi-Quellcode:
Vielen Dankunit ThreadUnit; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, ComCtrls, VT_Funktionen, Hilfsfunktionen; type TAnschlussElement = record Komponentenhandle: THandle; sIdent: string; iComSchnittstelle: integer; bAngeschlossen, bDLL: boolean; end; type THUnterthread = class(TThread) private ComPort_VT: integer; aComport: array of integer; procedure Fehler_verifizieren(iFehlercode: integer); protected procedure Execute; override; public iThreadmsg: integer; AnschlussElement: array of TAnschlussElement; constructor create; destructor Destroy; override; end; var V_Tische: TV_Tische; implementation uses LoaderUnit; constructor THUnterthread.create; begin inherited create(false); iThreadmsg := 1; end; procedure THUnterthread.Execute; begin V_Tische.create; //V_Tische.Fehlerevent_ausloesen := Fehler_verifizieren; end; destructor THUnterthread.Destroy; begin try V_Tische.Free except end; inherited Destroy; end; procedure THUnterthread.Fehler_verifizieren(iFehlercode: integer); begin iThreadmsg := 16; end; BAMatze |
Re: Event für Fehlercode-Übergabe
*hüstel*
Zitat:
Delphi-Quellcode:
:zwinker:
V_Tische := TVTische.create;
|
Re: Event für Fehlercode-Übergabe
Du hast noch nie einen Constructor aufgerufen? :stupid:
|
Re: Event für Fehlercode-Übergabe
f...
Danke |
Re: Event für Fehlercode-Übergabe
Also hab den *hust Fehler beseitigt :wall: :wall: und es läuft auch ohne Probleme, allerdings die Threadmsg 16 wird noch nicht ausgegeben. Sieht jemand dafür vieleicht noch einen Grund?
|
Re: Event für Fehlercode-Übergabe
Einkommentiert haste die Sachen aber wieder? :stupid:
Ach ja und das Event im Konstruktor auszulösen ist eher ne doofe Idee, wenn du es nach dem Erzeugen des Objekts erst zuweist ;) |
Re: Event für Fehlercode-Übergabe
ok alles funzt
Danke euch |
Re: Event für Fehlercode-Übergabe
Hallo an alle muss nochmal diesen Threat aufnehmen, weil ich jetzt verwirrt anscheinend bin. Letzten Freitag hat das von mir implizierte Event anscheinend tadellos funktioniert und heute scheint es sich gegen mich verschworen zu haben. Ich stelle hier nochmal die beiden wichtigen Units zur Verfügung, vieleicht sieht jemand, einen Fehler. Hab leider nach fast 1,5h immer noch keinen Anhaltspunkt.
TischUnit:
Delphi-Quellcode:
ThreadUnit
unit VT_Funktionen;
interface uses Windows, SysUtils, Hilfsfunktionen, ExtCtrls, Dialogs; // Eventdeklaration type TFehlerevent = procedure(const iFehlercode: integer) of object; // TV_Tische-Klassendeklaration type TV_Tische = class Fehlerevent: TFehlerevent; private // Deklaration aller verwendeten Variablen die nur intern in dieser Unit // verwendet werden können //Tischbmp: TBitmap; TischDLL: TDLL_Datei; DLL_Handle: THandle; //bBewegung, bkalibriert,bAngeschlossen: boolean; //iaktuelleTischposition, iZielTischposition: integer; iComport, iKanal: integer; Bewegungsueberwachung: TTimer; // Deklaration aller für die Initialisierung verwendeten und nur in dieser Unit // verwendeten Funktionen function DLLHandle_zuweisen: boolean; function DLLFunktionen_laden: boolean; function ComPort_ermitteln: boolean; function Verfuegbarkeit: boolean; // Deklaration aller für die Bewegung verwendeten und nur in dieser Unit // verwendeten Funktionen function Geschwindigkeit_festlegen(const iGeschwindigkeit: integer): boolean; function Beschleunigung_festlegen(const iBeschleunigung: integer): boolean; function Bremsen: boolean; // Deklaration aller für die Überprüfung des Tischstatus und nur in dieser Unit // verwendeten Funktionen function Bewegtsich(const Kanal: integer): boolean; procedure BewegungsueberwachungTimer(Sender: TObject); procedure Fehlermeldung(const iFehler: integer); public // Deklaration aller für die Initialisierung verwendeten und auch in anderen Units // zur Verfügungstehenden Funktionen constructor create; function Initialising: boolean; destructor Destroy; override; //function init(const iKanal: integer): boolean; // Deklaration aller für die Bewegung verwendeten und auch in anderen Units // zur Verfügungstehenden Funktionen //function Kalibrierung(const Kanal: integer): boolean; function BewegenABS(dneuPos: double): boolean; overload; function BewegenABS(const KaliPos: string): boolean; overload; function BewegenABS(dneuPos: double; iGeschwindigkeit: integer): boolean; overload; function BewegenABS(dneuPos: double; iGeschwindigkeit, iBeschleunigung: integer):boolean; overload; // Deklaration aller verwendeten Variablen die auch in anderen Units // zur Verfügungstehenden Funktionen property Handle: THandle read DLL_Handle; property Verfuebar: boolean read Verfuegbarkeit; property Fehlerevent_ausloesen: TFehlerevent read Fehlerevent write Fehlerevent; property Kanal: integer read iKanal write iKanal; end; // Typdeklaration für die aus der dynamisch eingebundenen MMC.DLL zu ladenen // Funktionen. type TMMC_COM_open = function(portnumber,bautrate: integer):integer; stdcall; type TMMC_close = function: integer; stdcall; type TMMC_sendCommand = function(pCmd: pChar): integer; stdcall; type TMST_moving = function: integer; stdcall; type TMMC_setDevice = function(NewAxis: integer): integer; stdcall; // Variablendeklaration der aus der dynamisch eingebundenen MMC.DLL zu ladenen // Funktionen var MMC_COM_open: TMMC_COM_open; MMC_close: TMMC_close; MMC_sendCommand: TMMC_sendCommand; MST_moving: TMST_moving; MMC_setDevice: TMMC_setDevice; implementation {////////////////////////////////////////////////////////////////////////////////////} {/ Funktionen für Komunikationsaufbau bzw. -terminierung und /} {/ und Statusüberprüfung /} {////////////////////////////////////////////////////////////////////////////////////} constructor TV_Tische.create; begin inherited create; // Der Überwachungstimer wird initialisiert und aktiviert. Dieser überwacht rein // ob sich der Tisch bewegt oder steht. Wenn der Tisch sich bewegt soll später // die Beschleunigung und die Geschwindigkeit berechnet werden. Fehlermeldung(100); Bewegungsueberwachung := TTimer.Create(nil); Bewegungsueberwachung.OnTimer := BewegungsueberwachungTimer; Bewegungsueberwachung.Enabled := true; end; ... etliche Proceduren und Funktionen aus der Tisch-Klasse procedure TV_Tische.Fehlermeldung(const iFehler: Integer); begin // Diese Fehlermeldung funktioniert allerdings scheint er nicht durch die // if-Anweisung zu gehen, warum? if assigned(Fehlerevent) then Fehlerevent(iFehler); <--- hier vermute ich einen Fehler, weil ab hier die Fehlermeldung verschwindet end; end.
Delphi-Quellcode:
unit ThreadUnit;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, ComCtrls, VT_Funktionen, Hilfsfunktionen, FehlerUnit; // Eventdeklaration type TFehleruebergabe = procedure(const iFehlercode: integer) of object; type TAnschlussElement = record Komponentenhandle: THandle; sIdent: string; iComSchnittstelle: integer; bAngeschlossen, bDLL: boolean; end; type THUnterthread = class(TThread) Fehleruebergabe: TFehleruebergabe; private protected procedure Execute; override; public iThreadmsg: integer; AnschlussElement: array of TAnschlussElement; constructor create; destructor Destroy; override; procedure Fehler_verifizieren(const iFehlercode: integer); property Fehleruebergeben: TFehleruebergabe read Fehleruebergabe write Fehleruebergabe; end; var V_Tische: TV_Tische; implementation uses LoaderUnit; constructor THUnterthread.create; begin inherited create(false); iThreadmsg := 1; end; procedure THUnterthread.Execute; begin V_Tische := TV_Tische.create; V_Tische.Fehlerevent_ausloesen := Fehler_verifizieren; <-- Hier könnte alternativ ein Fehler vorliegen end; destructor THUnterthread.Destroy; begin try V_Tische.Free except end; inherited Destroy; end; procedure THUnterthread.Fehler_verifizieren(const iFehlercode: integer); begin // in diese Fehlermeldung wird nicht reingegangen!!! Fehleruebergabe(iFehlercode); end; end. |
Re: Event für Fehlercode-Übergabe
Wann erwartest du denn den Fehler.
Im Constrcutor ist das Event noch nicht zugewisen (also Fehlermeldung(100) wird vor der Eventzuweisung aufgerufen) Außerdem wird dann Thread gleich nach Execute beendet. |
Re: Event für Fehlercode-Übergabe
Liste der Anhänge anzeigen (Anzahl: 1)
Naja eigentlich ist das ja nur der Anfang für mehrere Initalisierungen von Geräten. Fehler sind eigentlich wärend der gesamten Initialisierung und auch später bei der Benutzung der Geräte möglich. Diese will ich dann so weit möglich verifizieren. Habe aber erstmal die erste Fehlermeldung beim Create raus genommen. Vieleicht hilft es einfach, wenn ich dir mal das ganze Projekt hier zur Verfügung stelle.
|
Re: Event für Fehlercode-Übergabe
Liste der Anhänge anzeigen (Anzahl: 1)
Also hab jetzt nochmal einiges geändert, waren doch noch einiges zu verbessern drin, aber anscheinend hat es jetzt wieder seine Funktionalität bekommen.Was mich nur noch irritiert, vieleicht kennt ihr das Phänomen, seit ich den Fehler beseitigt hab, fehlt das Rückgabe Fenster beim Compilieren. Hier zum Test nochmal die korrigierte Version:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:10 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz