| Autor |
Beitrag |
Kay E.
      
Beiträge: 118
|
Verfasst: Mi 24.11.10 04:22
Hallo zusammen!
Ich werd grad halb wahnsinnig... Das ist nicht die erste Komponente, die ich zusammenbastel und ich dachte eigentlich, dass ich das kurz in ner halben Stunde runterschreib, aber Pustekuchen...
Kurz zur Komponente: Es soll ein Editfeld werden, in das der Benutzer nur Zahlen eingeben kann, wobei ein Kommazeichen sowie ein Punkt (wird als Komma interpretiert und in Komma umgewandelt) erlaubt sind. Es sind nur Eingaben mit zwei Nachkommastellen erlaubt (danach werden keine Tasten mehr angenommen) und beim verlassen der Komponente werden nicht eingegebene Nachkommastellen mit Nullen aufgefüllt.
Wie gesagt: Eigentlich nichts wirklich wildes. Allerdings hab ich grad massive Probleme mit dem Compiler. Das ist der Code:
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:
| type TNumEdit = class(TEdit) private vComma:boolean; vDecAfterComma:byte; protected procedure KeyPress(Sender: TObject; Var Key: Char); override; public Constructor Create(Owner:TComponent); override; published property Alignment default taRightJustify; end;
procedure Register;
implementation
procedure Register; begin RegisterComponents('OwnComponents', [TNumEdit]); end;
Constructor TNumEdit.Create(Owner: TComponent); begin inherited Create(Owner); Alignment:=taRightJustify; vComma:=false; vDecAfterComma:=0; end;
procedure TNumEdit.KeyPress(Sender: TObject; var Key: Char); begin case Key of '0'..'9': ; '.': ; ',': ; else Key:=#0; MessageBeep(-1); end;
inherited KeyPress(Sender,Key); end; |
Jetzt zu den Fragen:
1) Compiler bringt folgende Fehlermeldung: [DCC Error] NumEdit.pas(16): E2037 Declaration of 'KeyPress' differs from previous declaration
Ich hab die Deklaration mehrfach gecheckt und seh keinen Fehler. Wo steckt das Problem?
2) Ich möchte den Anfangstext der Komponente auf 1,00 setzen, aber bei den default-Werten werden ja nur ordinale Typen zugelassen. Wie kann ich das eintragen, so dass der default-Wert auch im Objektinspektor erscheint? Oder reicht eine einfache Zuweisung in der Create-Methode aus, damit der Objektinspektor entsprechend aktualisiert wird? (konnte Komponente noch nicht installieren);
3) Ich ändere im Keypress-Event ja unter Umständen den Key. Seh ich das von der Logik her richtig, dass ich erst danach inherited mit dem geänderten Key aufrufen darf? (Logik sagt ja, aber wenn ich schon am fragen bin, dann stell ich das jetzt auch noch  )
Wär super, wenn ihr mir helfen könntet. Danke schonmal!
|
|
Tranx
      
Beiträge: 648
Erhaltene Danke: 85
WIN 2000, WIN XP
D5 Prof
|
Verfasst: Mi 24.11.10 05:11
Hallo,
habe es mal versucht. TEdit hat Parameter für Keypress nur
Delphi-Quelltext 1: 2: 3:
| : KeyPress(var Key : char); : |
zu haben. Dann klappt es auch mit TNumEdit.
Zusätzlich hat das Messagebeep bei mir eine Verletzung der unteren Grenze erzeugt. Möglicherweise funktioniert der Aufruf Messagebeep(-1) nicht.
Außerdem scheint die Eigenschaft Alignment nur private (wenn überhaupt) deklariert zu sein, denn sie existiert nicht.
_________________ Toleranz ist eine Grundvoraussetzung für das Leben.
|
|
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mi 24.11.10 06:48
Kay E. hat folgendes geschrieben : | | Ich hab die Deklaration mehrfach gecheckt und seh keinen Fehler. Wo steckt das Problem? |
Dass du die Methode KeyPress überschreiben möchtest, aber bei dem Ereignis OnKeyPress nach dessen Deklaration schaust.
Kay E. hat folgendes geschrieben : | | Oder reicht eine einfache Zuweisung in der Create-Methode aus, damit der Objektinspektor entsprechend aktualisiert wird? |
Ja, denn wenn die Komponente auf dem Formular erzeugt wird, egal ob in der IDE oder zur Laufzeit, wird zuerst der Konstruktor aufgerufen und es werden danach die Eigenschaften gesetzt. Wenn dann die Eigenschaft noch nicht gesetzt war im Objektinspektor bleibt dann logischerweise der Standardtext aus dem Konstruktor erhalten.
Kay E. hat folgendes geschrieben : | | 3) Ich ändere im Keypress-Event ja unter Umständen den Key. Seh ich das von der Logik her richtig, dass ich erst danach inherited mit dem geänderten Key aufrufen darf? |
Ja, genau, oder eben gar nicht, wenn du das in manchen Fällen gar nicht möchtest.
Außerdem ist es sinnvoller von TCustomEdit statt von TEdit abzuleiten, denn genau dafür ist diese Klasse da. TEdit zementiert nämlich schon die Sichtbarkeit der ganzen Eigenschaften auf published (vorher sind die meisten noch public oder protected), was du bei TCustomEdit selbst definieren kannst.
Nebenbei noch etwas zum Stil:
Es ist allgemeine Konvention, dass private Felder mit einem großen F anfangen sollten. Also FComma bzw. FDecAfterComma.
Die anderen Sachen wie fehlende Leerzeichen sind nicht ganz so wichtig, wenn du mehr dazu lesen willst:
dn.codegear.com/article/10280 (englisch)
www.delphi-treff.de/delphi-styleguide/ (deutsch)
|
|
Kay E. 
      
Beiträge: 118
|
Verfasst: Mi 24.11.10 12:58
Oha, is dann doch schon ne Weile her, seit ich ne Komponente gebastelt hab. Ich schein da einiges vergessen zu haben. Danke für die Erinnerungen und Richtigstellungen!
@ jaenicke: Das die properties von TEdit schon auf published getrimmt sind, ist in dem Fall schon ok. Es soll im Prinzip die gleiche Komponente wie TEdit werden, nur eben mit oben genannten Änderungen.
Was die Leerzeichen angeht: Da hat sich mein Mitbewohner auch schon drüber beschwert. Ich versuch mich zu bessern
Den Styleguide hab ich mir durchgelesen und muss sagen, dass ich mich in den meisten Fällen an die Konvention halte (oben hab ich das 'F' Präfix vergessen gehabt, stimmt). Allerdings hab ich mir im Laufe meiner Programmierzeit angewöhnt, für Variablen, die nicht von Typendefinitionen abhängen, ein "v" ür Variable und bei Arrays ein "a" vorne anzuhängen. Damit weiß ich dann, auch wenn ich längere Zeit nicht mehr vor dem Code gesessen bin, was welche Variable für eine Aufgabe hat. Ich find, da gibt's schlechtere Konventionen, oder?
Achja, was ich noch nie nachvollziehen konnt: Für was steht eigentlich das "F" als Präfix?
|
|
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mi 24.11.10 13:17
Das F steht vermutlich für Field. Denn dein v ist ja auch falsch, da es für "Variable" steht. Schließlich sind das keine Variablen sondern private Felder.
|
|
Kay E. 
      
Beiträge: 118
|
Verfasst: Mi 24.11.10 19:13
Hallo,
jetzt muss ich doch nochmal fragen... Ich hab die Komponente jetzt ein wenig umgebaut, indem ich den String, der in Text steht, bei einem OnExit kontrollier und entsprechend anpasse, so dass er in das Schema der späteren Verwendung passt.
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:
| uses SysUtils, Classes, Controls, StdCtrls;
type TFloatEdit = class(TEdit) private FDecNumber: Integer; FWrittenDecNumbers: Integer; FCommaSet: Boolean; procedure SetDecNumber(DecNumber: Integer); function GetDecNumber: Integer; protected public constructor Create(AOwner: TComponent); override; procedure Exit; override; published property DecNumbers: Integer read GetDecNumber write SetDecNumber default 2; end;
procedure Register;
implementation
procedure Register; begin RegisterComponents('OwnComponents', [TFloatEdit]); end;
constructor TFloatEdit.Create(AOwner: TComponent); begin inherited Create(AOwner);
SetDecNumber(2); Text:='1,00'; end;
procedure TFloatEdit.Exit; var vText, vText2: string; i: Integer; begin inherited Exit;
FWrittenDecNumbers := 0; FCommaSet := false;
vText := Text; vText2 := ''; for I := 0 to length(vText) - 1 do begin if (ord(vText[i]) > 48) and (ord(vText[i]) < 57) then vText2 := vText2 + vText[i] else if vText[i] = ',' then begin vText2 := vText2 + vText[i]; FCommaSet := true; end else if vText[i] = '.' then begin vText2 := vText2 + ','; FCommaSet := true; end;
if FCommaSet then begin if (ord(vText[i]) > 48) and (ord(vText[i]) < 57) and (FWrittenDecNumbers < GetDecNumber) then begin vText2 := vText2 + vText[i]; inc(FWrittenDecNumbers); end; end; end;
if FWrittenDecNumbers < GetDecNumber then begin for I := FWrittenDecNumbers to GetDecNumber do vText2 := vText2 + '0'; end;
Text := vText2; end;
function TFloatEdit.GetDecNumber; begin result := FDecNumber; end;
procedure TFloatEdit.SetDecNumber(DecNumber: Integer); begin FDecNumber := DecNumber; end; |
Man beachte die Leerzeichen
Wenn ich compilieren wil, mosert der Compiler aber nun, dass es die Methode Exit in der Basiskomponente nicht geben würde. Aber das stimmt doch nicht, die OnExit-Methode ist doch in der TEdit definiert? Was läuft denn hier falsch?
Achja: Und Anmerkungen zum Code jeglicher Art sind natürlich erwünscht - zum Beispiel: Ist es ok, einfach so auf Text zuzugreifen oder sollte man lieber GetText nutzen?
|
|
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mi 24.11.10 19:16
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.
Schau doch einfach einmal in den Quelltext von TCustomEdit usw. 
|
|
|