![]() |
Endlosschleife + WarteFunktion ohne Programm zu blockieren
Ok, ich hoffe der Threadtitel ist einigermassen aussagekräftig. Mein Problem ist folgendes:
Ich gehe in einem Programm eine XML Datei nach der Reihe durch und je nach nodeName führe ich eine gewissen Prozedur aus. Durchgehen tue ich die XML in einer Endlosschleife, die unterbrochen wird, wenn ein unbekannter, bzw ein exit-Befehl in der XML auftaucht. So, taucht zB der nodeName "sentence" auf, dann wird die Prozedur ProcessSentence aufgerufen. Hier wird der Text von "sentence" in ein Array gespeichert und danach das Event OnChange meiner eigenen Klasse ausgelöst. Diesem Event habe ich in meiner MainForm dann zugewiesen, dass er die MainForm neu malt, wobei das Array aus meiner Klasse geschrieben werden soll. So, direkt nach dem Aufruf des Events, rufe icih die Funktion Delay auf, die verhindern soll, dass direkt das nächste Array Element aufgerufen wird.
Delphi-Quellcode:
So, in meiner Endlosschleife habe ich auch Application.ProcessMessages stehn, jedoch wird das Events und somit das OnPaint Ereignis nicht ausgelöst, und der Text nicht ausgegeben. Was ist der Fehler? Wie mache ich sonst eine Funktion die das vorranschreiten der Endlosschleife verhindert, bzw wie verhinder ich dasas die Endlosschleife das Programm blockiert (weiss nicht was von beidem oder ob beides davon zutrifft)!
procedure TDialogClass.Delay(msecs: LongInt);
var Start, Stop: LongInt; begin Start := GetTickCount; repeat Stop := GetTickCount; Application.ProcessMessages; until Stop - Start >= msecs; end; Hoffe ihr versteht was ich meine und könnt mir helfen! |
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Lager das Ganze doch in einen Extra Thread aus.
|
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Joa, was Threads sind weiss ich nicht, aber damit lassen sich solche Probleme lösen? Dann würde ich mich darüber genauer informieren. Wenn jemand ein gutes Tutorial zur Hand hat, gerne her damit ^^
Edit: Fast das Danke vergessen ^^ also, Dankesehr ^^ |
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Schau mal in die Demos, da ist auch eins zu Threads dabei.
[edit] Eine Demo meinte ich damit, kein Tutorial :oops: [/edit] |
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Delphi Demos oder was? Wo find ich die? :oops:
|
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Bei mir stehen die unter {Delphi}\Demos, die zu Threads also unter {Delphi}\Demos\Threads
|
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Hab ich nicht den Ordner, habe die Delphi7SE !?
|
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Meinst Du PE? Dann kann es sein, dass die nicht dabei sind.
|
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Ne, die SecondEdition.
|
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Sry, sagt mir jetzt nichts. Ist das eine Personal?
|
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
WEiss ich nicht genau, aber ist ja egal ich habe hier im Forum zwei Tutorials gefunden. Aber das ist ja meeeeega umfangreich!? o.O
Das wird ja ne heidenArbeit isch da durchzuforsten! |
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Nee, wieso.
1. Ansatz ist einfach eine Klasse von TThread ableiten und dann die Execute-Methode überschreiben. Und darin legst du den Code des Threads. Fertig. Musst natürlich beachten, dass du jetzt nicht einfach so kreuz und quer auf Variablen zugreifen kannst. |
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Ich hab diesen Wälzer gefunden ^^
![]() Habe mich shcon bisl durchgeforstet aber ist für imch nicht so einfach zu verstehen. Habe aber nun schon ein grobes Verständnis was passiert und was nicht passieren sollte ^^ Wenn ich jetzt noch ein simples Tut hätte, dass sich nur damit beschäftigt wie man das benutzt, dann würd das sicher was werden ^^ Edit: Achso, dann lager ich am besten meine Endlosschleife in einen Thread aus und die verarbeitung der nodeNames oder? Weil ich da dann ja noch die Wartezeit mit dem Thread erledigen könnte!? |
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Benutze doch einfach CreateThread oder BeginThread :P Dann kannst du in deinem Thread die Arbeiten durchführen und dein Programm friert trotzdem nichtein.
|
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Zitat:
Danke trotzdem ;-) |
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Liste der Anhänge anzeigen (Anzahl: 1)
Ok, ich raff das mit den Threads einfach noch nicht. Ich würde mich sehr freuen, wenn ihr euch mal meine Unit ansehen würdet und mir ein paar Anstöße geben könntet! Möchte keinen vollständigen Code, denn ich möchte verstehen was ich tue ;-)
So, ich weiss einfach nicht wie ich da die Threads einbaun soll. Soll ich beim DialogStart einen Thread erstellen, der dann ProfceedDialog aufruft? Wie mache ich das? Hierbei sagt er mir immer
Delphi-Quellcode:
"Variable Required udn zeigt auf das @ProceedDialog.
BeginThread(nil, 0, TFNThreadStartRoutine(@ProceedDialog), nil, 0, ThreadID);
Ich habe keinen Plan wie ich das nun realisieren soll, und die Parameter der BeginThread Funktion verstehe ich auch nicht so recht, bin aus den Tut Beschreibungen net recht schlau geworden! Edit: Achso, hilfreich wäre vielleicht zu wissen, dass das ganze als DialogSystem in einem Adventure genutzt werden soll! |
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Hallo,
Um auf das eigentliche Problem zurückzukommen: Wenn du ein OnPaint provozieren möchtest, so rufe auf:
Delphi-Quellcode:
Damit wird das Betriebssystem bei der nächsten Gelegenheit ein repaint veranlassen ...
<Komponente>.Invalidate
|
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
ProceedDialog muss eine Funktion sein mit folgender Deklaration:
Delphi-Quellcode:
Beachte, dass dies keine Methode ist, also nicht innerhalb einer Klasse sein darf.
function ProceedDialog(param:pointer):integer;
Ausserdem darfst du in einem Thread nicht auf globale Variablen zugreifen, bzw. auf Variablen, die auch der Main-Thread gleichzeitig benutzen könnte. Wenn dies zwingend notwendig wird, muss man eben synchronisieren. Du benutzt jetzt BeginThread. Warum nimmst du nicht eine Ableitung der Klasse TThread? Das ist für den Anfang viel einfacher. Vor allem sind die Änderungen, die du machn müsstest überschaubarer, wenn du die Klasse TDialogclass von TThread ableitest. |
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Ok, danke euch beiden!
Sirius, kannst du das etwas genauer erklären? Also ich leite die DialogUnit von TThread ab...sobald sie erzeugt wird ist das dann ein eigener Thread? Dann muss ich aber trotzdem noch mit den Variablen aufpassen oder? Also habe was von Critical Sections gelesen, das müsste sich dafür doch eignen oder? D.h. die einzige Änderung die ich machen müsste, wäre die Klasse von TThread abzuleiten und dann kann ich quasi alles so lassen, abgesehn davon dass ich mit den globalen Variablen aufpassen muss? |
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Liste der Anhänge anzeigen (Anzahl: 1)
Fast. Ich sehe halt den Rest des Programms nicht (besonders, wann du Methoden/Eigenschaften von der Klasse verwendest). Und kann nicht sagen, ob es alles ist.
Und zudem musst du dann die Execute-Methode anlegen/überschreiben. Die wird nämlich ausgeführt. Alle Parameter die du brauchst übergibst du im Constructor. Wenn du nachher noch Werte zwischen den Threads austauschen willst, dann würde ich dir erstmal zu "synchronize" raten (ist für den Anfang am einfachsten und dürfte bei dir auch ausreichen; da brauchst du dich mit CriticalSections noch nicht zu beschäftigen). Kann ich dir besser an einem Beispiel erklären, wenn du eins hast. Edit: Anhang angefügt Ich habe mal die Änderungen, die ich jetzt gesehen habe gemacht. Ob das jetzt alles richtig ist, weis ich nicht, da ich den Rest des Programmes nicht kenne. GEdacht ist es jetzt so, dass du das Objekt instanzierst und damit läuft der Thread gleich los (außer die Exception wird geworfen)und ruft irgendwann mal das TOnChange-Ereignis auf. Und genau darin bzw. nur darin darfst du dir den vollen Zugriff auf dein Objekt erlauben. |
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Also genutzt wird die Unit von aussen insofern, dass sie gestartet wird und sobald das Ereignis OnChange auftritt, werden von aussen die Sentences und Options angezeigt, die in den Arrays sind.
Delphi-Quellcode:
Wie mach ich das? Verstehe noch net ganz was du damit meinst! ^^
Und zudem musst du dann die Execute-Methode anlegen/überschreiben. Die wird nämlich ausgeführt.
|
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
siehe edit :mrgreen:
Edit: Ach und zum steuern des Threads von aussen gibt es die Methoden: -suspend (anhalten) -resume (fortsetzen) -terminate (abbrechen, dadurch wird eben terminated gesetzt) |
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Danke sehe ich mir die Tage an, muss nun wech ;-)
|
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Ok, das ist soweit ja relativ einfach, also Execute startet den Thread einfach und am Ende von Execute wird er wieder beendet? Dh ich muss für jeden Dialog den ich aufrufe das ganze neu Createn oder?
Die Sache ist jetzt noch, ich kann ja so nur im OnChange Ereignis darauf zugreifen, ich muss aber jedes mal wenn die Form, die die Unit einbindet gepainted wird, darauf zugreifen können, also nur die Variablen abrufen, nicht ändern! Geht das einfach oder muss ihc in der Form dann neue Variablen machen, die im OnChange geändert werden? Fänd ich etwas unpraktisch! Soweit aber schonmal ein FETTES DANKE, dafür dass du dir die Mühe gemacht hast dir das anzusehn und es zu ändern :) Super nett ;-) |
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Würde mir meinen letzten Post wohl nochmal wer beantwortet bitte? :angel: :dp: :-D Frohe Weihnachten ;-)
|
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Ohne Test, so aus dem Kopf. Die Werte aggf. ans Formular senden!!!
Code:
MFG
unit MyThread;
interface uses Windows,Classes,SysUtils,ComCtrls) TMyThread = class(TThread) private AHandle : THandle; protected procedure Execute;override; public published protected public constructor Create(Handle:THandle);virtual; destructor Destroy;override; published end; implementation {Type-TDriveThread-Anfang******************************************************} {Protected-TDriveThread-Anfang*************************************************} procedure TMyThread.Execute; var I : intger; begin inherited; I := 0; SendMessage(AHandle,WM_USER+10,0,0); // Für Senden für Meldungen while GetAsyncKeystate(VK_ESCAPE) <> 0 do//abbruch wenn ESC-Taste begin SendMessage(AHandle,WM_USER+11,0,I); // inc(I); end; SendMessage(AHandle,WM_USER+12,0,0); end; {Protected-TDriveThread-Ende***************************************************} {Public-TDriveThread-Anfang****************************************************} constructor TMyThread.Create(Handle:THandle); begin inherited Create(true); AHandle := Handle; Priority := tpLowest;//Die Eigenschaft Priority gibt die Priorität des Thread an. // Je nach Bedarf kann eine höhere oder niedrigere Priorität zugeordnet werden. end; //------------------------------------------------------------------------------ destructor TMyThread.Destroy; begin inherited; end; {Public-TDriveThread-Ende******************************************************} {Type-TDriveThread-Ende********************************************************} uses MyThread; {in Haupform} private FMyThread : TMyThread; procedure WM_USER10(var Msg: TMessage); message WM_USER+10; procedure WM_USER11(var Msg: TMessage); message WM_USER+11; procedure WM_USER12(var Msg: TMessage); message WM_USER+12; procedure TMain.FormDestroy(Sender: TObject); begin FreeAndNil(FProgressbarThread); end; procedure TMain.Button1Click(Sender: TObject); begin FMyThread := TMyThread.Create(Handle); FMyThread.Resume; end; procedure TMain.WM_USER10(var Msg: TMessage); begin Label1.Caption := 'Start'; end; procedure TMain.WM_USER11(var Msg: TMessage); begin Label2.Caption := intToStr(Msg.LParam); end; procedure TMain.WM_USER11(var Msg: TMessage); begin Label3.Caption := 'Fertig'; end; |
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Finds toll dass du duir soviel Mühe gemacht hast, danke aber mit fertigem Code kann ich recht wenig anfangen. Ich hätte lieber einen kleinen Denkanstoß gehabt. Was muss ich machen damit ich dauerhaft bestimmte Variablen von aussen lesen kann?
Wie wärs mit einer onRead-Procedure, die während der Ausgabe den Thread pausiert!? |
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Zitat:
Wenn der Thread läuft soll irgend was nicht passieren? Du wenn der Thread zuende ist soll es weiter gehen? Wo ist das Problem! SendMessage(AHandle,WM_USER+10,0,0); Meldung das der Thread gestartet wurde, er sagt dieses dem Hauptformular. SendMessage(AHandle,WM_USER+12,0,0), macht das gleiche wenn Thread fertig. procedure WM_USER10(var Msg: TMessage); begin FtuNix := true; end; procedure WM_USER12(var Msg: TMessage); begin FtuNix := false; end; SendMessage(AHandle,WM_USER+11,0,0), sagt dem Hauptformular das er arbeitet. Wenn es das nicht ist was du gefragt hast: Dann mal erklären was du mit onRead meinst. Mfg |
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Nene, also ich habein meiner DialogUnit zwei ein paar Variablen und Arrays, auf die das Formular jederzeit zugreifen können soll, damit sie dort gezeichnet werden. Ich habe ein OnChange-Event, in diesem Event kann die Form schon auf die Variablen zugreifen, ich möchte aber dass die Form das immer kann.
Dazu könnte ich einfach im OnChange Event die Variablen an das Formular übergeben und sie da speichern, bis ein neues OnChange Event auftritt. Das ist mir aber eigentlich zu umständlich und "unsauber" (warum Variablen doppelt speichern...). Also könnte ich nicht einfach die Variablen in meiner Dialog Unit als Property erstellen und dann eine ReadFunktion für sie schreiben in der der Thread pausiert wird, dann die Variable zurückgegeben und dann der Thread wieder gestartet wird oder so? Oder gibts da ne andere, bessere Lösung? Danke schonmal für die Hilfe! |
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
:gruebel: ich dachte ich hätte schon darauf geantwortet.
Mir fallen drei Möglichkeiten ein: 1. Die Werte zwischenspeichern. Du nennst es zwar unsauber, ist aber genau das um Threads sauber zu trennen und nich kreuz und quer auf Variablen zuzugreifen 2. Wenn sich die Werte sowieso selten ändern, könnte man hier mal über "Critical Sections" (TCriticalSection) nachdenken. Das sind quasi verschiedene Codeabschnitte die irgendwo in beiden Threads liegen (können) und wo du sicherstellen kannst, dass sich nur ein Thread zu einem Zeitpunkt in einem dieser Abschnitte befindet (und eben alle anderen dadurch "blockiert" sind). Ein zweiter Thread müsste, wenn er auch in so einen Abschnitt wöllte, erstmal warten. Dadurch erreichst du eine gewisse Synchronisation. Solche Codeabschnitte sind dann eben der gemeinsame Datenzugriff. 3. Message an den Thread schicken. Dürfte für dich irrelevant sein, denn dann müsste man erstmal ein Windohandle erzeugen (da ist 2. einfacher) 4. Thread mittels suspend anhalten, Variablen lesen und dann resume aufrufen. Finde ich unschön, auch wenns am einfachsten aussieht |
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Wenn du sagst du findest vier unschön, was findest du am schönsten? 1? Ist das nicht unelegant, doppelte Variablen zu haben?
|
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Ein Thread ständig anzuhalten ist eben nicht im Sinne des Erfinders. Aber je nachdem, wie du es im Programm benötigst, kannst du es ja einsetzen.
Aber versuchs mal mit TCriticalSection. Du erstellst ein Objekt davon im Main-Thread und übergibst es auch an den Thread (am besten über den Constructor) und immer bevor du in die kritische Region kommst (wo du auf eben diese Variablen zugreifst) rufst du IMHO CriticalSection.Enter auf und danach wieder leave. Wichtig ist, dass es dasselbe Objekt ist. |
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Ok, danke darüber informier ich mich dann genauer ;-)
|
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
Liste der Anhänge anzeigen (Anzahl: 1)
Ok, ich habe ein Problem! Ich kriege immer nen Abstract Error! Ich habs nun erstmal zum testen so gemacht, dass ich die Variablen in meiner FormUnit nochmal speichere. Ich hänge alles mal dran.
Ich weiss nicht worans liegt, irgendwie habe ich dass Gefühl dass Execute auch nicht ausgeführt wird, aber vll täusche ich mich auch. Klickt einfach im Programm oben auf Dialog und dann auf Testen. Normalerweise sollte dann rechts in der Paintbox der Dialog abgespielt werden. Zumindest die Funktionen die shcon funktionieren. Aber ich krieg immer den Error :-\ |
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
execute wird nicht ausgeführt, da du die Methode überschreiben musst.
Testen kann ich den Code nicht, da mir min. eine Unit fehlt, aber ich hab noch etwas gefunden:
Delphi-Quellcode:
Du kopierst ja hier das Array. Und in einer Schleife sollte man die von mir markierte Zeile solange es geht vermeiden.
for i := 0 to length(Dialogs.SentenceArray) - 1 do
begin SetLength(LocalSentenceArray, length(LocalSentenceArray) + 1); //<---- LocalSentenceArray[i] := Dialogs.SentenceArray[i]; end; Das macht es ja auch:
Delphi-Quellcode:
SetLength(LocalSentenceArray, length(Dialogs.SentenceArray));
for i := 0 to high(Dialogs.SentenceArray) do LocalSentenceArray[i] := Dialogs.SentenceArray[i]; |
Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
:wall: :wall: :wall:
Danke :angel: ^^ |
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:15 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