Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Delphi(Lazarus)-Problem! Delete Anweisung


Delete - Di 05.11.13 19:22
Titel: Delphi(Lazarus)-Problem! Delete Anweisung
Moin,
ich arbeite gerade an einem Programm und weiß nicht, wo im folgenden Code der Fehler ist.
Es wäre nett, wenn ihr mir helfen könntet. Das Problem scheint die delete-Anweisung zu sein.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
procedure TForm1.Edit1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
var taste,s1:string;
begin
  taste:=edit1.text;
  s1:=taste;
  if key=13 then checkclick(sender);
  if key=10 then neuclick(sender);
  if key>32   then
  Delete(s1,length(s1),1);
  //and (key<47) or (key>57)) then
end;


ich weiß, dass S1 unnötig ist, da ich bereits taste habe. Den Kommentar könnt ihr auch ignorieren. Lazarus markiert:

Delphi-Quelltext
1:
  Delete(s1,length(s1),1);                    

als falsch mit der Fehlermeldung 'Illegal Expression'. S1 ist der Inhalt des Eingabefeldes Edit1. Davon soll das letzte Zeichen gelöscht werden. Ich möchte am Ende deshalb:
edit1.text:=s1 oder taste.
Danke im Voraus für eure Hilfe,
euer Weyoun.

Moderiert von user profile iconMartok: Delphi-Tags hinzugefügt


Tranx - Di 05.11.13 19:32

Also, ich habe das mit Lazarus mal genau so (s. u.) getestet. Das funtioniert. Weiß nicht, wo Du da wirklich einen Fehler hast, vielleicht bei neuclick oder checkclick?

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
procedure TForm1.Edit1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
var taste,s1:string;
begin
  taste:=edit1.text;
  s1:=taste;
  //if key=13 then checkclick(sender);
  //if key=10 then neuclick(sender);
  if key>32   then
  Delete(s1,length(s1),1);
  //and (key<47) or (key>57)) then
end;


Delete - Di 05.11.13 19:44

Danke, für deine Antwort. Ich habe keine Ahnung warum, aber es geht immer noch nicht :( . Ich habe deinen Code kopiert und es versucht. Es klappt einfach nicht. Ich habe auch vor und hinter delete simple Anweisungen gesetzt, um herauszufinden, ob es wirklich an delete liegt. Und das tut es laut Lazarus.
Hier der ausgetestete Code:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
    procedure TForm1.Edit1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
    var taste,s1:string;
    begin
    taste:=edit1.text;
    s1:=taste;
    //if key=13 then checkclick(sender);
    //if key=10 then neuclick(sender);
    if key>32   then  begin
    label1.caption:='2';
    Delete(s1,length(s1),1);
    label1.caption:='1';
    end;
    label1.caption:='23';
    //and (key<47) or (key>57)) then

    end;

Hast du eine Idee, woran es liegen könnte?


@Martok: Danke, für die Tags :). Nach meinem ersten Beitrag dachte ich, Code würde automatisch erkannt. Jetzt werde ich aber immer Tags setzen.

Moderiert von user profile iconMartok: Delphi-Tags hinzugefügt


WasWeißDennIch - Di 05.11.13 20:39

Wie ist es mit System.Delete? Möglicherweise hast Du eine Unit eingebunden, die auch über eine Delete-Prozedur oder -Funktion verfügt, aber eine andere Parameterliste hat.


Tranx - Mi 06.11.13 07:44

Das wird es wohl sein. Denn es gibt mehrere Objekte, die eine Delete.Prozedur besitzen. Allerdings müsste dann diese Deleteprozedur in TForm1 selber definiert sein. Ansonsten würde Lazarus ja mitteilen, dass er die Delete-Prozedur nicht kennt. Allerdings hoffe ich, dass Delete auch in der System-Unit (wie bei Delphi) definiert ist, und nicht woanders.


WasWeißDennIch - Mi 06.11.13 10:29

user profile iconTranx hat folgendes geschrieben Zum zitierten Posting springen:
Allerdings müsste dann diese Deleteprozedur in TForm1 selber definiert sein.

Nicht unbedingt, es genügt, wenn man eine Unit einbindet, die auch eine Delete-Routine enthält.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
unit SomeUnit;

interface
  
procedure Delete(SomeParam: integer);

implementation

procedure Delete(SomeParam: integer);
begin
  (* Code *)
end;


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
unit MainUnit;

...

implementation

uses SomeUnit;

...

Delete(...); (* Hier denkt der Compiler dann, die Routine aus SomeUnit ist gemeint *)


Man kann hier aber für Eindeutigkeit sorgen, indem man die Routine voll qualifiziert, d.h. den Unit-Namen davorschreibt. So etwas kann z.B. auch passieren, wenn man mit TBitmap arbeitet, das gibt es einmal in Graphics und einmal in Windows.


jaenicke - Mi 06.11.13 10:30

Trotzdem muss es so etwas sein. Lazarus zeigt aber wie Delphi beim Drüberhalten der Maus an woher die Prozedur kommt (leider mit starker Verzögerung) und springt zur Deklaration mit Strg + Klick. Man kann also leicht sehen woher die Prozedur kommt und wie sie dort deklariert ist.

user profile iconTranx hat folgendes geschrieben Zum zitierten Posting springen:
Allerdings hoffe ich, dass Delete auch in der System-Unit (wie bei Delphi) definiert ist, und nicht woanders.
systemh.inc glaube ich, hab hier kein Lazarus.


Martok - Mi 06.11.13 14:30

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Lazarus zeigt aber wie Delphi beim Drüberhalten der Maus an woher die Prozedur kommt (leider mit starker Verzögerung)
Einstellungen->Editor->Vervollständigung/Hinweise->Verzögerung für... ;-)

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconTranx hat folgendes geschrieben Zum zitierten Posting springen:
Allerdings hoffe ich, dass Delete auch in der System-Unit (wie bei Delphi) definiert ist, und nicht woanders.
systemh.inc glaube ich, hab hier kein Lazarus.
Stimmt, rtl/inc/systemh.inc, Unit ist also System.pp, braucht man nix selbst schreiben.

Was vielleicht mal noch interessant wäre: an welchem Zeichen kommt der Fehler? Ist es wirklich Delete oder vielleicht Length? Das klingt mir ja schon nach einem Kandidaten für einen Variablennamen, und eine (nicht-prozedur-)Variable aufrufen wäre tatsächlich eine Illegal Expression...


Tranx - Mi 06.11.13 15:49

Ich würde wie folgt vorgehen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
    
var
  s1, taste : string;
  lStr : integer;
begin
    taste:=edit1.text;
    s1:=taste;
    //if key=13 then checkclick(sender);
    //if key=10 then neuclick(sender);
    if key>32   then  begin
      label1.caption:='2';
      lStr := Length(s1);  // Deleteaufruf trennen. Wenn Fehler mit Length, dann hier
      Delete(s1,lStr,1);  
      label1.caption:='1';
    end;
    label1.caption:='23';
    //and (key<47) or (key>57)) then


WasWeißDennIch - Mi 06.11.13 16:16

Oder ohne Delete:

Delphi-Quelltext
1:
s1 := Copy(s1, 1, Length(s1) - 1);                    


Delete - Mo 11.11.13 19:36

Moin.
Ich war so blöd :)
Ich hatte einen Button delete genannt. Lazarus ist also dadurch durcheinander gekommen.
Trotzdem danke, für eure Hilfe.


baumina - Di 12.11.13 08:25

Um so etwas zu vermeiden, ist es sinnvoll eine einheitliche Namensgebung zu verwenden. z.B. heißen alle Buttons btn_[irgendwas] (in deinem Beispiel dann btn_delete) Formulare heißen frm_[irgendwas], Editfelder ed_[irgendwas], Labels lb_[irgendwas] usw. Damit vermeidest du Namenskonflikte und weißt selber sofort welche Objekte sich hinter den Variablennamen verstecken.


jaenicke - Di 12.11.13 11:42

Und am besten ohne Unterstrich, z.B. btnDelete. (Denn der Unterstrich ist in Delphi höchst unüblich um nicht zu sagen verpönt, abgesehen von Windows Messages oder ähnlichen aus fremden Definitionen übernommenen Bezeichnern. Denn in Delphi wird in der Regel Camel Case benutzt, das reicht als Trennung ja.)

Das nennt sich übrigens ungarische Notation.

Es hat auch den Vorteil, dass du nur z.B. btn schreiben und Strg + Leertaste drücken musst um alle Buttons des Formulars zu sehen. So findet mal die sehr schnell auch ohne den konkreten Namen 100%ig zu wissen.


baumina - Di 12.11.13 12:12

Gibt es dafür eigentlich irgendwo eine Liste im Internet wie man was in Delphi am Besten benamst, irgendetwas einheitliches?


jaenicke - Di 12.11.13 12:32

Es gibt den Object Pascal Style Guide:
http://edn.embarcadero.com/article/10280 hat folgendes geschrieben:
Except in header translations, do not use underscores to separate words. Class names should be nouns or noun phrases. Interface or class names depend on the salient purpose of the interface.

GOOD type names:
AddressForm, ArrayIndexOutOfBoundsException

BAD type names:
ManageLayout // verb phrase
delphi_is_new_to_me // underscores


baumina - Di 12.11.13 12:49

Das ist gut zu wissen, danke dir. Mein (damaliger) Chef hat vor 10 Jahren mal innerhalb unserer Firma bestimmt, wie wir bestimmte Objektvariablen benennen sollten. Nach meinem Jobwechsel habe ich das einfach beibehalten (dummerweise mit Unterstrich). Das werde ich mir nun abgewöhnen (als alleiniger Programmierer unserer Firma muss ich das mit niemanden absprechen), aber um mir gleich etwas vernünftiges anzugewöhnen würde mich eben interessieren, ob sich da mal paar Delphi-Programmierer zusammengesetzt haben und Namenskonventionen entworfen haben wie dann z.B. Formulare, Editfelder, Labels, Comboboxen, Checkboxen etc. lauten sollten.

Edit: Nicht dass ich bei erneutem Jobwechsel von allen anderen ausgelacht werde, warum ich so seltsame Namen meinem Variablen gebe. :-D


WasWeißDennIch - Di 12.11.13 14:44

Ich glaube nicht, dass es da eine Art Standard gibt. Ich persönlich habe mir einen 3-stelligen Präfix angewöhnt: lbl für TLabel, frm für TForm, edt für TEdit usw. Übrigens bietet IIRC das cnPack die Möglichkeit, automatisch Präfixe zu vergeben, man muss die dann nur einmalig festlegen. Kann aber auch sein, dass ich das mit einem anderen IDE-Enhancement verwechsle.


jaenicke - Di 12.11.13 15:05

Da gibt es keinen Standard. Standard ist nur, dass in Delphi keine ungarische Notation für normale Variablen verwendet werden sollte. Für Komponenten ist es umstritten, ich selbst befürworte es, da es mehrere Vorteile, aber keine echten Nachteile gibt.


Tranx - Di 12.11.13 17:36

Ich habe mir angewöhnt, für Variablen einen 2-3-stelligen Präfix zu wählen.

es sind 2-3 Kleinbuchstaben vor dem eigentlichen Namen, der mit einem Großbuchstaben beginnt.

z.B.

poTabelle, giIndex, lasText

der erste Buchstabe bestimmt die Stelle der Definition (p für Parameter, g für global, l für lokal ...)

der zweite Buchstabe ist entweder ein a für Array oder z.B. o für Objekt, i für integer ...

Für mich ergibt sich der Vorteil, dass ich im Codetext sofort sehe, welche Variable ich nutze (lokal, global, in Klassen, Records, ...) und um welchen Typ es sich handelt. Und ich kann Namen wie Text, Name, Color ..., die ja oft Eigenschaftsnamen von Objekten sind, als Variablennamen verwenden, ohne dass es Konflikte geben kann, denn es gibt ja keine Eigenschaftsnamen psText, lsText oder gsName .....

Und eine Änderung des Namens einer Variablen ist viel sicherer.

Indices wie i,n,... und von Delphi benutzte Namen wie Sender, Key, Shift, HWnd belasse ich wie gehabt.

Sicher, die Namensbezeichnung klingt irgendwie komisch, aber ich habe festgestellt, dass ich wirklich schneller Probleme erkennen kann und nicht Gefahr laufe, was ganzanderes zu tun, als ich eigentlich wollte. Außerdem, da ich Prozeduren, Funktionen und Properties grundsätzlich am Anfang groß schreibe, sehe ich auch gleich sofort, was eine Variable udn was eine Prozedur/Funktion/Property ist.

Ist nur eine Idee. Kann ja jeder anders handhaben.


baumina - Di 12.11.13 17:44

@Tranx : auch interessant aber ob es nun ein Button oder ein Editfeld ist, erkennst du mit deiner Methode nicht, oder?


Tranx - Di 12.11.13 18:26

Ich benutze diese Art nur für Variable und nicht visuelle Objekte. Ansonsten muss ich noch die Bezeichner umstellen (habe noch die Präfixe mit Unterstrich (t_ für TTable, bu_ für Button, l_ für Label ....) (so wie oben beschrieben, 3-buchstabiges Präfix). Da das aber sehr viel aufwändiger ist, habe ich das noch hinten angestellt.

Mir ging es priomär um die Unterscheidung zwischen Variablen und Prozeduren und Eigenschaften von Objekten.


jaenicke - Di 12.11.13 22:13

user profile iconTranx hat folgendes geschrieben Zum zitierten Posting springen:
poTabelle, giIndex, lasText

der erste Buchstabe bestimmt die Stelle der Definition (p für Parameter, g für global, l für lokal ...)
Dafür wird in Delphi eine andere Konvention genutzt.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
type
  ITest = interface // Interface --> großes I vorne
  end;

  TTest = class(TInterfacedObject, ITest) // Klasse --> großes T vorne (EDIT: gilt für alle Typen)
  private
    FTest: Integer; // privates Feld --> großes F vorne
    procedure SetTest(const AValue: Integer); // Parameter --> großes A vorne
  public
    property Test: Integer read FTest write SetTest;
  end;
Die Typen einfacher Variablen per ungarischer Notation zu versehen ist in Delphi absolut unüblich, weil es ohnehin eine typisierte Sprache ist. Bei guten Variablennamen sieht man den Typ auch schon am Namen. Beispiel:
User --> wird ein Objekt sein
UserName --> wird eine Zeichenkette sein
UserNumber --> wird eine Zahl sein

Zudem zeugt es eher von einem strukturellen Problem, wenn man so viele Variablen an einer Stelle verfügbar hat, dass man die durch solche Typ-Präfixe weiter kategorisieren muss.

Bei visuellen Komponenten hat es wie schon erwähnt den Vorteil, dass man bestimmte Komponenten auf der Oberfläche schneller findet ohne den Namen nachschauen zu müssen. Visuelle Komponenten hat man aber normalerweise eher deutlich mehr als Variablen an einer Stelle.


WasWeißDennIch - Mi 13.11.13 09:36

Das T als Präfix steht aber nicht (nur) für Klasse, sondern allgemein für Typdefinition.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
type
  TDingensStatus = (dsDings, dsBums);
  TDingensOptions = set of (doEins, doZwei, doDrei);
  TDingenswert = 1..42;
  TDingens = class
  end;


jaenicke - Do 14.11.13 10:43

Da hast du natürlich Recht, ich wollte da nur das Beispiel kommentieren, aber ich hab den Hinweis auch noch ergänzt.