Entwickler-Ecke
Grafische Benutzeroberflächen (VCL & FireMonkey) - Konstantenausdruck erwartet
Apo95 - Mo 14.10.13 21:02
Titel: Konstantenausdruck erwartet
Hallo,
ich komme bei dem folgenden Problem : Beim Übersetzen meckert er, dass ein Konstanenausdruck vonöten wäre, aber ich finde die Ursache nicht ...
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:
| cStore := ExpandEnvStr('%ProgramFiles%\EA und SUMIT.de GmbH in Zusammenarbeit mit GG Berlin\ApoPlus Apothekensystem 2010\ApoPlus 1.0\Apoplus DELPHI2009\Apo.exe'); cStore_LogFile := ExpandEnvStr('%Appdata%\EA\ApoPlus 2010\.Crash\EA_'+DateTimeToStr(cDate)+'.log'); cStore_AppData := ExpandEnvStr('%Appdata%\EA\ApoPlus 2010\.Crash');
if IsExeRunning('Apo.exe') then Application.MessageBox('Das Apothekensystem oder eines seiner Bestandteile läuft bereits.', '',MB_ICONINFORMATION);
ProgressBar1.Position :=Timer1.Interval;
Timer1.Enabled :=true; if ProgressBar1.Position =100 then SHELLEXECUTE (handle,'open',PChar(cStore),nil,nil,SW_SHOWNORMAL); if not FileExists(cStore) then begin Application.MessageBox('Die Datei Apo.exe konnte nicht gefunden werden. Möglicherweise wurde die Datei umbenannt, verschoben oder entfernt. '+ #13+#10+#13+#10+'Installieren Sie das Programm erneut, um Fehler zu beheben.','Datei nicht gefunden.',mb_ICONSTOP or mb_OK);
AMsgDialog := CreateMessageDialog('LOG-Datei wird erzeugt...', mtINFORMATION, [mbOK]) ; AProgressBar := TProgressBar.Create(AMsgDialog) ; ATimer := TTimer.Create(AMsgDialog) ; with AMsgDialog do try Tag := 5; Height := 150; with AProgressBar do begin Name := 'Progress'; Parent := AMsgDialog;
Max := AMsgDialog.Tag; Step := 1; Smooth := True; Top := 100; Left := 8; Width := AMsgDialog.ClientWidth - 16; end;
with ATimer do begin Interval := 1000; OnTimer:=DialogTimer; end;
case ShowModal of ID_CANCEL: if not DirectoryExists(cStore_AppData) then CreateDir(cStore_Appdata); sl := TStringList.Create; try sl.add(DateTimeToStr(cDate)); sl.add('DATEI NICHT GEFUNDEN IM VERZEICHNIS '+ (cStore)+'.'+ 'INSTALLIEREN SIE DAS PROGRAMM GGF. ERNEUT.---'); sl.saveToFile(cStore_LogFile); finally sl.Free;
end; finally ATimer.OnTimer := nil; Free;
Application.Terminate; end; end; end; end; end; |
Gruß,
Apo95
jaenicke - Mo 14.10.13 21:32
Wenn du deinen Quelltext ordentlich formatieren würdest, würdest du den Fehler auch sofort sehen... :roll:
Tipp:
Schau dir an wo dein case anfängt und wo es aufhört...
Apo95 - Mo 14.10.13 21:35
Das müsste Zeile 63 sein... das end schließt die Anweisung ab
jaenicke - Mo 14.10.13 21:39
Nein, das end gehört zu dem try..finally davor... das ist genau was ich mit der Quelltextformatierung meinte. Zudem hört das case in der Mitte plötzlich auf (fehlendes begin..end). Ordentlich formatiert sieht das so aus:
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:
| cStore := ExpandEnvStr ('%ProgramFiles%\EA und SUMIT.de GmbH in Zusammenarbeit mit GG Berlin\ApoPlus Apothekensystem 2010\ApoPlus 1.0\Apoplus DELPHI2009\Apo.exe'); cStore_LogFile := ExpandEnvStr('%Appdata%\EA\ApoPlus 2010\.Crash\EA_' + DateTimeToStr(cDate) + '.log'); cStore_AppData := ExpandEnvStr('%Appdata%\EA\ApoPlus 2010\.Crash');
if IsExeRunning('Apo.exe') then Application.MessageBox('Das Apothekensystem oder eines seiner Bestandteile läuft bereits.', '', MB_ICONINFORMATION);
ProgressBar1.Position := Timer1.Interval;
Timer1.Enabled := true; if ProgressBar1.Position = 100 then SHELLEXECUTE(handle, 'open', PChar(cStore), nil, nil, SW_SHOWNORMAL); if not FileExists(cStore) then begin Application.MessageBox ('Die Datei Apo.exe konnte nicht gefunden werden. Möglicherweise wurde die Datei umbenannt, verschoben oder entfernt. ' + #13 + #10 + #13 + #10 + 'Installieren Sie das Programm erneut, um Fehler zu beheben.', 'Datei nicht gefunden.', mb_ICONSTOP or mb_OK);
AMsgDialog := CreateMessageDialog('LOG-Datei wird erzeugt...', mtINFORMATION, [mbOK]); AProgressBar := TProgressBar.Create(AMsgDialog); ATimer := TTimer.Create(AMsgDialog);
with AMsgDialog do try Tag := 5; Height := 150;
with AProgressBar do begin Name := 'Progress'; Parent := AMsgDialog;
Max := AMsgDialog.Tag; Step := 1; Smooth := true; Top := 100; Left := 8; Width := AMsgDialog.ClientWidth - 16; end;
with ATimer do begin Interval := 1000; OnTimer := DialogTimer; end;
case ShowModal of ID_CANCEL: if not DirectoryExists(cStore_AppData) then CreateDir(cStore_AppData);
sl := TStringList.Create; try sl.add(DateTimeToStr(cDate)); sl.add('DATEI NICHT GEFUNDEN IM VERZEICHNIS ' + (cStore) + '.' + 'INSTALLIEREN SIE DAS PROGRAMM GGF. ERNEUT.---'); sl.saveToFile(cStore_LogFile); finally sl.Free; end; finally ATimer.OnTimer := nil; Free; Application.Terminate; end; end; end; end; end; |
Und nebenbei ist with an sich schon schrecklich, aber geschachtelt ist es echt so ca. das schlimmste was man machen kann.
Apo95 - Mo 14.10.13 22:12
Seit wann das denn? Ich danke erstmal sehr für die formatierten Text; ferner sehe ich die Ursache weiterhin nicht. :-(
jaenicke - Mo 14.10.13 22:35
Zu dem if in Zeile 54 gehört ohne ein begin..end nur noch Zeile 55. Alles danach gehört nicht mehr dazu und damit auch nicht mehr zu ID_CANCEL. Dementsprechend sucht Delphi nach dem nächsten Fall nach ID_CANCEL, aber s1, das der Compiler danach findet, ist keine Kosntante. Deshalb kann das nicht als Fallunterscheidung für case benutzt werden, deshalb der Fehler.
Wie schon geschrieben, dir fehlt ein begin..end. Wenn das if oder das ID_CANCEL weiter als bis Zeile 55 gehen sollen, musst du daraus auch einen begin..end Block machen.
Delete - Mo 14.10.13 23:31
Kleiner Tipp am Rande:
Wenn du bei komplexen Verschachtelungen wie den deinen selbst nicht mehr durchblickst, liegt das u.a. auch an fehlenden Kommentaren und fehlerhafter Vorgehensweise. Delphi erstellt das
end; doch in vielen Fällen selbständig. Warum nicht die IDE das machen lassen? Ich gehe auf jeden Fall immer, wo es möglich ist, so vor:
Ein Case mit Bedingung erzeugt sofort ein
End; darunter. Hinter dieses
End; schreibe ich dann sofort einen Kommentar, noch bevor ich die einzelnen Fälle eintrage:
Delphi-Quelltext
1: 2:
| Case MeinIndex of End; |
Genau so bei Try-Finally-Blöcken: Auch hier erzeugt Delphi beim Drücken der Enter-Taste hinter einem alleinstehenden
Try sofort ein
Finally mit darunterstehendem
End;. Und ich gehe sofort her und schreibe das
Try als Kommentar hinter das
End;:
Delphi-Quelltext
1: 2: 3: 4: 5:
| Try
Finally
End; |
Wenn du dich an diese oder eine ähnlich pragmatische Vorgehensweise hältst, kannst du in Zukunft derart dumme Fehler mit ziemlicher Sicherheit vermeiden.
Mit
with sollte man, wie Jaenicke bereits schrieb, schon deshalb nicht arbeiten, weil es durch Variablen, die in verschiedenen Adressräumen gleich Bezeichner tragen, zu schwer auffindbaren Laufzeitfehlern kommen kann und häufig auch kommt. Einfach grundsätzlich kein
with verwenden und du bist auf der sicheren Seite. Und natürlich kann ich Jaenicke auch bei der Forderung, dir eine übersichtliche Formatierung anzugewöhnen, nur beipflichten. Ich könnte solche unformatierten Quelltexte nach einigen Monaten kaum noch entziffern. Kunden, denen ich Quelltexte überlasse, würden mir dieselben um die Ohren hauen, wenn ich sie so abliefern würde, wie du das hier vorführst.
WasWeißDennIch - Di 15.10.13 08:14
Mal ganz ehrlich: wenn mein Code derartige Kommentare braucht, mache ich etwas falsch. Sobald der komplette Code einer Routine nicht mehr auf den Bildschirm passt, schaue ich, wo ich etwas in eigene Routinen auslagern kann.
Delete - Di 15.10.13 10:07
WasWeißDennIch hat folgendes geschrieben : |
Mal ganz ehrlich: wenn mein Code derartige Kommentare braucht, mache ich etwas falsch. Sobald der komplette Code einer Routine nicht mehr auf den Bildschirm passt, schaue ich, wo ich etwas in eigene Routinen auslagern kann. |
Da gebe ich dir natürlich recht. Doch erstens gibt es Anfänger, die mit einer solchen Vorgehensweise gut beraten sind, um den Überblick zu behalten. Zweitens fallen manchmal hochkomplexe Konstrukte an, z.B. wenn du ein dir unbekanntes Script parsen mußt und mit Pos, Copy, Delete & Konsorten arbeitest. Und drittens helfen die Kommentare beim Auffinden von Fehlern, die zwar meist, aber nicht nur Anfängern unterlaufen. Auch ist es manchmal sinnvoll, zum Erreichen eiens bestimmten Ziels notwendige Befehlsfolgen überhaupt erstmal zu überblicken, sie zuerst in einer Methode zu vereinen und dann zu schauen, was man auslagern kann, soll oder muß oder ob sich gar die Entwicklung einer speziellen Klasse rentiert.
Übrigens: Entwickler verfügen über ganz veschiedene Bildschirmgrößen. Meiner ist ziemlich groß, und ich hab sogar zwei davon :twisted:
WasWeißDennIch - Di 15.10.13 11:00
Ich hab nur einen, aber der hat 27 Zoll. Nichtsdestotrotz macht die Aufteilung eines Problems in Teilprobleme IMO den Code um Längen les- und wartbarer. Ein Beispiel:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| procedure HasseNichGesehen1; begin case Dings of 0: Bums := 0; 1: Bums := 42; 2: Bums := 100; 3: Bums := 200; 4: Bums := -1; 5: Bums := ULTIMATIVE_ZAHL_ZUR_ERLANGUNG_DER_WELTHERRSCHAFT; end; end; |
Was man z.B. daraus machen könnte:
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:
| function ValueByDings(Dings: integer): integer; inline; begin case Dings of 0: Result := 0; 1: Result := 42; 2: Result := 100; 3: Result := 200; 4: Result := -1; 5: Result := ULTIMATIVE_ZAHL_ZUR_ERLANGUNG_DER_WELTHERRSCHAFT; else Result := Dings; end; end;
procedure HasseNichGesehen2; begin Bums := ValueByDings(Dings); end; |
Sofern man ausdrucksvolle Namen für die Routinen bzw. Methoden verwendet, liest sich das später fast wie ein Buch, so dass man auch ohne Kommentare dem Code folgen kann.
Delete - Di 15.10.13 12:07
Im geschilderten Fall mache ich das auch nicht viel anders.
Es ging doch aber um komplexe Verschachtelung. Wenn ich eine lange Reihe von Begin ... End habe, die ineinander verschachtelt sind, ist es zwar äußerst hilfreich, stets korrekte Einrückungen zu machen, doch muß ich in diesem Fall immer erst das Begin anschauen, um zu wissen, welches sein End ist. Habe ich das End entsprechend kommentiert, genügt ein Blick. Ich möchte mich jetzt aber nicht mit dir darüber streiten, wo Kommentare angebrachter sind und wo weniger. Für Anfänger ist es grundsätzlich ratsam, erstmal so viel wie möglich zu kommentieren. Mir hatte das damals sehr geholfen. Später hat man dann das Lesen von Code besser drauf und kann einige Kommentare weglassen, wenn der Code gewissermaßen selbsterklärend ist. Ich kommentiere jedoch, wie bereits erwähnt, nicht immer nur für mich selbst, sondern muß auch für andere kommentieren, denen ich Quellcode überlasse. Keine Ahnung, wie häufig du an Fremdcode arbeitest, aber ich ärgere mich regelmäßig über lückenhaft kommentierten Fremdcode, meist im Zusammenhang mit kryptischen Bezeichnern, die aus irgendwelchen Abkürzungen bestehen. Nach über 10 Jahren Delphi-Entwicklung und davor etlichen Jahren Turbo Pascal bin ich nun wahrlich kein Frischling mehr, dem Pacal-Code wie chinesisch vorkommt. :wink:
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!