![]() |
Funktionsliste
Hallo,
ich bin gerade dabei ein Anwendungsprogramm für eine Hardware zu entwickeln. Kommuniziert wird wahlweise mit USB oder COM. Zurzeit habe ich meine Kommunikation noch im Hauptthread. Ich habe nun folgendes vor und hoff ihr könnt mir ein paar Tipps geben: Nach dem Verbinden mit dem Gerät werden ersteinmal ein paar grundlegende Daten vom Gerät gelesen. --> Danach sollen je nach Maske andere Werte zyklisch gelesen werden. --> Dazwischen muss es immer wieder möglich sein Werte zu ändern und einen Schreibbefehl zwischen den anderen Lese- Befehlen abzusetzten. Ich würde die gesamte Kommunikation gerne in einen extra Thread programmieren. Zurzeit habe ich noch folgendes Konstrukt:
Delphi-Quellcode:
Wie kann ich denn Labels in eines anderen Threads in dem die VCL läuft aktualiseren und wie gebe ich das meinem Thread mit??
Get_SoftwareRelease(release);
label_softwarerelease.Caption:=release; .. Get_SoftwareSubRelease(subrelease); label_subrelease.Caption:=subrelease; .. usw... Desweiteren würde ich gerne eine Jobliste anlegen..., die alle Funktionen enthält, die gerade benötigt werden und nacheinander abgearbeitet werden. Beispiel Jobliste[0]:=Get_SoftwareDatum; Jobliste[1]:=Get_SoftwareVersion; usw.. Hoffe ihr könnt mir helfen.. Danke schonmal im Vorraus |
Re: Funktionsliste
Ich bin in dem Bereich natürlich nicht der Fachmann, aber ein paar Ansatzpunkte, die Dir vielleicht helfen können:
-dein abgeleiteter Thread kann ja auch die Labels als Objekte haben, die "Verweise" auf die Labels des Hauptformulars sind. Mit denen kannst du dann intern arbeiten.
Delphi-Quellcode:
Beachte dass Änderungen an visuellen Komponenten durch Threads generell nur durch den Aufrufen von einer Prozedur/Funktion mit dem Befehl "Synchronize" durchgeführt werden durfen. (Sonst Absturz!).
procedure TForm1.Button1Click(Sender: TObject);
var t: TMyThread; begin t := TMyThread.Create(True); t.Label1 := Form1.Label1; t.Label2 := Form1.Label2; // etc. end; procedure TMyThread.Sync; begin Label1.Caption := 'Bla' + IrgendEineStringVaribaleAusDiesemThread; // etc. end; procedure TMyThread.Execute; begin // IrgendWas IrgendEineStringVaribaleAusDiesemThread := 'Foo'; Synchronize(Sync); // IrgendWas end; -deine Aufgabenliste kann man eventuell als Array of TProcedure machen und diese dann auch so direkt wieder aufrufen:
Delphi-Quellcode:
^-- ungetestet, keine Ahnung ob das so direkt geht...
var // Global
arrProc: array of TProcedure; procedure Jobliste_Abarbeiten; begin for i := low(arrProc) to high(arrProc) do begin if assigned(arrProc[i]) then begin arrProc[i]; end; end; |
Re: Funktionsliste
Ich bin mir zwar nicht ganz sicher, aber ich glaube mich erinnern zu können, daß man nicht unbedingt aus einem Thread heraus zeichnen controls anteuern sollte. Würde daher also dem Thread ein Event hinterlegen, welches dann vom Form aus gesetzt wird. Dies sollte dann eigentlich keine Fehler beim Aktualiseren der visuellen Komponenten hervorrufen.
type Tmythreadevent = procedure (Sender:TObject;wert1,wert2,wert3,wert4 {...} : String) of object; tmythread .... onMyEvent : Tmythreadevent; tform ... procedure onThreadEvent (Sender:TObject;wert1,wert2,wert3,wert4 {...} : String) ... tmytherad.onmyevent := onThreadEvent ; procedure onThreadEvent (Sender:TObject;wert1,wert2,wert3,wert4 {...} : String) begin label1.caption := wert1; .... end; MFG TAC |
Re: Funktionsliste
Hi,
dein Ansatz die Kommunikation komplett von der Form zu trennen ist doch schon mal gut! Den solltest du aber auch konsquent einhalten. So ist es zwar mögllich dem Thread hier noch Referenzen auf Controls zu geben, aber die Frage ist viel mehr, ist das nötig? Du solltest vielmehr mit einer Art Call-Back arbeiten. Dein Thread übernimmt dabei (von aussen angestossen) die Kommunikation, wurde ein Wert abgeholt, dann benachrichtigt der einfach jeden der sich dafür interessiert. Im einfachsten Fall nimmst du einfach einen Funktionszeiger und rufst eine Funktion in deinem Formular auf, dass dann diesen Wert als Caption eines Labels verwendet, du kannst aber auch gleich ein Observer-Pattern implemtieren (z.B. eine Liste von Funktionszeigern oder halt ein Interface/eine Basisklasse die eine bestimmte Methode hat, die dann aufgerufen wird). Jedenfalls kannst du durch eine solche Trennung dann leicht das Design des Formulars ändern. Da die Kommunikation nichts mit dem Aussehen zu tun hat, hast du so nichts anzupassen. An sich solltest du das immer versuchen durch zu halten. Gruß Der Unwissende |
Re: Funktionsliste
@Der_Unwissende:
Hallo Danke erstmal für eure Antworten!!! Ich bin schonmal froh, dass mein Ansatz "Design von Logik zu trennen" schonmal nicht ganz so falsch ist :-D Allein mit der Umsetzung hapert es noch. @Der_Unwissende: Hast du evtl ein Beispielcode für die Callback Methode und das mit dem "Observer-Pattern" . Ich google mal, wäre aber trotzdem super wenn du mir da noch einen Schupps geben könntest. Vielen Dank schonmallllll |
Re: Funktionsliste
Zitat:
Delphi-Quellcode:
So legst du einen Methodenszeiger an. Dieser speicher die Adresse einer Funktion/Prozedur einer Klasse. Du legst jetzt eine Variable von diesem Typ in deinem Thread an. Die Parameter (hier neuerWert) geben dabei die Nachricht weiter (was genau ist passiert). Hier könntest du z.B. einen Messwert übergeben, der angezeigt oder gespeichert werden soll.
type
TDeinCallBack = procedure(const neuerWert : TTyp) of Object; In deiner Form legst du dann eine Methode mit dieser Signatur an
Delphi-Quellcode:
Diese Prozedur kannst du nun der Variable des Threads vom Typ TDeinCallback zuweisen (:= Form1.onWhatEver;) Also ohne Klammern und Argument. Wie gesagt, du speichert damit eine Adresse, assigned gibt dir also zurück, ob dieser Zeiger gültig ist oder nicht. Ist er gültig, kann dein Thread diese Methode einfach aufrufen. Dazu einfach diese Variable wie eine echte Methode verwenden. Damit muss dein Thread also gar nicht wissen wo die Funktion herkommt. Er hat einfach eine Adresse und ruft die entsprechende Methode auf. Die kannst dann auch aus Form2, Fomr3 oder DoFoo28737 kommen, hauptsache es ist eine Methode, die genau diese Signatur hat.
type
TForm1 = class(TForm) ... procedure onWhatEver(const neuerWert : TTyp); Das Observerpattern ist hingegen nur ein Muster. Hier wird vorgegeben, wie man mehr als einen Beobachter über ein Ereignis informieren kann, die Implementierung hingegen bleibt einem selbst überlassen. Das was ich noch ansprach (über Objekte) werde ich hier auch nochmal posten, aber jetzt muss ich erstmal weiter. |
Re: Funktionsliste
@der_Unwissende:
Hi, danke dass du dir nochmal Zeit genommen hast für mein Problem, obwohl du gerade aufm Sprung warst. habe aber noch ein paar Questions an dich: -->
Delphi-Quellcode:
Hier lege ich einen Type TDeinCallBack an, der einen Funktionszeiger (Adresse einer Funktion/Prozedur) speichert.
type
TDeinCallBack = procedure(const neuerWert : TTyp) of Object; Habe ich das richtig verstanden? Der Vorteil hier ist es ,dass ich eine Funktion übergeben kann an meinen Thread??? Wast ist denn genau mit
Delphi-Quellcode:
gemeint?
const neuerWert : TTyp
Naja werde jetzt nich gleich den Sand in den Kopf stecken (wie Lothar Matthäus :zwinker: ) DAAAANKE |
Re: Funktionsliste
Hallo,
die Prozedurezuweisung hat irgendwie nicht geklappt, nachdem ich das
Delphi-Quellcode:
weggelassen habe konnte ich die Prozeduren zuweisen.
of Object
Kannst du mir erklären für was das
Delphi-Quellcode:
zuständig ist?
of Object
Gracias |
Re: Funktionsliste
Moin,
mit dem
Delphi-Quellcode:
wird ein Methodenzeiger erzeugt, der über den
of object
Delphi-Quellcode:
verfügbar ist.
Type TDeinCallBack
In der Threadklasse wird dann das Event
Delphi-Quellcode:
implementiert, sinnvollerweise public, damit der Instanz von TMyThread von außen für OnDeinCallBack etwas zugewiesen werden kann.
OnDeinCallBack : TDeincallback;
In einer anderen Klasse (z.B. Form1) deklariert man dann z.B. eine entsprechende
Delphi-Quellcode:
.
procedure MeinThreadMeldetSich(const neuerWert : TTyp)
Wenn man nun in OnCreate des Form1 den
Delphi-Quellcode:
kreiert , dann macht man hier die Zuweisung
MyTHread := Thread.Create...
Delphi-Quellcode:
.
MyThread.OnDeinCallBack := MeinThreadMeldetSich;
Wenn man zudem, wie ich es zuvor vorgeschlagen hatte, den Sender in den Methodenzeiger implementiert, dann hat Form1 auch direkten Zugriff in
Delphi-Quellcode:
auf den Thread selbst und nicht über die Instanz
MeinThreadMeldetSich
Delphi-Quellcode:
. Dies macht dann Sinn, wenn vielleicht mehrere Threads gleichzeitig laufen, und man nicht unbedingt weiß, welcher gerade
MyThread
Delphi-Quellcode:
aufruft, dann lässt sich über Sender auf die jeweilige Instanz bezugnehmen. Wie z.B. wenn alle Button es Form1 dasselbe ClickEvent OnClick aufrufen, lässt sich in der
MeinThreadMeldetSich
Delphi-Quellcode:
z.B. mit
Procedure Tform1.ButtonClickEvent(Sender:TObject)
Delphi-Quellcode:
ausgeben.
showmessage((Sender as TButton).name)
Hoffe, daß hat ein wenig helfen können... Mfg TAC |
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:29 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