![]() |
Fehlermeldung "Element hat kein übergeördnetes Fenster&
Liste der Anhänge anzeigen (Anzahl: 1)
Ich verzweifle hier nochmal mit meiner Thread-Beispielapplikation.
Dafür habe ich ein Hauptformular mit 2 Schaltern erstellt, wobei der erste Schalter testweise ein leeres Formular öffnet. Der 2. Schalter öffnet ein Thread-Formular, in dem sich 3 Memofelder sowie ein Abbruch-Schalter befinden. Zu jedem der 3 Memos gehört ein Thread, der die Memos mit Zufallszahlen befüllt. Das funktioniert soweit ganz gut. Der Abbruch-Schalter beendet die 3 Threads jeweils mit ihren Terminate-Funktionen und ruft ein Close auf, um das Fenster zu schließen und wieder zum Hauptformular zu gelangen. Leider resultiert daraus immer wieder die Fehlermeldung "Element hat kein übergeördnetes Fenster" (siehe auch Screenshot). Ich habe irgendwas davon gelesen, dass man Create oder CreateWnd überschreiben muss und ein Parent zuweisen muss. Damit hatte ich allerdings keinen Erfolg. Ich bilde mir aber ein, dass es etwas mit den Threads zu tun haben muss, da das erste Testfenster ja fehlerfrei geschlossen werden kann. Woran kann das liegen ? Notfalls kann ich die Beispielapplikation einmal hochladen. |
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
erst mal eine Frage: du erstellst VCL-Fenster innerhalb der Thread's, oder hab ich das falsch verstanden?
|
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Zitat:
|
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Passiert das Ganze auch, wenn du die Threads ganz weglässt?
Also nur beim Schließen des Fensters? |
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
OK, dann hab ich das wohl wirklich falsch verstanden :oops:
Also wird da wohl nicht das Problem liegen :angel2: Passieren kann nichts, wenn das Fenster schon weg ist und z.B. einer der Threads noch versucht darauf zuzugreifen? Die Threads werden ja nicht sofort du .Terminate beendet, sondern laufen noch etwas weiter (bis sie da ankommen wo sie selbst .Terminated prüfen und sich beenden). |
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Liste der Anhänge anzeigen (Anzahl: 1)
Sobald ich die Threads rausnehme, öffnet und schließt das Fenster ohne Probleme.
Ich habe einmal die Beispielapplikation angehängt, um einen besseren Eindruck von der Situation zu geben. |
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Ich habe nur das Kompilat gestartet. Bei mir tritt kein Fehler auf (XP SP 3).
|
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
wie gesagt, DoThread wird noch aufgerufen, nachdem das Fenster schon weg ist ... und dort entsteht auch die Exception.
PS: das ist schon "kraß"
Delphi-Quellcode:
(true) ?
while (true) and (Terminated = false) do
ja und dann wird es hier auch immer wieder gesagt: prüfe nicht auf True und False
Delphi-Quellcode:
@DeddyH: selbes System, aber ich hab Fehler (im Debugger gestartet)
while not Terminated do
[add] also entweder prüfst du in .DoThread ob das das Fenster noch existiert und greifst dann nicht darauf zu, oder die einfach Lösung für diesen Fall:
Delphi-Quellcode:
hier würde sich dann aber eine Schleife besser eignen, welche vor Close; drauf wartet, daß alle Thread beendet wurden.
procedure TThreadForm1.Button1Click(Sender: TObject);
begin Th1.Terminate; Th2.Terminate; Th3.Terminate; //while not (alle_threads_beendet) do begin Sleep(100); // Sleep(10); Application.ProcessMessages; // Application.ProcessMessages; //end; Close; end; |
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Tatsächlich, der Fehler tritt nur in der Delphi-IDE auf. Kannst Du das auch bestätigen ?
Ich verwende Delphi 2007 Pro mit allen Updates. |
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Ich hab auf der Arbeit nur Delphi 5 zur Verfügung, daher kann ich das nicht ausprobieren.
|
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Zitat:
|
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Zitat:
PS: hatte oben etwas nachgetragen und ich hab hier grad 'nen D2009 auf. |
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Okay, das ist schon mal etwas brauchbares. Wie kann ich abfragen, ob ein Thread nach Terminate geschlossen ist ? Die Suspend-Eigenschaft kann ich nicht nehmen, da die nur für die vorübergehende Pause von Threads zuständig ist. Es gibt wohl noch Terminated, darauf kann ich aber von der VCL nicht zugreifen.
Als zusätzliche Maßnahme wollte ich wie vorgeschlagen in DoThread prüfen, ob das das Fenster noch existiert. Kannst Du dafür evtl. auch einen Tipp geben ? Danke schon mal im voraus. |
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
.Terminated sagt nur, daß der Thread beendet werden soll, aber nicht ob er schon beendet wurde.
Entweder du setzt eine Ereignisprozedur für .OnTerminate und setzt dort etwas in deinem Programm wenn du in ReturnValue setzt ( <> 0), dann könnte man über ThreadID bestimmt den Wert abfragen. oder ganz einfach, du machst in deinen TThread-Abkömmling einen neuen Wert (z.B. Boolean), welcher beim Start False ist und setzt den am Ende deiner .Execute diesen via Synchronize auf True und fragst diesen dann in der Schleife ab. |
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Wie wäre es damit:
Delphi-Quellcode:
Zuvor muss aber noch das "while (True)" aus allen Threads raus.
Th1.Terminate;
Th2.Terminate; Th3.Terminate; Th1.WaitFor; Th2.WaitFor; Th3.WaitFor; Close; |
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
ahh, WaitFor garb's ja och noch ... hatte da nur erst die Angst, daß dieses die Nachrichtenschleife nicht weiter abrbeiten würde und so 'ne Endlosschleife entstünde :oops:
aber es geht :angel: |
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Zitat:
Delphi-Quellcode:
Und dann mit der Schleifenabfrage:
TBeispielThread1 = class (TThread)
private FMemo: TMemo; protected procedure Execute; override; procedure StarteThread; procedure DoThread; public Beendet : Boolean; constructor Create(Memo: TMemo; ThreadPriority: TThreadPriority); end; constructor TBeispielThread1.Create(Memo: TMemo; ThreadPriority: TThreadPriority); begin inherited Create(False); Priority:=ThreadPriority; FMemo:=Memo; Beendet:=False; end; procedure TBeispielThread1.Execute; begin while not Terminated do begin sleep(1); StarteThread; end; Beendet:=True; end;
Delphi-Quellcode:
Edit: Habe jetzt WaitFor genommen und es läuft ohne Fehler. Jetzt gibt es noch das Problem, dass ich jeweils in .DoThread prüfen will, ob das das Fenster noch existiert.
while (Th1.Beendet=False) or (Th2.Beendet=False) or (Th3.Beendet=False) do
begin Sleep(10); Application.ProcessMessages; end; |
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Zitat:
|
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Ich habe in meinen Execute-Methoden meiner Threads oft in der Schleife eine Variable, die ich von außen setzen kann.
Delphi-Quellcode:
Und im Hauptprogramm
while CanRun do
Delphi-Quellcode:
Und gewöhn dir mal ab, auf False und True abzufragen sondern nutze logische Operatoren wie NOT, AND, OR usw.
Thread.CanRun := False;
Thread.Terminate; Thread.WaitFor; Also bei dir
Delphi-Quellcode:
Vielleicht solltest du dir auch überlegen anstatt auf Beendet abzufragen ob er noch laufen darf, dann musst du nicht immer alles negiert denken. Das macht es auch einfacher ...
while (not Th1.Beendet) and (not Th2.Beendet) and (not Th3.Beendet) do
Und du solltest auch strikt VCL und Threads voneinander trennen. Die Threads machen keinen Sinn wenn du andauernd über Synchronize auf den Mainthread zugreifst. Einfach wie himitsu sagt, dafür sorgen das die Threads beendet werden, bevor das Fenster beendet wird. |
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
@quendolineDD: für den CanRun gibt es die .Terminated Variable im Thread.
Setzt man diese (z.B. durch den Aufruf von .Terminate) auf True, muß sich der Thread selbst beenden. Zitat:
|
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Zitat:
|
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Und wenn du dir zur Synchronisation einen Container baust, der alle Threads beherbergt und verwaltet? Das wäre glaube sinnvoller als für jeden Thread aufgrund einer anderen ID eine eigene Klasse zu schreiben ;-)
|
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Du hast doch in dem BEispiel 3 Threads, wleche im Grunde alle das Selbe machen, ist das in der "produktiven" Anwendung später auch so?
Denn so wie es jetzt ist, könnte mann alle Threads durch eine Thread-Klasse ersetzten. |
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Zitat:
|
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Dann schreibe dir eine Containerklasse, die die Threads verwaltet und die Ausgabe übernimmt.
|
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Zitat:
|
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Liste der Anhänge anzeigen (Anzahl: 1)
Ich benötige noch einmal Hilfe bzgl. dieser Thread-Beispielanwendung. Wenn ich anstatt der 3 Threads das ganze auf 10 Threads jeweils mit 10 Memofeldern ausweite, scheint das Fenster nicht mehr auf Aktionen zu reagieren. Dies betrifft etwa das Verschieben des Fensters oder das Drücken des Abbrechen-Schalters. Auch ein Verwenden von Application.ProcessMessages ändert daran nichts.
Anbei noch einmal die Beispielanwendung mit 10 Threads anstatt mit 3 Threads. Was kann man da machen ? Dass die Belastungsgrenze des Prozessors erreicht ist, kann ich mir nicht vorstellen. Der Prozess errteicht ja nichtmal 50 Prozent CPU-Auslastung. Die Threads verrichten ausserdem noch keine eigentliche Arbeit, sondern schreiben nur Zufallszahlen ins Memo. Bin über jede Hilfe dankbar. |
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Du mußt bedenken, daß die Thread die Ganze Zeit über eigentlich nichts anderes machen, als den Hauptthread zu sperren und den Memos was übergeben (was die meußte Zeut eines Threads passiert, da er sonst nix macht) ... tja und der Hauptthread hat dann kaum noch Zeit sich um die VCL zu kümmer, also daß die Form und alles darauf reagiert.
PS: warum die Threads nicht soviel CPU-Last verbrauchen, liegt daran, daß sie sehr viel Zeit nichts tun, da sich oftmals darauf Warten, daß der Hauptthread mal Frei wird, damit sie auch endlich mal darauf zugreifen können. |
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Hi,
also auf meinem nicht mehr ganz so jungen Laptop läuft das Programm ganz flüssig. Wenn Du das allerdings im Debugger laufen läßt kannst du die Performance nicht mehr beurteilen, da der Debugger viel zu viel Leistung verbraucht um deine Threads zu kontrollieren. Allerdings ist mir aufgefallen, dass du zuviel (nämlich die ganze) Arbeit innerhalb von Synchronize verrichtest.
Delphi-Quellcode:
Es sollte eigentlich die Berechnung...
Procedure TBeispielThread4.DoThread;
begin randomize; FMemo.lines.add('Test Thread 4 - '+IntToStr(Random(200))); end;
Delphi-Quellcode:
von der Ausgabe mit Synchronize getrennt werden.
...
Randomize; // auch schon hier nicht so toll, nur einmal pro Programminstanz zufallszahl := Random(200); // zufallszahl = membervariable des threads, ebenso logstring logstring := 'Test Thread 4 - ' + IntToStr(Zufallszahl); Synchronize (Ausgabe); ....
Delphi-Quellcode:
Es kommt grundsätzlich darauf an, die Zeit innerhalb einer Synchronize ten Methode so kurz wie möglich zu halten, und die zeitaufwändigen Teile innerhalb der Thread.Execute zu halten.
procedure TThread4.Ausgabe;
begin FMemo.Lines.Add(logstring); end; Gruss [edit]falsche Quelltextformatierung[/edit] |
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
@thkerkmann: Ich habe Deine Tips beherzigt und die eigentlichen Berechnungen in Execute untergebracht. Der Umstand, dass ich bei sehr aktiver Verwendung der Memos ein nicht mehr reagierendes Fenster habe, bleibt allerdings bestehen.
Hier habe ich etwas experimentiert und mal eine Sleep-Funktion eingefügt (etwa 500 Ticks vor jedem Schreibvorgang) und siehe da, dem Hauptthread bleibt wieder mehr Zeit für Reaktionen. In diesem Maße wie hier in der Beispielanwendung auf die Memos zugegriffen wird, ist das in der produktiven Anwendung natürlich nicht der Fall. Man könnte neben den eigentlichen Thread-Prioritäten auch die Fenster-Priorität erhöhen, ich glaube hierfür gibt es TForm1.SetPriority mit den 4 Prioritätsklassen Idle_Priority_Class, Normal_Priority_Class, High_Priority_Class und Realtime_Priority_Class. |
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Du mußt bedenken, daß ein Memo nicht grad schnell ist und vorallem wenn es mehr und mehr Zeilen werden auch immer langsamer wird,
dagwgen ist die "Berechnung" des Strings in einem Bruchteil der Zeit geschaft. Wie gesagt, das in Synchronize Dauert immernoch recht lang und da hier viele Threads den Hauptthread stark belasten, hat der kaum noch Zeit für sich selbst. Wenn es jetzt z.B. um ein Label geht ... da wäre es einfacher nur den String im Thread zu ändern und den Hauptthread selber sich den String in angemessenen Abständen abzuholen ... also sozusagen auch mal einige Strings zu überspringen ... somit kann der Thread schnell weiterarbeiten, der Hauptthread hat mehr Zeit und der Benutzer bekommt eh nicht mit, ob sich nun das Label 100te oder nur 50 Mal die Sekunde ändert. |
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Liste der Anhänge anzeigen (Anzahl: 1)
Deswegen könnte man ja einen Thread mitlaufen lassen, welcher alle neuen Berechnungen mitgeteilt bekommt. Der speichert die ab unnd gibt dann die Berechungen in angemessenen Zeitabständen an den Hauptthread weiter und trägt diese in allen Memos ein. Wenn du zB immer wartest bis alle 4 Threads berechnet haben, hast du nur noch einen Zugriff anstatt 4. Das würde schon mal den Hauptthread weniger belasten.
Da könnte die parallel mitlaufende Thread-Klasse ca. so aussehen:
Delphi-Quellcode:
Hab die Unit auch nochmal angehangen. Ist aber nicht getestet!
unit Unit2;
interface uses Classes, Windows; type TSyncThread = Class(TThread) constructor Create; private FCalculates : TStringList; FThreadHandles : TWOHandleArray; FRegistredThreads : Integer; function GetNextFree : Integer; protected procedure Execute; override; public procedure AddCalc(ACalc : String); procedure RegisterThread(hThread : THandle); procedure DeregisterThread(hThread : THandle); End; implementation { TSyncThread } procedure TSyncThread.AddCalc(ACalc: String); begin if Assigned(FCalculates) then FCalculates.Add(ACalc); end; constructor TSyncThread.Create; begin FCalculates := TStringList.Create; FreeOnTerminate := False; FRegistredThreads := 0; inherited Create(False); end; procedure TSyncThread.DeregisterThread(hThread: THandle); var I : integer; begin for I := 0 to FRegistredThreads do if FThreadHandles[I] = hThread then begin FThreadHandles := 0; DEC(FRegistredThreads); end; end; procedure TSyncThread.Execute; begin while not Terminated do begin WaitForMultipleObjects(FRegistredThreads, @FThreadHandles, True, INFINITE); //Die Ergebnise entweder Zwischenspeichern oder nicht oder wie auch immer //kannst natürlich auch waitall auf false setzen und dann alles immer wieder in die zwischenablage und dort vlt per addobject und dann immer das dazugehörige memo al object anhängen oder so //an VCL per Synchronize Ergebnisse übertragen end; end; function TSyncThread.GetNextFree: Integer; var I : integer; begin for I := 0 to High(FThreadHandles) do if FThreadHandles[I] = 0 then begin Result := I; Exit; end; end; procedure TSyncThread.RegisterThread(hThread: THandle); begin FThreadHandles[GetNextFree] := hThread; INC(FRegistredThreads); end; end. EDIT: Also wie ich mir das gedacht habe: Wenn die einzelnen Threads fertig sind, melden sie ihr Ergebnis an AddCalc, dort kannst du dann String und Memo abspeichern und fertig. Die Subthreads haben in ihren Konstruktoren die Registrierung und in ihren Destruktoren die Deregistrierung an dieser Klasse implementiert. Die Syncthread-Klasse musst du selber freigeben, die Subthreads enden wenn gebraucht selbst. Wie du halt willst. In welchen Abständen du nun alles abgleichst und dann an die VCL schickst, ist dir überlassen. Kannst ja alles mit der Zeit, mit der du wartest steuern ... Obiger Beispielcode habe ich unter Zeitdruck gemacht, hab hier Urlaubsvorbereitungen. Also viel Spaß damit ich lese in ein paar Tagen die Ergebisse weiter ;-) |
Re: Fehlermeldung "Element hat kein übergeördnetes Fens
Bist du nun zu einer Lösung deines Problems gekommen?
Hab noch ein paar Fehler im Quellcode entdeckt, aber wenn eh keine Antwort kommt, hat sich die Sache wohl erledigt? Lg |
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:30 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