AGB  ·  Datenschutz  ·  Impressum  







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

Wie erzeugt man ein Event?

Ein Thema von UliBru · begonnen am 19. Apr 2012 · letzter Beitrag vom 20. Apr 2012
Antwort Antwort
Seite 1 von 2  1 2      
UliBru

Registriert seit: 10. Mai 2010
155 Beiträge
 
Delphi 11 Alexandria
 
#1

Wie erzeugt man ein Event?

  Alt 19. Apr 2012, 11:04
Ich habe in einem früheren Thread, siehe hier mal gefragt wie ich ein Datenereignis festellen kann.
Mittlerweile habe ich daraus folgendes gemacht:
In einem eigenen Thread bearbeite ich zyklisch eintreffende Daten und speichere diese in zwei wechselseitigen Puffern. Grundidee: während der eine beschrieben wird, kann der zweite verarbeitet werden. Das klappt soweit.
Nun würde ich gerne im VCL-Thread eine Ereignisprozedur verwenden, die genau dann aufgerufen wird, wenn ein Pufferwechsel stattgefunden hat, natürlich mit dem Parameter, welcher der beiden Puffer nun fürs Lesen freigegeben ist. Quasi als würde der Thread einen Button-Click auslösen, mit dem dann in der zugehörigen onClick-Methode der Lesepuffer verarbeitet wird.

Meine Fragen: wie erzeuge ich dieses Event aus dem Thread heraus? Wie sieht eine Grundstruktur hierzu aus, was muss in der Main-Unit stehen und was im Thread? Gibt es da ein einfaches verständliches Beispiel?

Uli
Er wollte so richtig in Delphi einsteigen. Nun steckt er ganz tief drin ...
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#2

AW: Wie erzeugt man ein Event?

  Alt 19. Apr 2012, 11:10
http://www.michael-puff.de/Programmi...reignis1.shtml

Aber man kann auch mit Nachrichten arbeiten. Ist eventuell einfacher.
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

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

AW: Wie erzeugt man ein Event?

  Alt 19. Apr 2012, 11:13
Deklaration eines EventHandlers:
Delphi-Quellcode:
type
  TMyEvent = procedure(<Parameter>) of object;

  TDings = class
  private
    FOnEvent: TMyEvent;
    ...
  public
    property OnEvent: TMyEvent read FOnEvent write FOnEvent;
    ...
  end;

implementation

procedure TDings.DoSomething;
begin
  DoWork;
  if Assigned(FOnEvent) then
    FOnEvent(<Parameter>);
end;
Wobei man bei Events eines Threads (meistens) darauf achten sollte, dass man diese synchronisiert auslöst.
Delphi-Quellcode:
procedure TMyThread.Execute;
begin
  ...
  Synchronize(DoEvent);
  ...
end;

procedure TMyThread.DoEvent;
begin
  if Assigned(FOnEvent) then
    FOnEvent(<Parameter>);
end;
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
UliBru

Registriert seit: 10. Mai 2010
155 Beiträge
 
Delphi 11 Alexandria
 
#4

AW: Wie erzeugt man ein Event?

  Alt 19. Apr 2012, 12:25
Danke. Hab es nun wie folgt programmiert.

Im der Main-Unit:
Delphi-Quellcode:
interface

  type
  TMainForm = class(TForm)
  private
    ...
  public
    ...
    procedure OnBufferSwitch(bufidx:integer);
  end;

implementation

procedure TMainForm.OnBufferSwitch(bufidx:integer);
begin
  Label1.Caption := IntToStr(bufidx);
  DoSomething(bufidx);
end;
und dann in der Thread-Unit:
Delphi-Quellcode:
interface

type
  TOnBufferSwitch = procedure(bufidx: Integer) of object;

type
  TmyThread = class(TThread)
  private
    ...
    bufidx: integer;
    FOnEvent: TOnBufferSwitch;
  protected
    procedure Execute; override;
  public
    property OnEvent: TOnBufferSwitch read FOnEvent write FOnEvent;
  end;

implementation

procedure TVASThread.Execute;
var oldbufidx: integer;
begin
  FOnEvent := MainForm.OnBufferSwitch; //Zuweisung Ereignisprozedur
  while not(Terminated) do
  begin
    Fillbuffers; //do something
    ...
    if bufidx <> oldbufidx then
      Synchronize(SyncBufferSwitch);
    sleep(10);
  end;
end;

procedure TmyThread.SyncBufferSwitch;
begin
  if Assigned(FOnEvent) then
    FOnEvent((bufidx);
end;
Scheint zu klappen.
Er wollte so richtig in Delphi einsteigen. Nun steckt er ganz tief drin ...
  Mit Zitat antworten Zitat
TBx
(Administrator)

Registriert seit: 13. Jul 2005
Ort: Stadthagen
1.893 Beiträge
 
Delphi 12 Athens
 
#5

AW: Wie erzeugt man ein Event?

  Alt 19. Apr 2012, 12:29
Schmeiß mal ganz schnell die Zuweisung des Eventhandlers aus der Execute-Methode.
Diese Zuweisung gehört dahin, wo auch das Threadobjekt created wird (ich vermute mal. Deine Main-Unit).
Ansonsten müßte ja der Thread Dein Hauptformular kennen und das widerspricht absolut der OOP.

Gruß aus dem Hohen Norden
Thomas Breitkreuz
Gruß Thomas
- Admin DelphiPRAXIS
- Admin Delphi-Treff
- Embarcadero MVP
  Mit Zitat antworten Zitat
Thom

Registriert seit: 19. Mai 2006
570 Beiträge
 
Delphi XE3 Professional
 
#6

AW: Wie erzeugt man ein Event?

  Alt 19. Apr 2012, 12:54
Ansonsten müßte ja der Thread Dein Hauptformular kennen und das widerspricht absolut der OOP.
Thomas Nitzschke
Google Maps mit Delphi
  Mit Zitat antworten Zitat
UliBru

Registriert seit: 10. Mai 2010
155 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: Wie erzeugt man ein Event?

  Alt 19. Apr 2012, 13:02
Schmeiß mal ganz schnell die Zuweisung des Eventhandlers aus der Execute-Methode.
Diese Zuweisung gehört dahin, wo auch das Threadobjekt created wird (ich vermute mal. Deine Main-Unit).
Ansonsten müßte ja der Thread Dein Hauptformular kennen und das widerspricht absolut der OOP.
Danke, erledigt. Hatte das Threadobject direkt mit non-suspended kreiert, daher die (falsche) Zuweisung in Execute. Man lernt eben nie aus.
Er wollte so richtig in Delphi einsteigen. Nun steckt er ganz tief drin ...
  Mit Zitat antworten Zitat
Medium

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

AW: Wie erzeugt man ein Event?

  Alt 19. Apr 2012, 13:42
So konterkarierst du allerdings die Nebenläufigkeit, da der Thread für die Dauer die der Handler braucht ja steht, und der Buffer-Flip nicht mehr nötig wäre. Sauberer und mehr in deinem Sinne wären Fensternachrichten, die asynchron via PostMessage() möglich sind. Gerüst:

Delphi-Quellcode:
unit uDataThread;
const
  WM_BUFFERFLIP = WM_USER + 1234;

type
  TDataThread = class(TThread)
  private
    FHandlerHanlde: HWND;
    Buffer1, Buffer2, CurrentBuffer: TMyBufferType;
    Buffer1CS, Buffer2CS, CurrentCS: TCriticalSection;
  protected
    procedure Execute; override;
  public
    constructor Create(aHandlerHandle: HWND);
  end;

implementation

constructor TDataThread.Create(aHandlerHandle: HWND);
begin
  inherited Create(false);
  FHandlerHandle := aHandlerHandle;
end;

procedure TDataThread.Execute;
begin
  repeat
    CurrentCS.Enter;
    try
      // Do things with CurrentBuffer
    finally
      CurrentCS.Leave;
    end;

    if DoBufferFlip then
    begin
      PostMessage(FHandlerHandle, WM_BUFFERFLIP, Integer(CurrentBuffer), Integer(CurrentCS));
      FlipBuffersAndCriticalSections;
    end;
  until Terminated;
end;

{-------------------------------------------}
unit uMainForm;

uses
  uDataThread;

type
  TMainForm = class(TForm)
  private
    FDataThread: TDataThread;
    procedure BufferHandler(var Msg: TMessage); message WM_BUFFERFLIP;
  public
  end;

implementation

procedure TMainForm.BufferHandler(var Msg: TMessage);
begin
  TCriticalSection(Msg.WParam).Enter;
  try
    DoSomethingWithBuffer(TMyBufferType(Msg.LParam));
  finally
    TCriticalSection(Msg.WParam).Leave;
  end;
end;
Die CriticalSections sind dann wichtig, wenn der Handler länger braucht als das Befüllen eines Buffers, gehören aber auch zum "guten Ton". Ich persönlich würde sogar noch einen Schritt weiter gehen, und eine Liste von Buffern machen. Fertige werden vom Thread an diese gehängt und das MainForm via PostMessage() darüber informiert. Der Handler schnappt sich dann immer den ältesten Buffer, tut was er damit tun soll, und kümmert sich um die Freigabe sowie Löschung aus der Liste. Idealerweise schaut der dann grob so aus:
Delphi-Quellcode:
  while DataThread.BufferList.Count>0 do
  begin
    DoStuffWithBuffer(DataThread.BufferList[0]); // muss nicht synchronisiert werden, da der Thread diesen Buffer nicht mehr anfasst, und in der Liste nur hinten Added
    DataThread.ListCS.Enter;
    try
      DataThread.BufferList.Delete(0); // sollte hingegn doch gesynced werden, weil dabei Daten in der Liste verschoben werden, was sich bei einem parallelen Add() im Thread schlecht macht (TList verwendet intern Arrays, es ist keine einfache Linked-List.)
    finally
      DataThread.ListCS.Leave;
    end;
  end;
Hier muss also nur noch das Adden und Deleten in der Liste duch eine CS gesichert werden, und man könnte im Thread auch mehrere Buffer in die Liste werfen bevor man die Verarbeitung im MainForm anstößt. Zudem hat man so eine handliche Queue, die Phasen großem Buffer-Aufkommens flexibel puffert, und der Handler kann nach und nach alles abarbeiten wenn Zeit dafür ist.
"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)
  Mit Zitat antworten Zitat
UliBru

Registriert seit: 10. Mai 2010
155 Beiträge
 
Delphi 11 Alexandria
 
#9

AW: Wie erzeugt man ein Event?

  Alt 19. Apr 2012, 14:38
Danke, das sieht nicht schlecht aus. Muss ich aber erst einmal verdauen (=verstehen, realisieren, testen). Ich schau mir das mal näher an.
Vermutlich komme ich aber ohne TList aus, die Daten müssen später auch wieder zeitgerecht ausgegeben werden, da kann ich mir ein Buffer-Overrun oder -Underrun sowieso nicht leisten, dann muss das Programm stehen bleiben. Ergo muss der Handler schnell genug arbeiten. Und ich kann dann noch mit der Puffergröße angleichen.
Er wollte so richtig in Delphi einsteigen. Nun steckt er ganz tief drin ...
  Mit Zitat antworten Zitat
silver-moon-2000

Registriert seit: 18. Feb 2007
Ort: Schweinfurt
170 Beiträge
 
Delphi XE Professional
 
#10

AW: Wie erzeugt man ein Event?

  Alt 19. Apr 2012, 15:59
Tut mir leid, wenn ich diesen Thread einfach so entere und nichts sinnvolles beisteuern kann, aber ich hätte mal dazu eine Frage:

Sowohl Luckie als auch Medium raten hier zu Messages anstelle von Events. Kann mir einer der Materie-Kundigen kurz darlegen, warum hier Messages einfacher / vorzuziehen sind?
Oder etwas allgemeiner: Was ist der Unterschied zwischen Events und Messages (mit Ausnahme der möglichen Asynchronität (mithilfe von PostMessage (im Gegensatz zu SendMessage)))?

Oder, nochmal umformuliert: Gibt es Guidelines, wann welches Konstrukt sinnvoller / besser / effektiver / wasauchimmerer einzusetzen ist, oder ist das (wie so vieles) eher dem Gusto des Programmierers überlassen?
Tobias
Bitte nicht hauen , ich weiß es nicht besser
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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 15:46 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