Autor Beitrag
Kay E.
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 118



BeitragVerfasst: 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:

ausblenden volle Höhe 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:
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
    { Private declarations }
    vComma:boolean;
    vDecAfterComma:byte;
  protected
    { Protected declarations }
    procedure KeyPress(Sender: TObject; Var Key: Char); override;
  public
    { Public declarations }
    Constructor Create(Owner:TComponent); override;
  published
    { Published declarations }
//    property Text default '1,00';
    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;
//  Text:='1,00';
  vComma:=false;
  vDecAfterComma:=0;
end;


procedure TNumEdit.KeyPress(Sender: TObject; var Key: Char);
begin
//Logic missing
  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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 648
Erhaltene Danke: 85

WIN 2000, WIN XP
D5 Prof
BeitragVerfasst: Mi 24.11.10 05:11 
Hallo,
habe es mal versucht. TEdit hat Parameter für Keypress nur

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 24.11.10 06:48 
user profile iconKay E. hat folgendes geschrieben Zum zitierten Posting springen:
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.

user profile iconKay E. hat folgendes geschrieben Zum zitierten Posting springen:
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.

user profile iconKay E. hat folgendes geschrieben Zum zitierten Posting springen:
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. Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 118



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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. Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 118



BeitragVerfasst: 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.

ausblenden volle Höhe 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:
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
    { Private declarations }
    FDecNumber: Integer;
    FWrittenDecNumbers: Integer;
    FCommaSet: Boolean;
    procedure SetDecNumber(DecNumber: Integer);
    function GetDecNumber: Integer;
  protected
    { Protected declarations }
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    procedure Exit; override;
  published
    { Published declarations }
    property DecNumbers: Integer read GetDecNumber write SetDecNumber default 2;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('OwnComponents', [TFloatEdit]);
end;

{ TFloatEdit }

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]) > 48and (ord(vText[i]) < 57then
      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]) > 48and (ord(vText[i]) < 57and (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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 24.11.10 19:16 
user profile iconKay E. hat folgendes geschrieben Zum zitierten Posting springen:
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. :idea:

Schau doch einfach einmal in den Quelltext von TCustomEdit usw. ;-)