| Autor |
Beitrag |
Kay E.
      
Beiträge: 118
|
Verfasst: Fr 10.12.10 11:58
Hallo!
Ich habe eine kleine Komponente von TLabel abgeleitet, die die eingegebenen Zeichen beim verlassen des Feldes formatiert. Es werden dann nur positive Zahlen mit einer festgelegten Anzahl an Nachkommastellen dargestellt. Das behandle ich sinnigerweise in einem OnExit.
Jetzt hab ich das Problem, dass wenn ich dem Feld einen Wert programmseitig zuweise, dieser OnExit-Befehl nicht ausgeführt wird. Ich seh jetzt zwei offensichtliche Möglichkeiten. 1. ich schreib nach der Wertzuweisung ein explizites Komponente.Exit; was ich aber nicht möchte. Andere Komponenten bekommen das auch intern geregelt, daher möchte ich nicht meinen Code im Programm unnötig zumüllen. 2. ich schreib in das OnChange nen Verweis auf das OnExit, aber dann wird die Formatierung nach jedem Tastendruck sofort ausgeführt, was auch nicht gewünscht ist.
Wie kann ich das Problem lösen?
Danke schonmal für Anregungen! Moderiert von Gausi: Topic aus Delphi Language (Object-Pascal) / CLX verschoben am Fr 10.12.2010 um 11:15
|
|
Gausi
      
Beiträge: 8554
Erhaltene Danke: 481
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Fr 10.12.10 12:14
So als Idee: Teste, ob die Komponente grade den Fokus hat. Wenn ja, dann gibt der User da grade was ein und eine Fortmatierung ist noch unerwünscht. Wenn nein, dann erfolgte die Änderung automatisch, und eine Formatierung ist erwünscht/notwendig.
_________________ We are, we were and will not be.
|
|
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 10.12.10 12:21
Du musst ja nicht bei der Zuweisung Exit aufrufen, sondern die Funktion, die die Behandlung des neuen Werts durchführt. (Also die, die du in Exit auch aufrufst.)
Da Exit nur für die Fokusänderung zuständig ist, hat es mit einer Änderung auch nichts zu tun. Du musst die Reaktion also auch bei der Zuweisung manuell einbauen.
|
|
Kay E. 
      
Beiträge: 118
|
Verfasst: So 12.12.10 23:58
So, bin leider erst jetzt dazu gekommen, das auszuprobieren.
Der Vorschlag von Gausi funktioniert wunderbar. Auf die Idee bin ich nicht gekommen. Vielen Dank!
|
|
Kay E. 
      
Beiträge: 118
|
Verfasst: Mo 13.12.10 16:28
Jetzt hat sich das nächste Problem ergeben. Ich hab das mit der idee von gausi implementiert, aber jetzt hab ich das problem, dass wenn ich Programmseitig eine OnChange-Prozedur benutz, dass dann das Komponenten-interne OnChange überschrieben wird. Und wenn ich ein inherited reinsetz, bekomm ich nen StackOverflow.
Wär schön, wenn mir da jemand Hilfestellung geben könnte, wie ich das behandeln kann.
Hier der Quellcode der Komponente:
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: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122:
| procedure TFloatEdit.ChangeMethod(Sender: TObject); begin if not TFloatEdit(Sender).Focused then begin FormatFloatEdit(Sender); end; end;
constructor TFloatEdit.Create(AOwner: TComponent); begin inherited Create(AOwner);
OnExit := FormatFloatEdit; OnChange := ChangeMethod;
Alignment := taCenter; Width := 65;
Text:='1,00'; SetDecNumber(2); end;
procedure TFloatEdit.FormatFloatEdit(Sender: TObject); var vText, vText2: string; i: Integer; IsDecNumberZero: Boolean; begin FWrittenDecNumbers := 0; FCommaSet := false; if GetDecNumber = 0 then IsDecNumberZero := true else IsDecNumberZero := false;
vText := Text; vText2 := '';
for i := 0 to length(vText) - 1 do begin if IsDecNumberZero then begin if (ord(vText[i+1]) > 48) and (ord(vText[i+1]) < 58) then begin vText2 := vText2 + vText[i+1]; end else if (vText[i+1] = ',') or (vText[i+1]='.') then break; end else begin if FCommaSet then begin if (ord(vText[i+1]) > 48) and (ord(vText[i+1]) < 58) and (FWrittenDecNumbers < GetDecNumber) then begin vText2 := vText2 + vText[i+1]; inc(FWrittenDecNumbers); end; end;
if (ord(vText[i+1]) > 48) and (ord(vText[i+1]) < 58) and (FCommaSet = false) then vText2 := vText2 + vText[i+1] else if vText[i+1] = ',' then begin vText2 := vText2 + vText[i+1]; FCommaSet := true; end else if vText[i+1] = '.' then begin vText2 := vText2 + ','; FCommaSet := true; end; end; end;
if vText2 = '' then begin vText2 := '1'; end;
if (FCommaSet = false) and (not IsDecNumberZero) then begin vText2 := vText2 + ','; FCommaSet := true; end;
if FWrittenDecNumbers < GetDecNumber then begin for i := FWrittenDecNumbers to GetDecNumber -1 do vText2 := vText2 + '0'; end;
Text := vText2; end;
function TFloatEdit.GetDecNumber; begin result := FDecNumber; end;
procedure TFloatEdit.KeyPress(var Key: Char); begin inherited KeyPress(Key);
if Key = #13 then FormatFloatEdit(self); end;
procedure TFloatEdit.SetDecNumber(DecNumber: Integer); begin if DecNumber < 0 then FDecNumber := DecNumber * (-1) else FDecNumber := DecNumber;
FormatFloatEdit(self); end; |
Und hier noch der Programmseitige Aufruf:
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:
| procedure TForm1.FormCreate(Sender: TObject); begin FloatEdit := TFloatEdit.Create(self); with FloatEdit do begin Parent := Form1; Left := 50; Top := 50; OnChange := FloatEditChange; end; end;
procedure TForm1.FloatEditChange(Sender: TObject); begin if not TFloatEdit(Sender).Focused then ShowMessage('Override?'); end;
procedure TForm1.Button1Click(Sender: TObject); begin FloatEdit.Text := Edit1.Text; end; |
|
|
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mo 13.12.10 23:45
Du änderst selbst etwas, deshalb wird OnChange vermutlich wiederum ausgelöst, darin änderst du etwas, deshalb wird OnChange wiederum ausgelöst, darin...
--> StackOverflow
Du musst also dafür sorgen, dass du nicht auf deine eigene Änderung reagierst, wenn du Change überschreibst, was bei einer eigenen Komponente natürlich am sinnvollsten ist. Zum Beispiel mit einem Flag.
Die abgeleitete Komponente hat jedenfalls nichts an den OnXXX Handlern zu suchen. Die sind dafür da, von extern benutzt zu werden.
|
|
Kay E. 
      
Beiträge: 118
|
Verfasst: Di 14.12.10 15:46
Also den ersten Teil mit dem StackOverflow versteh ich, macht auch Sinn. Aber den zweiten Teil versteh ich leider nicht ganz.
Ich hab in nem anderen Thread gefragt, wie ich auf die Exit-Methode zugreifen kann, also dass die komponente etwas macht, wenn sie verlassen wird. Da hast du dann geschrieben:
jaenicke hat folgendes geschrieben : | Kay E. hat folgendes geschrieben : | | Aber das stimmt doch nicht, die OnExit-Methode ist doch in der TEdit definiert? | Nein, ist sie nicht. Definiert ist die Eigenschaft OnExit, der ein Ereignishandler zugewiesen werden kann.  |
Das hab ich so verstanden, dass ich jetzt der Eigenschaft OnExit der Komponente den Handler auf die Prozedur FormatFloatEdit geb (was ja auch funktioniert hat, bis ich dann OnChange respektive OnExit im Programm verändert hab).
Und jetzt sagst du mir, dass die Komponente nichts an den Onxxx-Handlern zu suchen hat. Aber wenn ich nicht die Eigenschaft OnExit beschreiben darf, wie kann ich dann auf das Ereignis reagieren?
Kann mir da bitte jemand nen kleinen Codeschnippsel als Denkanstoß geben? Das wär wirklich hilfreich!
Und was du mir mit dem Flag sagen willst, ist mir auch noch nicht so ganz klar, sorry :\
Danke schonmal!
|
|
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Di 14.12.10 15:54
Kay E. hat folgendes geschrieben : | | Ich hab in nem anderen Thread gefragt, wie ich auf die Exit-Methode zugreifen kann, also dass die komponente etwas macht, wenn sie verlassen wird. |
Oh, ja, in dem Code hast du ja Exit als Methode. Du hattest von OnExit als Methode geschrieben (aber das ist ja eine Eigenschaft), in den Code habe ich gar nicht geschaut.
Die Methode, die deklariert ist, ist DoExit. Diese kannst du überschreiben. Steht alles im Quelltext drin.
Alternativ kannst du auf die Message CM_EXIT reagieren.
|
|
Kay E. 
      
Beiträge: 118
|
Verfasst: Di 14.12.10 16:24
Also wenn ich in die StdCtrls.hpp reinschau, seh ich zwar das OnExit property, aber nirgends steht was zu DoExit. Ne andere Datei, die StdCtrls heisst, hab ich nicht gefunden, also geh ich mal davon aus, dass das die Definitionsdatei ist. Nur bedingt hilfreich ist, dass das in C geschrieben ist...
Wenn ich in der Hilfe nach "TEdit DoExit" such, find ich auch nichts. Sonst eine Datei, die TEdit heisst, gibts auch nicht.
Das ist jetzt vielleicht ne doofe Frage, aber: Wo find ich denn den Sourcecode von dem TEdit?!
|
|
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Di 14.12.10 16:32
Kay E. hat folgendes geschrieben : | | Also wenn ich in die StdCtrls.hpp reinschau |
Das ist ja auch wie du schon sagst eine C++ Dateierweiterung.
Den hier relevanten Code findest du in der Controls.pas im Quelltext von TWinControl, wovon TEdit abgeleitet ist. Diese Datei solltest du im Quelltext unter source\win32\vcl finden.
Du kannst den ursprünglichen Code nehmen, nur dass du Exit durch DoExit beim Überschreiben ersetzt.
|
|
|