Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   OnChangeValue ? (https://www.delphipraxis.net/187891-onchangevalue.html)

akurka 13. Jan 2016 09:23

OnChangeValue ?
 
Hallo
Ich suche eine Komponente die bei ànderung einer Variable (Externe Eingangswert) einen Event auslöst. Etwa in der Art : OnChangeValue.

Ich habe überall danach gesucht aber niergens gefunden.
Muss ich dann eine eigene Komponente schreiben ?

Der schöne Günther 13. Jan 2016 09:29

AW: OnChangeValue ?
 
Mach das doch mit einer Property dessen Setter-Methode ein "OnChange"-Event auslöst:

Delphi-Quellcode:
  TMeineKlasse = class
     private
      var FMeinWert: Integer;
      procedure setMeinWert(const value: Integer);
     public
      var OnValueChange: TNotifyEvent;
      property MeinWert: Integer read FMeinWert write setMeinWert;
  end;

procedure TMeineKlasse.setMeinWert(const value: Integer);
begin
   if (FMeinWert = value) then Exit;
   FMeinWert := value;
   if Assigned(OnValueChange) then OnValueChange(self);
end;

Perlsau 13. Jan 2016 12:36

AW: OnChangeValue ?
 
Zur Ergänzung: Man schreibt sich dann eine Ereignisbehandlung, z.B.:
Delphi-Quellcode:
procedure TFormMain.ExternValueChanged;
begin
  DoSomething;
end;
und weist z.B. im OnCreate oder im OnShow der Form dem Ereignis diese Methode zu:
Delphi-Quellcode:
procedure TFormMain.FormCreate(Sender: TObject);
begin
  OnValueChange := ExternValueChanged;
end;
Wird das Ereignis in einer anderen Unit bzw. Form ausgelöst, muß man darauf achten, daß diese andere Form bereits instaziiert wurde. Wird sie erst nach der Unit/Form, in der die Ereignisbehandlung steht, erzeugt, wählt man für die Zuweisung der Ereignisbehandlung zum Ereignis z.B. OnShow oder OnActivate statt OnCreate.

akurka 13. Jan 2016 13:13

AW: OnChangeValue ?
 
Hallo, danke für die beiden Beiträge.

Was den Setter anbelangt verstehe ich es nicht ganz, der Wert den ich überwachen will kommt von aussen, d.h es wird in meinem Programm gar nicht
verändert resp. gesetzt.
Im meinem Programm wird das Wert nur gelesen.

Ich meinte Setter bedeutet setzen eines bestehenden
Wertes und wenn es ungültig ist dann eine Exception auslösen. Verstehe ich es falsch ??

Beim zweitem Vorschlag was meinst Du mit DoSomething ?
Sollte da ein Vergleich zwischen AltWert und NeuWert statfinden ?
Aber wie soll daraus ein Event erzeugt werden ?

Zoot 13. Jan 2016 13:51

AW: OnChangeValue ?
 
Zitat:

Zitat von akurka (Beitrag 1326853)
Beim zweitem Vorschlag was meinst Du mit DoSomething ?

Delphi-Quellcode:
procedure TFormMain.DoSomething;
Var i : integer
begin
 for i := 0 to 999999 do
 begin
  beep;
  Sleep(1000);
 end;
end;

Perlsau 13. Jan 2016 15:57

AW: OnChangeValue ?
 
Zitat:

Zitat von akurka (Beitrag 1326853)
Was den Setter anbelangt verstehe ich es nicht ganz, der Wert den ich überwachen will kommt von aussen, d.h es wird in meinem Programm gar nicht
verändert resp. gesetzt. Im meinem Programm wird das Wert nur gelesen.

Du schreibst den Wert, der überwacht werden soll, doch in eine Variable, nicht wahr? Und diese Variable deklarierst du nun als Property. Properties (Eigenschaften) liest und schreibt man über Getter und Setter. Dabei stellt der Name (Bezeichner) des Properties die "von außen" ansprechbare Variable dar. Die "eigentliche" Variable, die den Wert tatsächlich vorhält, wird nach den Regeln der Code-Formatierung mit einem vorangestellten f gekennzeichnet:
Delphi-Quellcode:
Private
  fMeinWert : Integer;

Public
  Property MeinWert : Integer read GetfMeinWert write SetfMeinWert;
Das ist die Art & Weise, wie man Properties erstellt. Drückst du nun in der Zeile, in der das Property deklariert wird, die Tastenkombination Shift-Control-C, werden automatisch die beiden Methoden Getter und Setter erstellt. Nun kannst du "von außen" die Variable fMeinWert nur noch auf dem Weg über das Property ändern:
Delphi-Quellcode:
// Wert setzen
MeinWert := 65; //oder
MeinWert := AusgelesenerWert;
// Wert auslesen
MeineVariable := MeinWert;
Beim Setzen und Auslesen von MeinWert werden jetzt immer Setter und Getter des Properties aufgerufen. Hier kannst du dann z.B. das reinschreiben, was passieren soll, wenn sich die Variable ändert, also im Setter nach der Zuweisung DoSomeThing.

Zitat:

Zitat von akurka (Beitrag 1326853)
Ich meinte Setter bedeutet setzen eines bestehenden Wertes und wenn es ungültig ist dann eine Exception auslösen. Verstehe ich es falsch ??

Nein, Setter ist einfach die Methode, um den privaten Integer fMeinWert zu schreiben. Wenn du einer Variablen einen Wert zuweist, passiert ja sonst nichts. Wenn du einem Property einen Wert zuweist, kannst du im Setter zusätzliche Befehle unterbringen.

Zitat:

Zitat von akurka (Beitrag 1326853)
Beim zweitem Vorschlag was meinst Du mit DoSomething ?

DoSomething ist einfach das, was beim Setzen des Wertes passieren soll, eine Dummy-Procedure, da ich ja nicht wissen kann, was du da vorhast, wenn der Wert gesetzt wird.

Zitat:

Zitat von akurka (Beitrag 1326853)
Sollte da ein Vergleich zwischen AltWert und NeuWert statfinden ?

Das weiß ich doch nicht, was da stattfinden soll, das mußt du doch selber wissen. Du hattest doch oben geschrieben, du möchtest, daß etwas bestimmtes ausgeführt wird, wenn sich der eingelesene Wert ändert, nicht? Okay, dann schreibst du in den Setter das rein, was dann ausgeführt werden soll, am besten in einer eigenständigen Methode, die du dann im Setter aufrufst, was ich mit DoSomething quasi als Dummy bereits vorgeführt habe.

Zitat:

Zitat von akurka (Beitrag 1326853)
Aber wie soll daraus ein Event erzeugt werden ?

Ein Event – auf deutsch: ein Ereignis – mußt du nur dann erzeugen, wenn du Unit-übergreifend arbeitest. Mit anderen Worten: Befindet sich das Property in derselben Unit, in der sich auch die Methode, mit der auf die Änderung des Wertes reagiert werden soll, befindet, brauchst du kein Ereignis, dann kannst du das dort direkt erledigen. Befindet sich das Property jedoch in einer eigenständigen Unit, muß die Unit, die die Reaktions-Methode enthält, ja irgendwie mitbekommen, daß sich der Wert geändert hat. Zu diesem Zweck wurden die Events erfunden. Ein Event wird erst einmal als Typ deklariert, gewöhnlich vor der Typdeklaration der Klasse, wie ich dir anhand eines Beispiels zeigen möchte, in welchem das Ereignis in der Klasse TDatMod (UnitData) stattfindet:
Delphi-Quellcode:
TYPE
  TUpdateStatusbarEvent   = Procedure of Object; // Statusbar in Mainform

TYPE
  TDatMod = CLASS(TDataModule)
  ...
  PRIVATE { Private-Deklarationen }
    Var
      fUpdateStatusbar : TUpdateStatusbarEvent;
  ...
  PUBLIC { Public-Deklarationen }
    ...
    Property OnUpdateStatusbar   : TUpdateStatusbarEvent   read fUpdateStatusbar   write fUpdateStatusbar;
    ...
  END;
Ausgelöst wird das Ereignis dann durch diesen Befehl:
Delphi-Quellcode:
If Assigned(fUpdateStatusbar) Then fUpdateStatusbar;
Verbindest du nun in deiner Unit, in der die Reaktions-Methode steht, das Ereignis mit der Methode, wird diese Methode jedesmal aufgerufen, wenn das Ereignis stattfindet – oder wie man hier gewöhnlich sagt: wenn das Event feuert:
Delphi-Quellcode:
Procedure TFormMain.FormActivate(Sender: TObject);
begin
  ...
  DatMod.OnUpdateStatusbar := StatusBarAktuell;
  ...
end;
Ich setze dieses Event z.B. ein, um in der Mainform die Statusbar zu aktualisieren, wenn sich der Datensatzzeiger einer Tabelle geändert hat:
Delphi-Quellcode:
Procedure TDatMod.View_LogAccessAfterScroll(DataSet: TDataSet);
begin
  If Assigned(fUpdateStatusbar) Then fUpdateStatusbar;
end;
Damit wird nun jedesmal beim Scrollen einer Datenmenge, die z.B. in FormMain durch das Scrollen in einem DBGrid ausgelöst wurde, die Anzeige in der Methode StatusBarAktuell aktualisiert:
Delphi-Quellcode:
Procedure TFormMain.StatusBarAktuell;
begin
  StatBar.Panels[0].Text := GLD.IntToStrPunkte(DatMod.View_LogAccess.RecNo);
  StatBar.Panels[1].Text := GLD.IntToStrPunkte(DatMod.View_LogAccess.FieldByName('ID').AsInteger);
  StatBar.Panels[2].Text := DatMod.View_LogAccess.FieldByName('DATEI').AsString;
  Application.ProcessMessages;
end;
Solltest du entgegen meiner Erwartung nur Bahnhof verstehen, empfiehlt sich die Lektüre des einen oder anderen Tutorials, z.B. das beim Delph-Treff über Klassen und Objekte.

akurka 13. Jan 2016 16:27

AW: OnChangeValue ?
 
Hallo
Vielen vielen Dank für die ausführliche Erklärung.
Es ist sehr gut erklärt, soweit habe ich es verstanden.

Ich hatte die überwachte Werte bisher über mehrere Timer überwacht was im prinzip einem Polling gleichkommt, und natürlich auch dem Windows Prinzip wiederspricht.

Jetzt werde ich mein Programm entsprechend umstellen, ich schreibe Dir
dann ob es klappt.
Besten Dank und ein Gruss aus dem Wolkenverhangenem Engadin
Anton

akurka 13. Jan 2016 17:33

AW: OnChangeValue ?
 
Hallo Perlsau

Leider klappt es bereits bei der Deklaration nicht :
Delphi-Quellcode:
unit menueREF;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,ExtCtrls,
  NC__09,NC__08,NCAS09,NCKU00,NCKU09;

type
  TForm2 = class(TForm)
    Image1: TImage;
    procedure MenueCreate(Sender: TObject);
    procedure StatusBild;
    procedure Man;
    procedure MenueDestroy(Sender: TObject);
    procedure OnKeyPress(Sender: TObject; var Key: Char);
  private
    fBWStellung: Integer;
    { Private-Deklarationen }
  public
    Property BWStellung :Integer read GetfBWStellung write SetfBWStellung;
    { Public-Deklarationen }
  end;

var
  Form2: TForm2;
  ActiveImage :TImage;
  BWStellung := int(Status.CNC.ZBETR); //Status.CNC.ZBETR ist Byte
  F_KeyA :boolean;
  procedure OptionFehlt;

implementation
{$R *.dfm}
uses NCUP01,NCUP10,NCUP11,NCUP12,NCUP13;
//=====================================================
procedure TForm2.MenueCreate(Sender: TObject);
begin
  keypreview:=true;
usw.....
Bei der Compilation gibt es diese Meldung:
[Fehler] menueREF.pas(22): Feld- oder Methodenbezeichner erwartet

Eigentlich ist der zu überwachende Wert ein Byte (STATUS.CNC.ZBETR).
Ich habe es zuerst mit Byte probiert danach auch mit integer.
Es wird ein Feld verlangt also z.Bsp ein String
Muss ich meine Variable als String deklarieren d.h. Feld?
oder liegt sm am DELPHI7 dass es nicht schluckt ?
Gruss Anton

Perlsau 13. Jan 2016 17:45

AW: OnChangeValue ?
 
Ich sehe in deinem Code keine Getter- und Setter-Methoden. Die erzeugst du, wie ich oben bereits ausgeführt habe, indem du den Cursor auf die Zeile mit der Property-Deklaration setzt und die Tastenkombi Ctrl-Shift-C drückst. In den Setter schreibst du dann rein, was passieren soll, wenn der Wert gesetzt wird.

Hinweis: Eine Anleitung sollte man schon komplett ausführen, weil sonst Fehlermeldungen auftreten.

akurka 13. Jan 2016 19:13

AW: OnChangeValue ?
 
Hallo Perlsau
Tut mir leid dass ich Dich nochmal beanspruche aber es haut nicht.
Muss man für die Setter Deklaration immer eigene Klasse deklarieren
oder kann ich auch bestehende nehmen ? Ich habe beides probiert
aber ohne Erfolg. Was mache ich falsch ?

Delphi-Quellcode:
unit menueREF;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,ExtCtrls,
  NC__09,NC__08,NCAS09,NCKU00,NCKU09;

type
  TForm2 = class(TForm)
    Image1: TImage;
    procedure MenueCreate(Sender: TObject);
    procedure OnValueChange;
    procedure StatusBild;
    procedure Man;
    procedure MenueDestroy(Sender: TObject);
    procedure OnKeyPress(Sender: TObject; var Key: Char);
  private
     //fBWStellung: Integer;
     //procedure setBWStellung(const value: Integer);
    { Private-Deklarationen }
  public
      //OnValueChange :TNotifyEvent;
      //Property BWStellung :Integer read GetfBWStellung write SetfBWStellung;
    { Public-Deklarationen }
  end;

  TMeineKlasse = class
    private
       fBWStellung: Integer;
       procedure setBWStellung(const value: Integer);
    public
      OnValueChange :TNotifyEvent;
      Property BWStellung :Integer read getfBWStellung write SetfBWStellung;
    end;


var
  Form2: TForm2;
  ActiveImage :TImage;
  F_KeyA :boolean;
  procedure OptionFehlt;

implementation
{$R *.dfm}
uses NCUP01,NCUP10,NCUP11,NCUP12,NCUP13;
//=====================================================
//procedure TForm2.setBWStellung(const value: Integer);
procedure TMeineKlasse.setBWStellung(const value: Integer);
begin
  if (fBWStellung = value) then Exit;
    fBWStellung := value;
  if Assigned(OnValueChange) then
    OnValueChange(Self);
end;
//-------------------------------------------------
procedure TForm2.OnValueChange;
begin
  StatusBild;
end;
//====================================================
procedure TForm2.MenueCreate(Sender: TObject);
begin
  keypreview:=true;
  //BWStellung := int(Status.CNC.ZBETR);
  ActiveImage :=Image1;
  Form2.ClientWidth:=512;
  Form2.ClientHeight:=256;
  Form2.Image1.Width:=511;
  Form2.Image1.Height:=255;
  F_obereAchsen:=false;
  F_KeyA := false;
end;
//=====================================================
procedure TForm2.MenueDestroy(Sender: TObject);
die Fehler Meldung ist die gleiche :
[Fehler] menueREF.pas(35): Feld- oder Methodenbezeichner erwartet

Gruss
Anton

Perlsau 13. Jan 2016 20:34

AW: OnChangeValue ?
 
Du solltest eigentlich schon wissen, was du da tust. Das Property soll gelesen und geschrieben werden von getfBWStellung und SetfBWStellung. Dann mußt du deine Methoden auch so benennen. Wenn du, wie von mir empfohlen, auf der Property-Zeile Ctrl-Shift-C gedrückt hättest, wären diese Methoden automatisch richtig erstellt worden. Oder gibt's das bei deiner alten Version noch nicht? Das kann ich natürlich nicht wissen. Also wie gesagt: das, was hinter read steht, ist die Methode zum lesen des Property's, und das, was hinter write steht, die zum schreiben. Wenn du jetzt in der Deklaration ebenso wie in der Implementation dieses f einfügst, sollte es funktionieren.

Und vergiß nicht, die Tutorials durchzuarbeiten, damit deine Kenntnisse über OOP (Objektorientiertes Programmieren) voranschreiten können. Weißt du, ich hab das damals auch nicht alles auf Anhieb verstanden, sondern erst nach & nach durch viel Übung und ständiges Anwenden. Einfach nur so was abtippen und dann wie der Ochs vor einer kryptischen Fehlermeldung zu stehen, wird dich nicht wirklich weiterbringen ...

Dejan Vu 14. Jan 2016 06:17

AW: OnChangeValue ?
 
Habe ich das jetzt so verstanden, dass
Delphi-Quellcode:
STATUS.CNC.ZBETR
irgendwo außerhalb gesetzt wird und man auf die Änderung dieses Speicherbereiches reagieren will? Das kann mit der Lösung von Perlsau nicht funktionieren.

Laut Variable ist das der Status irgendeiner CNC-Maschine. Und dieser Wert ändert sich dann, wenn die CNC-Maschine ihren Status ändert. In der SPS-Welt pollt man den Wert (alle paar ms) und reagiert dann auf Änderungen.

Wenn der Treiber kein Callback anbietet, muss man selbst pollen. Das geht mit einem Timer, nur bekommt man die Änderungen dann nicht in Echtzeit mit. Falls damit ein Leitstand, also eine Anzeige des Status umgesetzt werden soll, reicht es aber.

Besser wäre es, eine Threadklasse zu schreiben, die den Status kontinuierlich prüft und bei Änderung ein Event auslöst (per Synchronize oder Queue). Dann hat man sein Event.

akurka 14. Jan 2016 11:02

AW: OnChangeValue ?
 
Hallo mitenand

Beitrag von Perlsau:
Zitat:

Wenn du, wie von mir empfohlen, auf der Property-Zeile Ctrl-Shift-C gedrückt hättest, wären diese Methoden automatisch richtig erstellt worden. Oder gibt's das bei deiner alten Version noch nicht? Das kann ich natürlich nicht wissen. Also wie gesagt: das, was hinter read steht, ist die Methode zum lesen des Property's, und das, was hinter write steht, die zum schreiben. Wenn du jetzt in der Deklaration ebenso wie in der Implementation dieses f einfügst, sollte es funktionieren.
genau das habe ich auch probiert aber mit oder ohne "f" die Fehlermeldung
ist immer die Gleiche.
Auch das mit Ctrl-Shift-C funktioniert nicht.
Ich fürchte das Problem liegt tatsächlich an meiner alte Delphi version.
Ja nun was tun ?
Allzuviel will ich in eine neue Delphi Version nicht investieren. Was empfielst Du mir ?

Uebrigens bin ich hauptsöchlich ein Hardware Entwickler (VHDL,FPGA)darum
bereitet mir dass OOP denken ziemliche Schwierigkeiten.
In den Tutorials die ich schon X-mal durchgelesen habe ist es immer so schön erklärt, aber die Praxis ist eine andere. Ja, ich gebs mir Mühe !!!
Gruss Anton

Beitrag von Dejan Vu
Zitat:

Habe ich das jetzt so verstanden, dass STATUS.CNC.ZBETR irgendwo außerhalb gesetzt wird und man auf die Änderung dieses Speicherbereiches reagieren will? Das kann mit der Lösung von Perlsau nicht funktionieren.
Laut Variable ist das der Status irgendeiner CNC-Maschine. Und dieser Wert ändert sich dann, wenn die CNC-Maschine ihren Status ändert. In der SPS-Welt pollt man den Wert (alle paar ms) und reagiert dann auf Änderungen.
Ja das ist so, der STATUS.CNC.ZBETR ist ein Byte aus einer 16 Byte Meldung
die in unregelmässigen Abständen über RS232 in einem Thread empfangen wird.
Die Meldung selber kommt relativ häufig aber der STATUS.CNC.ZBETR ändert
sich nur dann wenn der Benützer das Betriebswahlschalter wechselt.Und das kann Stunden dauern. Ausserdem gibt es ganzer Menge andere Meldungen.

Bis jetzt habe ich es mit Polling gelöst was aber nicht gerade sauber ist. Der Grund warum ich es anders machen will ist, dass bei einem BW Wechsel das aktuelle Menü komplett neu aufgebaut wird.
Sonst bleibt das Menue bestehen und es werden nur Anzeigen geändert.
Aber auch das stösst an Grenzen mit Polling.

Eigentlich suchte ich eine Komponente die auf Aenderung einer Variable
reagiert (OnChangeValue).
Dieser Komponente möchte ich dann für verschiedene Variablen
anwenden (OnChangeBWStellung, OnChangeIstwert, OnchangeAchsenWahl usw.)

Die Polling Lösung hat ein gewichtige Nachteil, es verbraucht sehr viel Rechenzeit(bei allen diesen Meldungen).

Im übrigem ist mir klar, dass wenn die neue Lösung funktioniert ich mich auch mit "kritische Region" befassen muss, das aber später,eines nach dem anderem.

Die RS232 ist sowieso nur vorläufige (alte) Lösung , im Zukunft möchte ich auf EtherCAT(oder OpenCAN) umstellen, schon deswegen möchte ich die Resourcen sparen.
Du hast dich offenbar auch schon mit der SPS Welt befasst, was schlägst Du vor ?

Gruss Anton

Jumpy 14. Jan 2016 13:29

AW: OnChangeValue ?
 
Delphi-Quellcode:
//interface-Teil

TMeineKlasse = class
  private
    fBWStellung: Integer;
    procedure setBWStellung(value: Integer);
    function getBWStellung:Integer;
  public
    OnValueChange :TNotifyEvent;
    Property BWStellung :Integer read getBWStellung write SetBWStellung;
  end;

//implementation-Teil

procedure TMeineKlasse.setBWStellung(value: Integer);
begin
  if (fBWStellung = value) then Exit;
  fBWStellung := value;
  if Assigned(OnValueChange) then
    OnValueChange(Self);
end;

function TMeineKlasse.getBWStellung:Integer;
begin
  Result:=fBWStellung;
end;
Hattes du überhaupt den Getter implementiert?

himitsu 14. Jan 2016 13:40

AW: OnChangeValue ?
 
Getter ist ja nicht wirklich nötig, außer man will den Zugriff threadsicher machen, oder man muß mehr machen, als nur ein Feld auszulesen.
Delphi-Quellcode:
type
  TMeineKlasse = class//(TComponent)
  private
    FBWStellung: Integer;
    FOnValueChange :TNotifyEvent;
    procedure SetBWStellung(Value: Integer);
  public//published? (vorallem für OnValueChange, wenn man TMeineKlasse im Designer AUF die Form legt)
    Property BWStellung: Integer read FBWStellung write SetBWStellung;
    property OnValueChange: TNotifyEvent read FOnValueChange write FOnValueChange;
  end;

procedure TMeineKlasse.SetBWStellung(Value: Integer);
begin
  if FBWStellung = Value then
   Exit;
  FBWStellung := Value;
  if Assigned(FOnValueChange) then
    FOnValueChange(Self);
end;

Im Thread kannst du nun per TThread.Synchronize oder TThread.Queue dem Property was zuweisen.
Der Thread wertet also die Records aus und setzt die entsprechenden Property und die Klasse kümmert sich um die Notifications.
(mit Queue, wenn der Thread nicht hängen soll, so lange der Hauptthread arbeitet, aber mit Generice/anonymen Methroden geht sowas einfacher)

akurka 14. Jan 2016 16:05

AW: OnChangeValue ?
 
Hallo
jetzt läuft es durch den Compiler auch durch. Es ist jetzt auch klar warum es immer ein Fehler bei der Compilation gab.

Delphi-Quellcode:
Property BWStellung :Integer read getBWStellung write SetBWStellung;
Wenn es in der Zeile das " read getBWstellung" gibt, ist natürlich auch die Funktion
"getBWStellung" notwendig. Ersetzt man dagegen das
read getBWStellung durch read fBWStellung kann man die getFunktion weglassen.

Es ist zwahr jetzt beim Compiler auch durch, aber es gibt leider kein Event beim änderung der BWStellung.

Delphi-Quellcode:
procedure TForm2.OnValueChange;
begin
  StatusBild;
end;
Die Procedur StatusBild wurde gar nicht aufgerufen bei
BWStellung Aenderung.Das konnte ich eindeutig mit dem Debugger feststellen.

Nun eine Frage:
Ich habe versucht nebenbei eine eigene Komponente zu
schreiben. Nun in den Tutorials wird für ein Event Auslösung z.Bsp. ein OnKeyPress genommen und entsprechend geändert.Was ich für mein Problem nicht brauchen kann.
In allen Tutorials die ich gefunden habe,
wurden immer als Beispiel Event von Tasten genommen.
Ist es darum, dass es keine andere WindowsMessage gibt?
Weiss jemand, wie man in eine eigene Komponente ein
Event auslöst für eine Wertänderung ? Oder ist es gar nicht möglich ?

Gruss Anton

TiGü 14. Jan 2016 16:36

AW: OnChangeValue ?
 
Zitat:

Zitat von akurka (Beitrag 1327059)
Es ist zwahr jetzt beim Compiler auch durch, aber es gibt leider kein Event beim änderung der BWStellung.

Delphi-Quellcode:
procedure TForm2.OnValueChange;
begin
  StatusBild;
end;
Die Procedur StatusBild wurde gar nicht aufgerufen bei
BWStellung Aenderung.Das konnte ich eindeutig mit dem Debugger feststellen.

Nun eine Frage:
Ich habe versucht nebenbei eine eigene Komponente zu
schreiben. Nun in den Tutorials wird für ein Event Auslösung z.Bsp. ein OnKeyPress genommen und entsprechend geändert.Was ich für mein Problem nicht brauchen kann.

Zeige doch bitte mal die Stelle in deinen Quelltext, wo du das schreibst:
Delphi-Quellcode:
DeinVariablenName := TMeineKlasse.Create;
DeinVariablenName.OnValueChange := Form2.OnValueChange

akurka 14. Jan 2016 16:59

AW: OnChangeValue ?
 
Hallo TiGü
Entschuldige, aber mir ist nicht ganz klar welche Stelle in meinem Programm sehen willst ?
Soll ich Dir die ganze Unit senden ?
Gruss Anton

Perlsau 14. Jan 2016 19:24

AW: OnChangeValue ?
 
Das schreibt TiGü doch "laut" und deutlich: Er möchte sehen, wo du eine Instanz deiner neuen Klasse erzeugst. Wenn du eine solche Stelle nicht finden kannst, dann erzeugst du keine Instanz deiner Klasse und kannst auch nicht mit dieser Klasse arbeiten.

Ich würde dir wirklich dringendst emfpehlen, mal das eine oder andere Class-Turorial durchzuarbeiten, denn offenbar verstehst du von dem, was man dir ständig an wertvollen Tips gibt, nicht mal die Hälfte. Diesen Umstand kannst nur du selbst ändern.

akurka 14. Jan 2016 22:43

AW: OnChangeValue ?
 
Hallo Perlsau

So habe ich die neue Klasse Instanziert, gemäss dem Tutorial :

Delphi-Quellcode:
//====================================================
procedure TForm2.MenueCreate(Sender: TObject);
begin
  keypreview:=true;
  ActiveImage :=Image1;
  Form2.ClientWidth:=512;
  Form2.ClientHeight:=256;
  Form2.Image1.Width:=511;
  Form2.Image1.Height:=255;
  F_obereAchsen:=false;
  F_KeyA := false;
  MeineKlasse :=TMeineKlasse.Create;
  //MeineKlasse.fBWStellung.OnvalueChange := Form2.OnValueChange;
  //MeineKlasse.fBWStellung.OnvalueChange := OnValueChange;
  //MeineKlasse.OnvalueChange := OnValueChange;
  //MeineKlasse.OnvalueChange := Form2.OnValueChange;
  //fBWStellung := Form2.OnValueChange;
  //fBWStellung := OnValueChange;
  // das frisst der Compiler nicht..
end;
Genügt das nicht ?
Ich meinte wenn die neue Klasse instanziert ist, sind auch die drin deklarierte Proceduren bekannt, oder nicht ?
Muss man die OnValueChange noch zusätzlich deklarieren ? das habe ich probiert, aber das schluckt der Compiler nicht.
Ich habe den verdammten Tutorial von vorne und zurück
heute nachmittag sicher 5 mal durchgelesen aber die Verwirrung
wird nur noch grösser.
Gruss Anton

akurka 14. Jan 2016 22:49

AW: OnChangeValue ?
 
ja übrigens das fehlt noch :
Delphi-Quellcode:

  TMeineKlasse = class
    private
       fBWStellung: Integer; //Hier ist der Wert gespeichert
       fOnValueChange :TNotifyEvent;
       procedure setBWStellung(const value: Integer);
       //function getBWStellung:Integer;
    public
      //BWStellung steht für Eigenschaft von fBWStellung
      Property BWStellung :Integer read fBWStellung write SetBWStellung;
      property OnValueChange: TNotifyEvent read FOnValueChange write FOnValueChange;
    end;
   // setBWStellung :Setter ist eine Methode um in fBWStellung zu schreiben
   //fBWStellung kann nur über das propperty ändern

var
  Form2: TForm2;
  MeineKlasse: TMeineKlasse;
  fBWStellung :integer;
  ActiveImage :TImage;
  F_KeyA :boolean;
  procedure OptionFehlt;

implementation
usw.

Perlsau 15. Jan 2016 00:47

AW: OnChangeValue ?
 
Akurka, tut mir leid, aber ich geb's hier auf. Offenbar fehlen mir noch weitere Informationen, um dein Problem richtig zu verstehen. Es gibt hier zahlreiche berufenere Geister als mich, die dir sicher gerne weiterhelfen werden.

akurka 15. Jan 2016 08:25

AW: OnChangeValue ?
 
Hallo Perlsau
ja ok, ich meine ich habe mein Problem genügend erklärt (siehe Antwort an Dich und Dejan Vu), vollständigkeits halber zitiere ich es noch einmal :

Zitat:

------------------------------------------------
Zitat von Dejan Vu
Habe ich das jetzt so verstanden, dass STATUS.CNC.ZBETR irgendwo außerhalb gesetzt wird und man auf die Änderung dieses Speicherbereiches reagieren will? Das kann mit der Lösung von Perlsau nicht funktionieren.
Laut Variable ist das der Status irgendeiner CNC-Maschine. Und dieser Wert ändert sich dann, wenn die CNC-Maschine ihren Status ändert. In der SPS-Welt pollt man den Wert (alle paar ms) und reagiert dann auf Änderungen.
------meine Antwort-----------------------------------------
Ja das ist so, der STATUS.CNC.ZBETR ist ein Byte aus einer 16 Byte Meldung die in unregelmässigen Abständen über RS232 in einem Thread empfangen wird.
Die Meldung selber kommt relativ häufig aber der STATUS.CNC.ZBETR ändert sich nur dann, wenn der Benützer das Betriebswahlschalter wechselt.Und das kann Stunden dauern. Ausserdem gibt es ganzer Menge andere Meldungen.

Bis jetzt habe ich es mit Polling gelöst was aber nicht gerade sauber ist. Der Grund warum ich es anders machen will ist, dass bei einem BW Wechsel das aktuelle Menü komplett neu aufgebaut wird.
Sonst bleibt das Menue bestehen und es werden nur Anzeigen geändert.
Aber auch das stösst an Grenzen mit Polling.

Eigentlich suchte ich eine Komponente die auf Aenderung einer Variable
reagiert (OnChangeValue).
Dieser Komponente möchte ich dann für verschiedene Variablen
anwenden (OnChangeBWStellung, OnChangeIstwert, OnchangeAchsenWahl usw.)

Die Polling Lösung hat ein gewichtige Nachteil, es verbraucht sehr viel Rechenzeit(bei allen diesen Meldungen).

Im übrigem ist mir klar, dass wenn die neue Lösung funktioniert ich mich auch mit "kritische Region" befassen muss, das aber später,eines nach dem anderem.

Die RS232 ist sowieso nur vorläufige (alte) Lösung , im Zukunft möchte ich auf EtherCAT(oder OpenCAN) umstellen, schon deswegen möchte ich die Resourcen sparen.

Nun muss ich auch die setter Methode immer wieder aufrufen
was dem Polling eigentlich gleich kommt, ist das nicht so ?

Nun ich verstehe, dass Du genug hast Dich mit OOP Anfänger
zu plagen. Trotzdem vielen Dank für Deine Hilfe, ich habe
wieder einiges gelernt.
Gruss Anton

Jumpy 15. Jan 2016 09:59

AW: OnChangeValue ?
 
Lies dir mal hier den 2ten Abschnitt: Prozedurale Typen und Objekte durch.

Da geht es auch um ein TNotifyEvent und wie man eine entsprechende Prozedur definiert, erzeugt und benutzt. Oder informiere dich einmal zum Stichwort "Methodenzeiger".


Musst du eigentlich mehrere verschiedene Werte überwachen (du würdest dann für jeden ein entsprechendes Objekt von TMeineKlasse brauchen) oder geht es nur um einen Wert? Im letzteren Fall könntest du dir den ganzen Aufwasch ja sparen und mit einer Variablen + Setter + Property direkt in Form2 arbeiten.

Mavarik 15. Jan 2016 10:27

AW: OnChangeValue ?
 
Zitat:

Zitat von akurka (Beitrag 1327100)
Nun muss ich auch die setter Methode immer wieder aufrufen
was dem Polling eigentlich gleich kommt, ist das nicht so ?

Klar...

Du möchtest einen Event... Aber wo soll der den her kommen? Wer soll den auslösen?

Wie pollst Du den? Du Fragst doch sicherlich etwas ab... Oder? Gibt es einen Trigger der RS232 Routine, nach dem Motto "Neue Daten da"? Das wäre eine Event... Auf den kannst Du reagieren, dann den Wert abfragen und gut ist. Kein Pollen mehr...

Mavarik

TiGü 15. Jan 2016 11:04

AW: OnChangeValue ?
 
So wäre das im Ansatz richtig:
Delphi-Quellcode:
procedure TForm2.MenueCreate(Sender: TObject);
begin
  keypreview := True;
  ActiveImage := Image1;
  Self.ClientWidth := 512;
  Self.ClientHeight := 256;
  Self.Image1.Width := 511;
  Self.Image1.Height := 255;
  F_obereAchsen := False;
  F_KeyA := False;
  MeineKlasse := TMeineKlasse.Create;
  MeineKlasse.OnvalueChange := Self.OnValueChange;
end;
Nun müsstest du uns nur noch die Stelle zeigen, wo du das machst:

Delphi-Quellcode:
MeineKlasse.BWStellung := ... // Die Zuweisung des neuen Wertes
// Das musst du ja irgendwie durch Pollen im Timer oder Thread umgesetzt haben?!

akurka 15. Jan 2016 11:07

AW: OnChangeValue ?
 
Hallo Jumpy
Besten Dank für Dein Tipp.
Ja nach der ersten Durchsicht ist es genau das was mir fehlt.
Habe es augedrückt und werde es genau studieren.

Zu Deiner Frage:

Ja es sind mehrere Werte aus den Meldungen die von der CNC über RS232
kommen. Die Wichtigste ist die Status.CNC Meldung(16 Byte,Array) und daraus das ZBETR(BetriebswahlSchalterStellung=BWStellung= 1 Byte).

Aber es soll aber auch bei der IstWertMeldung
( Anzahl Bytes variert,je nach Anzahl Achsen,pro Achse 24bit)
festgestellt werden ob sich irgend ein Istwert(24bit =>Integer) verändert hat.
Jetzt mache ich es mit Polling und Vergleich AltWert <> NeuWert und nur wenn eine Aenderung da ist, wird es Angezeigt.
Ziemlich umständlich und ein Resourcen Fresser.

Im grossen Ganzen sind es (je nach Betriebswahl) 2 bis 4 unterschiedliche Meldungen die permanent überwacht werden müssen.

Andrererseits muss ich sagen, dass die bisherige Lösung eigentlich nicht schlecht läuft.
Eleganter wäre natürlich eine Lösung wie bei
Tasten z.Bsp. OnKeyPress, darum meine Idee mit OnChangeValue.

Nur wenn sich ein Wert ändert wird entsprechender Erreigniss ausgelöst und der Wert Angezeigt.
Ob es dann weniger Rechenzeit braucht kann ich nicht beurteilen, aber ich will es probieren und testen.
Gruss Anton

Mavarik 15. Jan 2016 11:10

AW: OnChangeValue ?
 
Zitat:

Zitat von akurka (Beitrag 1327125)
Eleganter wäre natürlich eine Lösung wie bei
Tasten z.Bsp. OnKeyPress, darum meine Idee mit OnChangeValue.

Nur wenn sich ein Wert ändert wird entsprechender Erreigniss ausgelöst und der Wert Angezeigt.
Ob es dann weniger Rechenzeit braucht kann ich nicht beurteilen, aber ich will es probieren und testen.
Gruss Anton

Hast Du eigentlich meine Antwort gelesen?

akurka 15. Jan 2016 11:22

AW: OnChangeValue ?
 
Hallo TiGü
Besten Dank, das " MeineKlasse.OnvalueChange := Self.OnValueChange;"
hat gefehlt.

Ja mit der Polling, dass ist genau das Problem, das mache ich jetzt schon:
Zitat:

Delphi-Quellcode:
MeineKlasse.BWStellung := ... // Die Zuweisung des neuen Wertes
// Das musst du ja irgendwie durch Pollen im Timer oder Thread umgesetzt haben?!
siehe meine vorherige Antwort an Jumpy und an Perlsau.

Wird es punkto Rechenzeit überhaupt etwas bringen mit dem setter, wenn ich den Wert der Variable pollen muss ??
Gruss Anton

Mavarik 15. Jan 2016 12:12

AW: OnChangeValue ?
 
Zitat:

Zitat von akurka (Beitrag 1327130)
Wird es punkto Rechenzeit überhaupt etwas bringen mit dem setter, wenn ich den Wert der Variable pollen muss ??
Gruss Anton

Hast Du eigentlich meine Antwort gelesen?

TiGü 15. Jan 2016 13:16

AW: OnChangeValue ?
 
Zitat:

Zitat von akurka (Beitrag 1327130)
Wird es punkto Rechenzeit überhaupt etwas bringen mit dem setter, wenn ich den Wert der Variable pollen muss ??
Gruss Anton

Eigentlich nicht, denn dein Hauptproblem ist ja nicht das Aktualisieren des Formulars.
Da scheinst du ja mit den Vergleich von Alt- zu Neuwert nur zu erneuern, wenn du es musst.

Das Pollen scheint dein eigentliches Problem zu sein.
Hier wären mal konkrete Zahlenwerte gefragt.

Verbraucht dein Abfragethread ungewöhnlich viel CPU-Arbeit im Task-Manager?
Wenn ja, wieviel Prozent?

Wie oft pollst du denn? Mit welcher Frequenz oder im welchen Intervall?
Wenn du das nicht beantworten kannst, dann hast du einen Abfragethread, der stumpf im Execute die serielle Schnittstelle ausliest.
Dann erklärt sich der Ressourcenhunger.

akurka 15. Jan 2016 15:32

AW: OnChangeValue ?
 
Hallo Mavarik
Entschuldige die späte Antwort. Ich musste nach den ersten Antworten
schnell weg.
Du hast es richtig angesprochen, woher soll der Event kommen ?

Leider bringt es nichts auf Empfang der Meldungen vom RS232 zu triggern.

Der Grund ist, dass es z.Bsp mehrere Status oder Istwert Meldungen die genau gleich sind, also müssen gar nicht berücksichtigt werden.

Du kanst Dir das so vorstellen wenn z.Bsp die CNC Achsen gar nicht in
Bewegung sind wird im Prinzip immmer der gleiche Istwert öbermittelt.
Ab un zu mal bedingt durch Regelung gibt es ein Unterschied +/-1 um
dies aber u.U.in Abständen von Sekunden. Die Status-, Istwert-, Endlage- usw. werden aber in Abständen von ca. 50 - 100 mS empfangen.Es gibt also ganze menge Meldungen die nicht relevant sind.

Auf der andere Seite gibt es Situationen wo eine sehr schnelle Reaktion notwendig ist, darum die relativ kurzen Zeitabstände.

Die jetztige Polling Rate bei 4 Achsen ist ca. 50 mS, es ist ein Kompromiss.

Wenn man eine Taste drückt hat man die Methode OnKeyPress, ohne das
man die Taste ständig abtasten muss.
So etwas stelle ich mir vor aber für die Aenderung einer Variable.

Soviel ich weiss werden die Tastaur-Nachrichten im Supervisor Modus des uP's abgearbeitet, und damit sind auch die Windows Message verfügbar.

Ob so etwas auch für Memory ànderungen gibt entzieht sich meiner Kenntnis.

Vermutlich ist das bestehende, zugegeben etwas holprige Lösung
gleich das optimale.
Aber ich will es genau abklären ob es der Wahrheit letzter Schluss Schluss ist.
Gruss Anton

noisy_master 15. Jan 2016 16:21

AW: OnChangeValue ?
 
Ich mische mich jetzt auch mal kurz ein:
das mit dem OnKeyPress ist recht einfach zu erklären:
Wenn du eine Taste drückst generiert deine Tastatur einen Interrupt. Dieser wird von diversen Treibern "aufgefangen" und dann als Windows Message versendet...und auf dies Message reagieren dann halt entsprechende Komponenten.

Ist aber eine gaaannnzz doll abstahierte Darstellung.

Wenn du nun deine CNC dazu bringen könntest Nachrichten über die RS232 nur dann zu senden, wenn sich auch was geändert hat hättest du auch ein "event" auf das du reagieren könntest.
Ansonsten bleibt dir halt nur übrig die Infos von der CNC "kontinuierlich" auszulesen und das ist dann halt Polling....

akurka 15. Jan 2016 17:21

AW: OnChangeValue ?
 
Hallo Dirk
Danke, jetzt ist mir klar, dass ich kein OnChangeValue machen kann.
Bei der CNC wird es schwierig, resp. mit sehr grossem Aufwand verbunden (FPGA Aenderungen).

Aber vielleicht im Empfangs Thread für den COM Port nach jedem MeldungsEmpfang ein Vergleich zu machen und damit den Event auszulösen.
Während dem ein Byte empfangen wird kann man den vorherigen testen.
Mal versuchen.

Das Polling später im Programm tut u.a. auch der Empfang über den COM Port behindern, das habe ich bereits festgestellt wenn ich die Baudrate erhöht habe.

Besten Dank für den Tipp.
Anton

Perlsau 15. Jan 2016 17:27

AW: OnChangeValue ?
 
Ich verstehe noch immer nicht, wo das Problem sein soll. Was ich bisher, nachdem nun weitere Informationen vorliegen, verstanden habe:
  1. Eine CNC-Maschine sendet bei Änderung eines ihrer Parameter einen Bytecode an die serielle Schnittstelle.
  2. Ein eigenständiger Thread pollt diesen Input im Millisekunden-Abstand.
  3. Weicht der eingegangene Byetcode vom voherigen ab, soll ein Ereignis ausgelöst werden.
Hier muß man sich doch einfach nur den eingegangenen Bytecode merken und mit dem aktuellen vergleichen. Weist der neue Bytecode Unterschiede zum gespeicherten Bytecode auf, wird der neue Bytecode gespeichert und danach ein Ereignis ausgelöst, auf das eine Methode in der aufrufenden Unit oder Form reagiert. Da der gemerkte Bytecode außerhalb des pollenden Threads nicht verändert wird, ist auch keine Synchronisation notwendig.

Nachtrag: Es gibt doch diese AsyncPro-Komponente, mit der man, soweit ich informiert bin, alles handeln kann, was mit seriellen Schnittstellen zusammenhängt. Ich bin mir sicher, daß diese Komponentensammlung auch die Möglichgkeit beinhaltet, einen Com-Port zu überwachen und bei gewissen Änderungen ein Ereignis auszulösen:
The TApdComPort is designed to interface with a standard RS-232 or RS-485 serial port via the Windows communication drivers. (Quelle: DevGuide, S. 11)

Triggers and trigger handlers

Async Professional uses the term "trigger" for any serial port action that can cause its communications dispatcher to generate a VCL event. There are four types of triggers:
  • Data available – received data ist available
  • Data match trigger – a particular character or character string was received.
  • Status trigger – a status event occured
  • Time trigger – a timer expired.

Quelle: Reference Guide, Seite 22

Mavarik 15. Jan 2016 17:47

AW: OnChangeValue ?
 
Zitat:

Zitat von akurka (Beitrag 1327170)
Leider bringt es nichts auf Empfang der Meldungen vom RS232 zu triggern.

Selbstverständlich... Du scheinst etwas wirre Vorstellungen zu haben... Event vom Memory usw... alles Quark!

Die Kommunikation mit der CNC-Maschine läuft über die RS-232 Schnittstelle. PUNKT.

Also muss man die eingehenden Daten - je nach Baudrate - mit für heutige Rechner wenig CPU Last - SOWIESO einlesen...

Das ist der einzige Kommunikations-Kanal hier werden dann die Datenpakete auseinander genommen... Wenn dann eine Änderungen eintritt, die für die Software relevant ist, sendet der RS-232 Treiber eine Windows-Message. Bingo damit hast Du Deinen Event-Trigger... Ohne zu pollen!

Perlsau 15. Jan 2016 17:49

AW: OnChangeValue ?
 
Genau so :thumb: :!: :thumb:

akurka 15. Jan 2016 19:17

AW: OnChangeValue ?
 
Hallo mitenand,

mit der AsyncPro rennt Ihr offene Türe ein, ich verwende es bereits.
Dirk hat schon recht, dass ich falsche Vorstellung von
den OnChange... Methoden hatte.
Ja nun man lernt nie aus.
Besten Dank für die Unterstützung von Euch allen.

Gruss Anton

Perlsau 15. Jan 2016 21:21

AW: OnChangeValue ?
 
Zitat:

Zitat von akurka (Beitrag 1327201)
Hallo mitenand, mit der AsyncPro rennt Ihr offene Türe ein, ich verwende es bereits.

Das "Ihr" ist unzutreffend, denn der Vorschlag kam bislang allein von mir. Und ich bin weder adelig noch mehrere ...

Wenn du AsyncPro bereits verwendest, dann werden da auch Ereignisse ausgelöst, wenn am Comport ein Signal eintrifft. Wieso verwendest du das nicht so, wie es in den Manuals steht? Leider kann ich nichts weiter dazu sagen, da du uns bislang verschwiegen hast, daß du AsyncPro einsetzt, und somit auch kein Code vorliegt, der zeigt, wie du das anwendest.

Vermutlich wäre es das Beste, du würdest erstmal das Handbuch zu AsyncPro studieren, bevor du eine Komponente aus dieser Sammlung verwendest.

akurka 17. Jan 2016 11:44

AW: OnChangeValue ?
 
Hallo Perlsau
Entschuldige, war falsch,ich habe schon Dich gemeint-
Ich habe das AsyncPro darum nicht erwähnt weil ist es im Form1 verwende und zwar in einem
Thread der die Empfangene Meldungen direkt in Globale Variable abspeichert.

Da gibt es in Abständen von 50mS z.Bsp Status.CNC Meldungen und es kommen bis zu 10 Meldungen die genau gleich sind.
Mich interessiert aber nur, wenn sich etwas verändert hat, und so bin ich auf die doofe Idee gekommen es wäre nett eine OnChangeValue Erreigniss zu haben.

Ja nu manchmal hat man ein Brett vor dem Kopf, vor allem wenn man allein arbeitet und
mit niemandem die doofe Ideen diskutieren kann.

Mir jetzt auch klar das es am besten ist, die Meldungen im EmpfangsThread auf Gleichheit
zu testen. Für gar nichts ist das Exploit doch nicht gewesen, ich habe etwas mehr gelernt
über OOP.

Vielen Dank für Deine Erklärungen betr.setter und nicht zu ungut.
Heute schneit es wie verrückt im Engadin, so habe jede menge Zeit den EmpfangsThread
zu ändern.

Wenn es dich Interessiert für was das ganze ist :
http://www.antonkurka.ch/KurkaAGSeiten/Kurka_AG.htm

An dem Delphi Programm bin ich mit unterbrüchen schon fast zwei Jahren dran.
Da die Hardware jetzt endlich richtig funktioniert, kann ich mich jetzt voll mit
der Bedienungs Software (Delphi) beschäftigen.

Ubrigens habe ich mir erlaubt Dein Profil anzuschauen,sehr interessant Dein Werdegang.
Du hast die ganze Entwicklung praktisch von Anfang an miterlebt.

Gruss Anton


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:21 Uhr.
Seite 1 von 2  1 2      

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