Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Funktionsliste (https://www.delphipraxis.net/77809-funktionsliste.html)

DelphiManiac 25. Sep 2006 09:51


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:
Get_SoftwareRelease(release);
label_softwarerelease.Caption:=release;
..
Get_SoftwareSubRelease(subrelease);
label_subrelease.Caption:=subrelease;
..
usw...
Wie kann ich denn Labels in eines anderen Threads in dem die VCL läuft aktualiseren und wie gebe ich das meinem Thread mit??

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

berens 25. Sep 2006 10:24

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:
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;
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!).

-deine Aufgabenliste kann man eventuell als Array of TProcedure machen und diese dann auch so direkt wieder aufrufen:
Delphi-Quellcode:
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;
^-- ungetestet, keine Ahnung ob das so direkt geht...

TAC 25. Sep 2006 10:37

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

Der_Unwissende 25. Sep 2006 11:09

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

DelphiManiac 25. Sep 2006 12:15

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

Der_Unwissende 25. Sep 2006 12:50

Re: Funktionsliste
 
Zitat:

Zitat von DelphiManiac
@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.

Erstmal zu den Callbacks (sorry, wird mal etwas unsauber, bin auf'm Sprung):
Delphi-Quellcode:
type
  TDeinCallBack = procedure(const neuerWert : TTyp) of Object;
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.
In deiner Form legst du dann eine Methode mit dieser Signatur an
Delphi-Quellcode:
type
  TForm1 = class(TForm)
   ...
   procedure onWhatEver(const neuerWert : TTyp);
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.

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.

DelphiManiac 26. Sep 2006 09:43

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:
type
  TDeinCallBack = procedure(const neuerWert : TTyp) of Object;
Hier lege ich einen Type TDeinCallBack an, der einen Funktionszeiger (Adresse einer Funktion/Prozedur) speichert.
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:
const neuerWert : TTyp
gemeint?

Naja werde jetzt nich gleich den Sand in den Kopf stecken (wie Lothar Matthäus :zwinker: )


DAAAANKE

DelphiManiac 26. Sep 2006 10:03

Re: Funktionsliste
 
Hallo,

die Prozedurezuweisung hat irgendwie nicht geklappt,

nachdem ich das
Delphi-Quellcode:
of Object
weggelassen habe konnte ich die Prozeduren zuweisen.

Kannst du mir erklären für was das
Delphi-Quellcode:
of Object
zuständig ist?

Gracias

TAC 26. Sep 2006 10:36

Re: Funktionsliste
 
Moin,

mit dem
Delphi-Quellcode:
of object
wird ein Methodenzeiger erzeugt, der über den
Delphi-Quellcode:
Type TDeinCallBack
verfügbar ist.
In der Threadklasse wird dann das Event
Delphi-Quellcode:
OnDeinCallBack : TDeincallback;
implementiert, sinnvollerweise public, damit der Instanz von TMyThread von außen für OnDeinCallBack etwas zugewiesen werden kann.
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:
MyTHread := Thread.Create...
kreiert , dann macht man hier die Zuweisung
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:
MeinThreadMeldetSich
auf den Thread selbst und nicht über die Instanz
Delphi-Quellcode:
MyThread
. Dies macht dann Sinn, wenn vielleicht mehrere Threads gleichzeitig laufen, und man nicht unbedingt weiß, welcher gerade
Delphi-Quellcode:
MeinThreadMeldetSich
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
Delphi-Quellcode:
Procedure Tform1.ButtonClickEvent(Sender:TObject)
z.B. mit
Delphi-Quellcode:
showmessage((Sender as TButton).name)
ausgeben.

Hoffe, daß hat ein wenig helfen können...

Mfg
TAC


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:51 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz