Autor Beitrag
hui1991
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 433

Windows XP, WIndows Vista
Turbo Delphi Explorer| Delphi, PHP,Blitzbasic
BeitragVerfasst: So 10.08.08 15:18 
Hallo,

ich codiere mit meinem Programm Daten in ein anderes Format. Dies mache ich mit Threads. Der Hauptthread ist dazu da das Fenster neuzuzeichnen. Der andere Thread berechnet die Daten.
Bei den Informationen ist aber hin und wieder ein Fehler beim Zeichnen.
Manchmal wird die Schrift zu groß gezeichnet.
Kann es daran liegen, genau in dem moment der andere Thread die Anzeige aktualisiert und der Hauptthread das Label neuzeichnet.
Im Anhang wird gezeigt wie es groß und wie es normal aussieht.

Meine Frage ist nun: Wie kann ich es beseitigen?

Edit: Gerade bekam ich eine Fehlermeldung die unten als Screen ist und da steht:
ausblenden Quelltext
1:
Im Projekt ist eine Exeception der Klasse EInvalidOperation mit der Meldung 'Leinwand/Bild erlaubt kein Zeichnen' aufgetreten.					

Wie bekommt man den Fehler weg so das sich die 2 Threads nicht im Weg stehen?

MfG
hui1991
Einloggen, um Attachments anzusehen!
Hidden
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2242
Erhaltene Danke: 55

Win10
VS Code, Delphi 2010 Prof.
BeitragVerfasst: So 10.08.08 16:06 
Hi,

Mal so ven dem her, was ich bisher von Threads gehört habe: Lass doch den Hauptthreat die Daten Suche in der Entwickler-Ecke SYNCHRONISIERT aus deinem Threat auslesen und die Form auch ausschließlich von der Hauptanwendung bearbeiten.

mfG,

_________________
Centaur spears can block many spells, but no one tries to block if they see that the spell is a certain shade of green. For this purpose it is useful to know some green stunning hexes. (HPMoR)
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1335
Erhaltene Danke: 118

Win 10
RIO, CE, Lazarus
BeitragVerfasst: So 10.08.08 16:39 
Ein Thread darf niemals einfach so auf ein Fenster zugreifen und irgendwelche Eigenschaften von Komponenten ändern.

Wenn du über Delphi : Datei / Neu / Thread-Object einen Neuen Thread erstellst, dann steht das ganz deutlich als Kommentar in der neuen Unit.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
{ Wichtig: Methoden und Eigenschaften von Objekten in visuellen Komponenten dürfen
  nur in einer Methode namens Synchronize aufgerufen werden, z.B.

      Synchronize(UpdateCaption);

  und UpdateCaption könnte folgendermaßen aussehen:

    procedure RGBRenderer.UpdateCaption;
    begin
      Form1.Caption := 'Aktualisiert in einem Thread';
    end; }


Allgemein:
Eine Möglichkeit ist es, unter Verwendung von Syncronize aus deinem Thread heraus zu aktualisieren. Die bessere Lösung.
Die andere Möglichkeit ist, die Aktualisierung über deine Fenster zu realisieren. Unter Verwendung eines Timers oder OnIdle. Da kann es aber immer mal passieren das du einen Thread zu einem ungünstigen Zeitpunkt erwischst. Also, die schlechtere Lösung.

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
hui1991 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 433

Windows XP, WIndows Vista
Turbo Delphi Explorer| Delphi, PHP,Blitzbasic
BeitragVerfasst: So 10.08.08 16:59 
Ich hab den Thread als Code erstellt. Ich hab gerade die Werte mit:
InterlockedExchange
geändert.
Das hab ich aus dem Thema: www.delphi-library.d...20%20synchronisieren

Stand in der PDF drin, scheint auch zu funktionieren.
Ich schreibe es auf Synchronize um.
Problem ist nur wie bekomme ich die Werte von meiner Thread-Funktion in die Procedure?

Edit:
Ich werde einfach einen Record erstellen und dort alle Daten eingeben. Wenn ich den Synchronize-Befehl aufrufe, dann werden die Daten gelesen und eingetragen.
Hoffe das geht so.
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1335
Erhaltene Danke: 118

Win 10
RIO, CE, Lazarus
BeitragVerfasst: So 10.08.08 17:18 
Ich verwende dafür immer zwei Prozeduren.
Eine, und zwar die, die im Thread aufgerufen wird, hat Parameter. Die speichert die bekommenen Werte in, unter private im Thread liegenden Variablen.
Und ruft im Anschluss die Andere, Parameterlose via Synchronize auf.
Die Parameterlose holt sich dann die Variablen und aktualisiert die Ansicht.
Das ist zwar nicht unbedingt schön, ist aber die einzige Lösung die mir dazu einfällt.

// Edit: bist ja schon selber drauf gekommen :wink:

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
hui1991 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 433

Windows XP, WIndows Vista
Turbo Delphi Explorer| Delphi, PHP,Blitzbasic
BeitragVerfasst: So 10.08.08 17:40 
Ich kann Synchronize nicht aufrufen.

Meine Threadfunktion sieht so aus:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
procedure UpdateComponents;
begin
  //Hier Aktualisieren
  Form1.ProgressBar1.Max := Fensterinfo.ProgressBar1Max;
  Form1.ProgressBar1.Position := Fensterinfo.ProgressBar1Positon;
  Form1.Label5.Caption := Fensterinfo.Label5Caption;
  Form1.Panel2.Caption := Fensterinfo.Panel2Caption;
  Form1.Panel3.Caption := Fensterinfo.Panel3Caption;
end;

function ThreadFunc(tp: PThreadParams): Integer;
var
  Open : string;
  Save: string;
begin
  // Parameter lokalen Variablen zuweisen.
  Open := PThreadParams(tp)^.Open;
  Save := PThreadParams(tp)^.Save;

  //Hier wird dann irgendwas gemacht

  Synchronize(UpdateComponents); //An der Stelle kommt ein [Pascal Fehler] Unit1.pas(589): E2066 Operator oder Semikolon fehlt

  // Reservierten Speicher für Parameter wieder freigeben.
  Dispose(tp);
end;


in der Delphi-Hilfe steht:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
procedure TMyThread.PushTheButton;
begin
Button1.Click;
end;
...
procedure TMyThread.Execute;
begin
...
Synchronize(PushTheButton);
...
end;


Irgendwie funktioniert Synchronize nicht mit einer funktion.
Ich rufe die Funktion so auf:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
var
  Thread : THandle;
  ThreadID : Cardinal;
begin
  // Thread erzeugen.
  Thread := BeginThread(nil0, @ThreadFunc, nil0, ThreadID);
  //...
end;


Ich muss wohl den Thread anders erstellen. :(
Oder gibt es eine andere Möglichkeit.
Probiere schon 4 Stunden an den Threads rum. In der Zeit wäre das Programm schon fertig gewesen ^^
Boldar
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1555
Erhaltene Danke: 70

Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
BeitragVerfasst: So 10.08.08 17:53 
user profile iconhui1991 hat folgendes geschrieben:

An der Stelle kommt ein [Pascal Fehler] Unit1.pas(589): E2066 Operator oder Semikolon fehlt


Dann fehlt wohl ein Semikolon!!!
Poste doch mal den ganzen Code
hui1991 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 433

Windows XP, WIndows Vista
Turbo Delphi Explorer| Delphi, PHP,Blitzbasic
BeitragVerfasst: So 10.08.08 18:03 
Semikolon ist hinten dran. Irgendwas ist da noch falsch.
Welcher von den 3 Proceduren wird eigentlich verwendet für sowas:
ausblenden Quelltext
1:
2:
3:
4:
5:
[Delphi] procedure Synchronize(ASyncRec: PSynchronizeRecord; QueueEvent: Boolean); overload;

[Delphi] procedure Synchronize(AMethod: TThreadMethod); overload;

[Delphi] procedure Synchronize(AThread: TThread; AMethod: TThreadMethod); overload;


Zuletzt bearbeitet von hui1991 am So 10.08.08 18:32, insgesamt 5-mal bearbeitet
Boldar
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1555
Erhaltene Danke: 70

Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
BeitragVerfasst: So 10.08.08 18:23 
user profile iconhui1991 hat folgendes geschrieben:
Semikolon ist hinten dran. Irgendwas ist da noch falsch.
Welcher von den 3 Proceduren wird eigentlich verwendet für sowas:
ausblenden Quelltext
1:
2:
3:
4:
5:
[Delphi] procedure Synchronize(ASyncRec: PSynchronizeRecord; QueueEvent: Boolean); overload;

[Delphi] procedure Synchronize(AMethod: TThreadMethod); overload;  //--------------------> Die

[Delphi] procedure Synchronize(AThread: TThread; AMethod: TThreadMethod); overload;


Poste doch mal den Code vor der Stelle oder den Gesamten code!!!!!!!!
hui1991 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 433

Windows XP, WIndows Vista
Turbo Delphi Explorer| Delphi, PHP,Blitzbasic
BeitragVerfasst: So 10.08.08 18:32 
Ich hab mal einen Thread umgeschrieben auf:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
procedure UpdateComponents;
begin
  //Hier Aktualisieren
  Form1.ProgressBar1.Max := Unit1.Fensterinfo.ProgressBar1Max;
  Form1.ProgressBar1.Position := Unit1.Fensterinfo.ProgressBar1Positon;
  Form1.ProgressBar2.Max := Unit1.Fensterinfo.ProgressBar2Max;
  Form1.ProgressBar2.Position := Unit1.Fensterinfo.ProgressBar2Positon;
  Form1.Label5.Caption := Unit1.Fensterinfo.Label5Caption;
  Form1.Panel2.Caption := Unit1.Fensterinfo.Panel2Caption;
  Form1.Panel3.Caption := Unit1.Fensterinfo.Panel3Caption;
end;

procedure Threadladen.Execute;
var
  s : string;
  x,y: Integer;
begin
  Unit1.Fensterinfo.Panel2Caption := 'Status: Anwendung laden...';
  Unit1.Fensterinfo.ProgressBar2Max:=100;
  Unit1.hin_daten := TStringlist.Create;
  Unit1.Fensterinfo.ProgressBar2Positon:=2;
  Unit1.hin_leistung := TStringlist.Create;
  Unit1.Fensterinfo.ProgressBar2Positon:=4;
  Unit1.hin_daten.LoadFromFile('2.joined');
  Unit1.Fensterinfo.ProgressBar2Positon:=74;
  Unit1.hin_leistung.LoadFromFile('1.joined');
  Synchronize(UpdateComponents);  //Hier kommt der Fehler: [Pascal Fehler] Unit2.pas(77): E2250 Es gibt keine überladene Version von 'Synchronize', die man mit diesen Argumenten aufrufen kann
end;
  //Wenn ich es auskommentiere, dann gibt es keinen Fehler beim compilieren


Dieses Synchronize hat bei mir bis jetzt nie funktioniert. :(

Edit: Hab einen neuen beitrag erstellt, weil delphi-tag sonst nicht funktioniert.
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1335
Erhaltene Danke: 118

Win 10
RIO, CE, Lazarus
BeitragVerfasst: So 10.08.08 18:36 
Warum blos immer alle so giergig auf den Quelltext anderer Leute sind!?

Ich vermute mal das es daran liegt das die Prozedur aus der du den Aufruf machst nicht zu Thread gehört und damit Synchronize unbekannt ist. Denn Synchonize ist eine Prozedur des Threads!

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
hui1991 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 433

Windows XP, WIndows Vista
Turbo Delphi Explorer| Delphi, PHP,Blitzbasic
BeitragVerfasst: So 10.08.08 18:46 
Ich hab den Fehler gefunden.
Das muss so heißen
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
class procedure Threadladen.UpdateComponents;
begin
  //Hier Aktualisieren
  Form1.ProgressBar1.Max := Unit1.Fensterinfo.ProgressBar1Max;
  Form1.ProgressBar1.Position := Unit1.Fensterinfo.ProgressBar1Positon;
  Form1.ProgressBar2.Max := Unit1.Fensterinfo.ProgressBar2Max;
  Form1.ProgressBar2.Position := Unit1.Fensterinfo.ProgressBar2Positon;
  Form1.Label5.Caption := Unit1.Fensterinfo.Label5Caption;
  Form1.Panel2.Caption := Unit1.Fensterinfo.Panel2Caption;
  Form1.Panel3.Caption := Unit1.Fensterinfo.Panel3Caption;
end;

procedure Threadladen.Execute;
var
  s : string;
  x,y: Integer;
begin
  Unit1.Fensterinfo.Panel2Caption := 'Status: Anwendung laden...';
  Unit1.Fensterinfo.ProgressBar2Max:=100;
  Unit1.hin_daten := TStringlist.Create;
  Unit1.Fensterinfo.ProgressBar2Positon:=2;
  Unit1.hin_leistung := TStringlist.Create;
  Unit1.Fensterinfo.ProgressBar2Positon:=4;
  Unit1.hin_daten.LoadFromFile('2.joined');
  Unit1.Fensterinfo.ProgressBar2Positon:=74;
  Unit1.hin_leistung.LoadFromFile('1.joined');
  Synchronize(UpdateComponents); //Hier ist jetzt kein Fehler mehr
end;


1. Es muss in ein Thread-Objekt
2. Es muss eine Class Procedure sein.

dann geht es.

Die Lösung habe ich hier gefunden:
www.delphipraxis.net/topic91117.html

Eigentlich sollte als Fehlermeldung:
[Pascal Fehler] Unit1.pas(440): E2076 Diese Form des Methodenaufrufs ist nur für Klassenmethoden erlaubt

kommen, aber es kommt nur mit TThread.Synchronize