![]() |
OnChange-Verarbeitung bei eigenem Edit-Objekt
Hallo,
folgendes Problem (OOP-Anfänger :-) ): wie kann ich bei eigenen Edit-Objekten sowohl im Objekt als auch außerhalb (im Formular) auf OnChange reagieren? Konkret: da ich in einem Formular viele Eingabefelder mit angrenzenden Textfeldern und besonderem Verhalten brauche, habe ich mir ein eigenes Objekt hierfür gemacht
Delphi-Quellcode:
Im FormCreate meines Formulars werden diese InputBoxen jetzt instantisiert und gezeichnet (kann man sicherlich auch zusammenfassen, aber egal):
type TInputBlock = class(TEdit)
private FEdit: TEdit; ... protected procedure edtChange(Sender: TObject); ... public constructor Create(InputData: TInputData; InputDDName: TInputDDNames); procedure ShowBox(parent: TWinControl; col: integer); //procedure OnChange2(Sender: TObject); ... end; procedure TInputBlock.ShowBox(parent: TWinControl; col: integer); begin ... FEdit:=TEdit.Create(FPanel); FEdit.Parent:=FPanel; FEdit.Name := 'edt_'+IntToStr(col); FEdit.SetBounds(120,2,60,20); FEdit.Text := dd2s(FInputData[FInputDDName],-1); FEdit.OnEnter := edtEnter; FEdit.OnExit := edtExit; FEdit.OnKeyPress := edtKeyPress; FEdit.OnChange := edtChange; ... end; procedure TInputBlock.edtChange(Sender: TObject); var dd: Double; begin if s2dd(FEdit.Text,dd) then begin // erfolgreiche Umwandlung in Double => Wert speichern FInputData[FInputDDName] := dd; FEdit.Color:= clYellow; ... end else begin // Umwandlung fehlgeschlagen FEdit.Color:= clRed; end; end; //procedure TInputBlock.OnChange2(Sender: TObject); //begin // edtChange(Sender); //end;
Delphi-Quellcode:
Soweit klappt das gut: kann im Formular viele Felder erzeugen, die ihre Werte bei Eingabe automatisch prüfen und wegsichern bzw Fehleingaben verhindern und durch Farbe kennzeichnen, also jedes Feld für sich verarbeitet intern das OnChange über edtChange.
inpX := TInputBlock.Create(myData,iTS);
inpX.ShowBox(scrInput, col); ... Allerdings müssen die Boxen untereinander Wechselwirkung haben, d.h. bei Eingabe/Auswahl bestimmter Werte z.B. in Box inpX (Comboboxen kommen noch) muss sich der Inhalt von Box inpY und inpZ entsprechend anpassen. Also sollte ich im Formular ebenfalls auf OnChange reagieren, aber natürlich das Basisverhalten der Box behalten/erben. Ich dachte mir, ich könne im Formular eine eigene, zentrale Procedure machen, die ich dem OnChange jeder Box zuweise und die somit zuerst durchlaufen wird, und dann aber seinerseits die jeweilige Original-Routine aufruft (daher auch mal der Versuch mit OnChange2, um OnChange nicht zu überschreiben)
Delphi-Quellcode:
Aber leider wird immer noch die edtChange direkt durchlaufen, die InputChanged wird gar nicht erst aufgerufen.
inpX.OnChange := InputChanged;
... procedure TFormSingle.InputChanged(Sender: TObject); begin ... if Sender is TInputBlock then TInputBlock(Sender).OnChange(Sender); ... end; Wo liegt der Denkfehler, kann mir da jemand vielleicht bitte einen Tipp geben? Gruß, jokeBB |
Re: OnChange-Verarbeitung bei eigenem Edit-Objekt
[edit]
Jetzt seh ich das gerade... Deine Komponente ist ein "TEdit" und sie erzeugt intern nochmals ein TEdit, welches sie aber extern verwalten läßt, von einem femden TPanel, welches als Parent und Owner des Edits fungiert .... wieso? Somit sind es ja nun 2 Edits. TInputBlock erzeugt das Edit, also sollte das Edit auch dessen Besitz bleiben. Wenn du den Namen nicht wirklich brauchst, dann weiße .Name nichts zu. Das erspart dir später mal Probleme, falls schon eine gleichnamige Komponente existieren sollte. [/edit] Überschreibe in deiner Komponente dieses:
Delphi-Quellcode:
Das Change entspricht dem OnChange.
TInputBlock = class(TCustomEdit)
protected procedure Change; override; end; procedure TInputBlock.Change; begin ... inherited; end; Über die Methode Change hast du dann die interne Rückmeldung über das Change-Ereignis und über das Property OnChange wäre das Ereignis weiterhin extern verfügbar. PS: Idealer Weise leitet man soeine Komponente von TCustomEdit ab. Somit hat man mehr Kontrolle über die Freigaben und TCustomEdit wurde auch ja extra für sowas Eingeführt. Schau dir einfach mal an, wie TEdit definiert ist, dann siehst du vielleicht schon, was gemeint ist. |
Re: OnChange-Verarbeitung bei eigenem Edit-Objekt
Zunächst mal danke für die Antwort.
Zu dem doppelten TEdit und dem Panel als Owner: zunächst hatte ich mein Objekt nur von TObject abgeleitet. In diesem Objekt wurden als Kernelement das TEdit, aber auch weitere Label, Panel u.a. erzeugt. Alles zusammen habe ich auf ein Panel gepackt, so dass ich die Positionen immer nur innerhalb des Panels angeben musste. Hatte soweit schon alles funktioniert. Um dann aber dem gesamten TInputBlock ein OnChange zu vererben, habe ich ihn von TEdit statt von TObject abgeleitet. Funktionell hat sich nichts geändert, aber das TInputBlock.OnChange war verfügbar. Ok, war vielleicht keine so geniale Idee... bezieht sich das OnChange jetzt auf das falsche TEdit? Ich probier mal aber auf jeden Fall mit deinem Vorschlag weiter. |
Re: OnChange-Verarbeitung bei eigenem Edit-Objekt
Zitat:
Leite deinen TInputBlock von TPanel ab und positioniere seine Objekte (Edit, Label und Co.) in diesem. (vielleicht noch den Rahmen des Panels im Constructor verstecken) Dann verpaß deinem TInputBlock ein neues öffentliches Property OnChange und eine interne Methode Change. Das Edit wird dann im Constructor erstellt und Owner, sowie Parent auf Self gesetzt. (freigeben mußt du das Edit nicht, denn darum kümmert sich ja der Owner, also die Inputbox selber, wenn diese freigegeben wird) Change wird dann den eigenen Edits (also denen innerhalb der InputBox) als Edit.OnChange zugewiesen. In TInputBlock.Change kommt dannnoch ein
Delphi-Quellcode:
Wird nun eines der Edits verändert, dann kann die Komponente (TInputBlock) dort darauf reagieren und falls der TInputBlock ein OnChange von außerhalb zugewiesen wurde, dann wird auch dieses aufgerufen.
if Assigned(FOnChange) then FOnChange(Self);
|
Re: OnChange-Verarbeitung bei eigenem Edit-Objekt
Cool, es funktioniert! Vielen Dank! Ich hab's zwar immer noch nicht so ganz geblickt, wer hier was von wem und überhaupt erbt, aber irgendwann kommt das auch noch. Wenn man's blickt, ist OOP doch irgendwie eine nette Sache...
P.S. FEdit:=TEdit.Create(Self); FEdit.Parent:=Self; hatte ich entsprechend deiner Empfehlung auch probiert, gab aber Schutzverletzung Falls es jemand interessiert (und jemand genauso lange grübelt wie ich), hier die Langform...
Delphi-Quellcode:
Sowie im Form
type TInputBlock = class(TPanel)
private FPanel: TPanel; FEdit: TEdit; FOnChange: TNotifyEvent; ... protected procedure Change(Sender: TObject); ... public property OnChange: TNotifyEvent read FOnChange write FOnChange; constructor Create(InputData: TInputData; InputDDName: TInputDDNames; parent: TWinControl; col: integer); ... end; ... constructor TInputBlock.Create(InputData: TInputData; InputDDName: TInputDDNames; parent: TWinControl; col: integer); begin ... FPanel:= TPanel.Create(parent); FPanel.Parent := parent; FPanel.SetBounds(0,(col-1)*25,250,25); ... FEdit:=TEdit.Create(FPanel); FEdit.Parent:=FPanel; FEdit.SetBounds(120,2,60,20); FEdit.Text := dd2s(FInputData[FInputDDName],-1); FEdit.OnChange := Change; ... end; ... procedure TInputBlock.Change; var dd: Double; begin if s2dd(FEdit.Text,dd) then begin // erfolgreiche Umwandlung in Double => Wert speichern FInputData[FInputDDName] := dd; FEdit.Color:= clYellow; ... end else begin FEdit.Color:= clRed; ... end; if Assigned(FOnChange) then FOnChange(Self); inherited; end; ...
Delphi-Quellcode:
Ergebnis: bei einer Änderung des Eingabefeldes wird zuerst die "innere" Routine (z.B. für die Eingabeprüfung) und dann die "äußere" (z.B. um andere Felder zu ändern) durchlaufen
procedure TFormSingle.FormCreate(Sender: TObject);
begin ... inpX := TInputBlock.Create(myData,iTS,scrInput, col); inpX.OnChange := InputChanged; ... end; procedure TFormSingle.InputChanged(Sender: TObject); begin ... Label1.Caption := 'Test'; ... end; |
Re: OnChange-Verarbeitung bei eigenem Edit-Objekt
Wie gesagt, TInputBlock ist ja nun selber das Panel, also wenn man es richtig initialisiert.
Delphi-Quellcode:
type TInputBlock = class(TPanel)
private FEdit: TEdit; FOnChange: TNotifyEvent; ... protected procedure Change(Sender: TObject); ... public constructor Create(Owner: TWinControl; InputData: TInputData; InputDDName: TInputDDNames; col: integer); property OnChange: TNotifyEvent read FOnChange write FOnChange; ... end; ... constructor TInputBlock.Create(OwnerAndParent: TWinControl; InputData: TInputData; InputDDName: TInputDDNames; col: integer); begin inherited create(OwnerAndParent); Parent := OwnerAndParent; SetBounds(0,(col-1)*25,250,25); ... FEdit:=TEdit.Create(Self); FEdit.Parent:=Self; FEdit.SetBounds(120,2,60,20); FEdit.Text := dd2s(FInputData[FInputDDName],-1); FEdit.OnChange := Change; ... end; ... procedure TInputBlock.Change; var dd: Double; begin if s2dd(FEdit.Text,dd) then begin // erfolgreiche Umwandlung in Double => Wert speichern FInputData[FInputDDName] := dd; FEdit.Color:= clYellow; ... end else begin FEdit.Color:= clRed; ... end; if Assigned(FOnChange) then FOnChange(Self); inherited; end; ... procedure TFormSingle.FormCreate(Sender: TObject); begin ... inpX := TInputBlock.Create(scrInput, myData,iTS, col); inpX.OnChange := InputChanged; ... end; procedure TFormSingle.InputChanged(Sender: TObject); begin ... Label1.Caption := 'Test'; ... end; |
Re: OnChange-Verarbeitung bei eigenem Edit-Objekt
ah, ok, klar - wie du schon schreibst "wenn man es richtig macht"... :roll:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:54 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 by Thomas Breitkreuz