AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Label Text ändern aus einem Thread heraus

Ein Thema von CreativeMD · begonnen am 25. Sep 2014 · letzter Beitrag vom 27. Sep 2014
Antwort Antwort
Seite 1 von 3  1 23      
Benutzerbild von CreativeMD
CreativeMD

Registriert seit: 11. Okt 2011
127 Beiträge
 
Delphi XE2 Architect
 
#1

Label Text ändern aus einem Thread heraus

  Alt 25. Sep 2014, 19:09
Hallo,

Viele von euch werden das Problem kennen, es ist kompliziert einen Labeltext aus einem Thread heraus zu update.

Der einfachste Weg ist das ganze über Synchronize zu lösen.

Eigentlich sollte es aber dann funktionieren, tut es aber nicht. Ich habe schon alles mögliche versucht und ich bekomme den Text nicht geupdatet.

Was irgendjemand wo das Problem liegen könnte? Eine Einstellung der TForm oder irgendetwas anderes?
Die andere TForms kann ich ohne Probleme aus dem Thread heraus bearbeiten nur nicht die Hauptform .

Vielen Dank für eure Hilfe.
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.625 Beiträge
 
Delphi 12 Athens
 
#2

AW: Label Text ändern aus einem Thread heraus

  Alt 25. Sep 2014, 19:15
Wie soll man darauf antworten, wenn man den Code nicht kennt?
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Benutzerbild von CreativeMD
CreativeMD

Registriert seit: 11. Okt 2011
127 Beiträge
 
Delphi XE2 Architect
 
#3

AW: Label Text ändern aus einem Thread heraus

  Alt 25. Sep 2014, 19:23
Ja ich will auch immer den Code sehen, aber da ist überhaupt nichts auffälliges


hier die Thread-Klasse:
Delphi-Quellcode:
TBackgroundThread = class(TThread)
    Text : String;
    procedure setLabelText;
    procedure Execute; override;
    constructor Create;
  end;

procedure TBackgroundThread.setLabelText;
begin
  if Text <> OverviewF.lblTaskBackground.Caption then
  begin
    Log.AddLog('Setting label to from "' + OverviewF.lblTaskBackground.Caption + '" to "' + Text + '"');
  end;
  OverviewF.lblTaskBackground.Caption := Text;
//Ja, ich hab auch alles möglich versucht update zu daten oder mit progressmessages zu arbeiten
end;

procedure TBackgroundThread.Execute;
begin
  while Application.Active do
  begin
    OverViewF.cmdProgressBackground.Reset;
    if Tasks.Count > 0 then
    begin
      Tasks[0].runTask(OverViewF.cmdProgressBackground);
      Text := Log.getLastRow;
      Synchronize(setLabeltext);
    end
    else
    begin
      Text := 'Nothing to do';
      Synchronize(setLabeltext);
    end;
    Sleep(10);
  end;
  Log.AddLog('Terminating Background Thread!');
end;

constructor TBackgroundThread.Create;
begin
  inherited Create;
  Log.AddLog('Creating Background Thread!');
end;
Das Thread wird beim OnShow der Form gestartet.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#4

AW: Label Text ändern aus einem Thread heraus

  Alt 25. Sep 2014, 19:50
MSDN-Library durchsuchenSendMessage und MSDN-Library durchsuchenPostMessage synchronisieren den Aufruf auch in den Thrad, in welchem die Windows-Komponente erstellt wurde, womit man dort selber nichts synchronisieren müsste.
Nur hat TLabel ja kein Handle, aber das wirkliche LABEL (Delphi-Referenz durchsuchenTStaticText) hätte Eines.


Und wenn man erstmal lernt, daß man doppelten Code besser vermeiden sollte und sich dann auch noch an die anonymen Methoden gewöhnt hat, dann wird das Leben viel einfacher.


Zitat:
Delphi-Quellcode:
if Tasks.Count > 0 then
begin
  Tasks[0].runTask(OverViewF.cmdProgressBackground);
  Text := Log.getLastRow;
  Synchronize(setLabeltext);
end
else
begin
  Text := 'Nothing to do';
  Synchronize(setLabeltext);
end;
Delphi-Quellcode:
if Tasks.Count > 0 then begin
  Tasks[0].RunTask(OverViewF.cmdProgressBackground);
  Text := Log.GetLastRow;
end else
  Text := 'Nothing to do';
Synchronize(SetLabeltext);
Delphi-Quellcode:
if Tasks.Count > 0 then begin
  Tasks[0].RunTask(OverViewF.cmdProgressBackground);
  Text := Log.GetLastRow;
end else
  Text := 'Nothing to do';
Synchronize(procedure
  begin
    if Text <> OverviewF.lblTaskBackground.Caption then
      Log.AddLog('Setting label to from "' + OverviewF.lblTaskBackground.Caption + '" to "' + Text + '"');
    OverviewF.lblTaskBackground.Caption := Text;
  end);
$2B or not $2B

Geändert von himitsu (25. Sep 2014 um 19:52 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.625 Beiträge
 
Delphi 12 Athens
 
#5

AW: Label Text ändern aus einem Thread heraus

  Alt 25. Sep 2014, 19:58
Oder man regelt das über Events, oder man schickt die Messages an das Fensterhandle statt an das nicht vorhandene Label-Handle. Fehlt da übrigens nicht ein override beim Konstruktor?
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Benutzerbild von CreativeMD
CreativeMD

Registriert seit: 11. Okt 2011
127 Beiträge
 
Delphi XE2 Architect
 
#6

AW: Label Text ändern aus einem Thread heraus

  Alt 25. Sep 2014, 20:10
Erstmal dankeschön für eure schnellen Antworten.

@himitsu ich hab es schon mit den Methoden SendMessage/PostMessage probiert. Es könnte aber auch sein das es falsch war, könntet ihr mir mal ein SendMessage Beispiel geben?
P.S. der Code ist durcheinandergewürfelt weil ich momentan erstmal nur das Problem beheben will und der Rest erstmal egal ist.

@DeddyH Beispiel?
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.625 Beiträge
 
Delphi 12 Athens
 
#7

AW: Label Text ändern aus einem Thread heraus

  Alt 25. Sep 2014, 20:36
Schnell zusammengetippt, kann noch Fehler enthalten:
Delphi-Quellcode:
type
  TOnSomethingHappenedEvent = procedure(var OldValue: string; const NewValue: string) of object;
  
  TMyThread = class(TThread)
  private
    FText: string;
    FOnSomethingHappened: TOnSomethingHappenedEvent;
    procedure DoOnSomethingHappened;
    ...
  public
    ...
    property OnSomethingHappened: TOnSomethingHappenedEvent read FOnSomethingHappened write FOnSomethingHappened;
  end;
  
procedure TMyThread.DoOnSomethingHappened;
var
  OldValue: string;
begin
  if Assigned(FOnSomethingHappened) then
    begin
      FOnSomethingHappened(OldValue, FText);
      Log('Changed from ' + OldValue + ' to ' + FText);
    end;
end;

procedure TMyThread.Execute;
begin
  ...
  Synchronize(DoOnSomethingHappened);
end;
Nun kannst Du dem Thread eine Methode vom Typ TOnSomethingHappenedEvent als Eventhandler für OnSomethingHappened zuweisen, der dann synchronisiert ausgeführt wird. Allerdings musst Du den Thread nun Suspended erzeugen, damit er nicht gleich losrennt, bevor die Property belegt wurde.
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#8

AW: Label Text ändern aus einem Thread heraus

  Alt 25. Sep 2014, 20:41
Bist du sicher, dass dein Thread überhaupt bis da hin kommt? Ich sehe null Exception-Handling, dafür aber diverse Zugriffe auf Komponenten im Mainthread ohne Synchronisierung, die den Thread frühzeitig ins Nirvana schicken können. (Und auch wenn du meinst nichts auffälliges mehr zu sehen, so kann man fast garantieren, dass so lange etwas nicht geht etwas dran verkehrt ist, was andere vielleicht eher erkennen - sei es wegen größerer Erfahrung oder einfach weil man nicht wie man selbst oft im Wald steht. IMMER Source mit posten. Das ist NIE falsch. BITTE!!!)

Delphi-Quellcode:
TBackgroundThread = class(TThread)
    Text : String;
    procedure setLabelText;
    procedure Execute; override;
    constructor Create;
  end;

procedure TBackgroundThread.setLabelText;
begin
  if Text <> OverviewF.lblTaskBackground.Caption then
  begin
    Log.AddLog('Setting label to from "' + OverviewF.lblTaskBackground.Caption + '" to "' + Text + '"');
  end;
  OverviewF.lblTaskBackground.Caption := Text;
//Ja, ich hab auch alles möglich versucht update zu daten oder mit progressmessages zu arbeiten
end;

procedure TBackgroundThread.Execute;
begin
  while Application.Active do
  begin
    OverViewF.cmdProgressBackground.Reset; // <-------- Kann knallen
    if Tasks.Count > 0 then
    begin
      Tasks[0].runTask(OverViewF.cmdProgressBackground); // <-------- Kann knallen, woher kommt Tasks überhaupt!? Es ist nicht Member der Threadklasse! Also: Syncen!
      Text := Log.getLastRow; // <-------- Kann knallen (ich vermute Log ist letztlich etwas, was in ein Memo schreibt.)
      Synchronize(setLabeltext);
    end
    else
    begin
      Text := 'Nothing to do';
      Synchronize(setLabeltext);
    end;
    Sleep(10);
  end;
  Log.AddLog('Terminating Background Thread!');
end;

constructor TBackgroundThread.Create;
begin
  inherited Create;
  Log.AddLog('Creating Background Thread!');
end;
Das sind alleine schon 3 Stellen in 7 Zeilen Code vor dem Aufruf um den es geht, in dem du genau DAS tust, was man eben NICHT tut - und du sogar versuchst richtig zu machen, aber leider nur in diesem einen Fall. Gewöhne dir einfach folgendes an: immer wenn ein Thread auf Variablen zugreift, die NICHT in eben genau dieser Threadklasse bzw. ihrer Execute-Methoden liegen, synchronisieren. Wenn du damit deadlocks bekommst, ist 100%ig am Konzept etwas falsch. Wenn es zu langsam wird, hast du Racing-Conditions ohne Sync, und am Konzept stimmt etwas nicht. Behandle Threads am besten wie komplett separate Programme. (Das sind sie sogar fast, bis auf eben, dass sie im selben Prozessraum liegen wie der Hauptthread, und daher auch einfach so auf den gemeinsamen Speicher zugreifen können. Aber eben nicht unbedingt immer sollten.)
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)

Geändert von Medium (25. Sep 2014 um 20:46 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von CreativeMD
CreativeMD

Registriert seit: 11. Okt 2011
127 Beiträge
 
Delphi XE2 Architect
 
#9

AW: Label Text ändern aus einem Thread heraus

  Alt 26. Sep 2014, 18:55
Schnell zusammengetippt, kann noch Fehler enthalten:
Delphi-Quellcode:
type
  TOnSomethingHappenedEvent = procedure(var OldValue: string; const NewValue: string) of object;
  
  TMyThread = class(TThread)
  private
    FText: string;
    FOnSomethingHappened: TOnSomethingHappenedEvent;
    procedure DoOnSomethingHappened;
    ...
  public
    ...
    property OnSomethingHappened: TOnSomethingHappenedEvent read FOnSomethingHappened write FOnSomethingHappened;
  end;
  
procedure TMyThread.DoOnSomethingHappened;
var
  OldValue: string;
begin
  if Assigned(FOnSomethingHappened) then
    begin
      FOnSomethingHappened(OldValue, FText);
      Log('Changed from ' + OldValue + ' to ' + FText);
    end;
end;

procedure TMyThread.Execute;
begin
  ...
  Synchronize(DoOnSomethingHappened);
end;
Nun kannst Du dem Thread eine Methode vom Typ TOnSomethingHappenedEvent als Eventhandler für OnSomethingHappened zuweisen, der dann synchronisiert ausgeführt wird. Allerdings musst Du den Thread nun Suspended erzeugen, damit er nicht gleich losrennt, bevor die Property belegt wurde.
Aber das wird auch nichts an der Tatsache ändern, dass das Label nicht updatet

@Medium daran liegt es nicht hab, dass updaten klappt auch wenn das Thread leer ist nicht

Mit der Form stimmt etwas nicht
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.625 Beiträge
 
Delphi 12 Athens
 
#10

AW: Label Text ändern aus einem Thread heraus

  Alt 26. Sep 2014, 19:07
Ob mit der Form was nicht stimmt, kannst Du ja testen, indem Du ohne Thread mal einfach in einem ButtonClick oder so die Beschriftung änderst.
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23      

 

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:59 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