![]() |
Menüs zur Laufzeit
Hallo, liebe Delphianer!
Weil ich in die Tiefen der Delphi-Programmierung einsteigen will und als fortgeschrittener nun auch die Interna besser verstehen will, bin ich dabei, Menüs zur Laufzeit zu erstellen und zur Laufzeit uneingeschränkt darauf zuzugreifen. Außerdem halte ich diese Vorgehensweise bei der Erstellung mehrsprachiger Anwendungen für unabdingbar, da ich dann die Captions der Menüeinträge leicht an die gewünschte Sprache anpassen kann. Leider funktionirt der Code noch nicht. Deshlb bitte ich um Eure Hilfe und zeige Euch an dieser Stelle meinen Quellcode: {----------------------------------------------------------------------------- Unit Name: main Author: Projektmaster Purpose: Building menus at runtime History: -----------------------------------------------------------------------------} unit main; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Menus, StdCtrls; type TForm1 = class(TForm) LBox: TListBox; btnShow: TButton; btnEnde: TButton; procedure FormCreate(Sender: TObject); procedure Beenden1Click(Sender: TObject); procedure btnShowClick(Sender: TObject); procedure btnEndeClick(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } Menu: TMainMenu; MenuItems: array of TMenuItem; SubItems: array of TMenuItem; Datei, Bearbeiten, Fenster, Hilfe: TMenuItem; Neu, Oeffnen, N1, Beenden: TMenuItem; end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin //Hier will ich zur Laufzeit mein Menü aufbauen. //Grund: // Das soll später mehrsprachig werden // Da werden dann den Captions ResourceStrings // zugewiesen, die von der gewünschten Sprache // abhängen. Menu := TMainMenu.Create(self); Datei := TMenuItem.Create(Self); Datei.Caption := 'Datei'; Bearbeiten := TMenuItem.Create(Self); Bearbeiten.Caption := 'Bearbeiten'; Fenster := TMenuItem.Create(Self); Fenster.Caption := 'Fenster'; Hilfe := TMenuItem.Create(Self); Hilfe.Caption := 'Hilfe'; Neu := TMenuItem.Create(self); Neu.Caption := 'Neues Projekt öffnen...'; N1 := TMenuItem.Create(self); N1.Caption := '-'; Oeffnen := TMenuItem.Create(self); Beenden := TMenuItem.Create(self); Beenden.Caption := 'Programm &Verlassen'; Beenden.OnClick := Beenden1Click; Oeffnen.Caption := 'Existierendes Projekt öffnen...'; Menu.Items.Add(Datei); Menu.Items.Items[0].Insert(0,Neu); // Sobald ich Untermenüs einfügen will, Wird Exception // EListError ausgelöst // Meldung: Listenindex überschreiete das Maximum (1) // Menu.Items.Items[1].Add(Oeffnen); // Menu.Items.Items[2].Add(N1); // Menu.Items.Items[3].Add(Beenden); Menu.Items.Add(Bearbeiten); Menu.Items.Add(Fenster); Menu.Items.Add(Hilfe); end; procedure TForm1.Beenden1Click(Sender: TObject); begin Close; end; procedure TForm1.btnShowClick(Sender: TObject); var i,j,k: Integer; begin if Menu <> nil then if Menu.Items.Count > 0 then for i:=0 to Menu.Items.Count-1 do LBox.Items.Add(Menu.Items[i].Caption); //Warum wird hier die Exception EListError ausgelöst, Meldung: //Listenindex überschreiete das Maximim (4) //wenn ich diesen Code ausführe ? { Ich will hier die Untermenüs anzeigen, weil ich lernen will, wie sich das Menü, das ich so wunderbar mit dem Designer er- stellen läßt, denn nun intern aufbaut. j := 0; // wenn ich das gleiche mit for... mache, gleiches Erebnis. while j <= Menu.Items[i].Count-1 do begin LBox.Items.Add(Menu.Items[i].Items[j].Caption); inc(j); end; } end; procedure TForm1.btnEndeClick(Sender: TObject); begin Close; end; end. Warum werden die in den Kommentaren angegebenen Exceptions ausgelöst? Wie kann ich mein Problem lösen? DelphiSourcer |
Re: Menüs zur Laufzeit
Du musst wissen, dass nach einer FOR Schleife, die LoopVariable ein undefiniertes Wert hat. Ja, so ist es.
So klappt es :-D
Delphi-Quellcode:
for i:=0 to Menu.Items.Count-1 do
for j:=0 to Menu.Items[i].Count-1 do LBox.Items.Add(Menu.Items[i].Items[j].Caption); |
Re: Menüs zur Laufzeit
[ot]
Herzlich willkommen in der DP! :-D Benutz bitte die den Code-Tag, damit der Quellcode von dir leserlicher wird :!: [/ot] |
Re: Menüs zur Laufzeit
Hallo DelphiSourcer.
Zunächst mal solltest Du die Delphi-Code-Tags verwenden, dann ist Dein Code lesbar (geht auch noch nachträglich mit "Edit"). Zitat:
Zeile 1 erzeugt das Objekt
Delphi-Quellcode:
Das ist das Menü "Datei". Dieses hat noch keine Untermenüpunkte.
Menu.Items[0]
Der Aufruf in Zeile 2 ginge auch kürzer:
Delphi-Quellcode:
Damit existiert das Objekt Menu.Items[0].Items[0] (nämlich "Datei->Neu").
Menu.Items[0].Insert(0, Neu) // wg. Default-Property
// alternativ: Menu.Items[0].Add(Neu) Das Objekt Menu.Items[1] existiert aber noch nicht, deshalb wird bei Deinem Versuch, mit Menu.Items[1].Add(Oeffnen) auf das Objekt zuzugreifen, eine Exception ausgelöst. Der Abschnitt müsste also (wie gesagt, wenn ich es richtig sehe) so aussehen:
Delphi-Quellcode:
Den zweiten problematischen Abschnitt habe ich mir nicht angesehen, aber vielleicht hat sich das ja auch erledigt- sofern mein Vorschlag funktioniert.
Menu.Items.Add(Datei);
Menu.Items[0].Add(Neu); Menu.Items[0].Add(Oeffnen); /etc. HTH Urs |
Re: Menüs zur Laufzeit
hallo DelphiSourcer,
für mehrsprachige Menues müßtest Du aber weder die MenuItems zur Laufzeit erzeugen noch ResourceStrings verwenden. -> Beim Umschalten der Sprache kannst du auch einfach nur die Captions ändern -> Den Sinn von ResourceStrings habe ich noch nie verstanden. Wir verwenden Ascii-Dateien mit den Spracheinträgen, die an die Tags der Komponenten gekoppelt sind. Der riesige Vorteil ist der, daß man Sprachdateien einfach mit einem Texteditor ändern kann, ohne das Projekt neu kompilieren zu müssen. Roderich |
Re: Menüs zur Laufzeit
Hallo, allerseits!
Danke wie verrückt für Eure schnelle Hilfe. sniper_w schreibt, dass es so hier funktioniert: [ot] for i:=0 to Menu.Items.Count-1 do for j:=0 to Menu.Items[i].Count-1 do LBox.Items.Add(Menu.Items[i].Items[j].Caption); [/ot] Perfekt, funktioniert auch, Danke mr47 schreibt: [ot] Herzlich willkommen in der DP! Very Happy Benutz bitte die den Code-Tag, damit der Quellcode von dir leserlicher wird Exclamation [/ot] Ok, werde ich beherzigen. Habe bei obigem Quelltext in dieser Antwort das Tag gleich mal verwendet, um zu sehen, ob es wie gewünscht funktioniert. urs.liska schreibt: [ot] Damit existiert das Objekt Menu.Items[0].Items[0] (nämlich "Datei->Neu"). Das Objekt Menu.Items[1] existiert aber noch nicht, deshalb wird bei Deinem Versuch, mit Menu.Items[1].Add(Oeffnen) auf das Objekt zuzugreifen, eine Exception ausgelöst. Der Abschnitt müsste also (wie gesagt, wenn ich es richtig sehe) so aussehen: Quellcode: markieren Menu.Items.Add(Datei); Menu.Items[0].Add(Neu); Menu.Items[0].Add(Oeffnen); /etc. [/ot] Du hast recht, das war der Grund, warum ich keine weiteren Menüpunkte einfügen konnte. Zu dem anderen Problem hat mir sniper_w bereits gehlfen. Sein Tipp ist hier der richtige. roderich schreibt: [ot] für mehrsprachige Menues müßtest Du aber weder die MenuItems zur Laufzeit erzeugen noch ResourceStrings verwenden. -> Beim Umschalten der Sprache kannst du auch einfach nur die Captions ändern [/ot] Gut und schön, aber wie ordne ich dann den Spracheintrag der richtigen Caption zu? Von Hand ist es klar, aber um die Captions spracabhängig aus einer Datei zu lesen, muss ich zur Laufzeit auf die Menüeinträge zugreifen können. Und durch meine Laufzeitmenüs in meinem Programm, weiß ich nun, wie ich die Captions dann erreiche. [ot] -> Den Sinn von ResourceStrings habe ich noch nie verstanden. Wir verwenden Ascii-Dateien mit den Spracheinträgen, die an die Tags der Komponenten gekoppelt sind. Der riesige Vorteil ist der, daß man Sprachdateien einfach mit einem Texteditor ändern kann, ohne das Projekt neu kompilieren zu müssen. [/ot] [ot] -> Den Sinn von ResourceStrings.... [/ot] Ich nehme an, das man damit verschiedene Stringkonstanten nach folgendem Muster anlegt: [ot] ResourceString sDatei = 'Datei'; sFile = 'File'; ............ sBearbeiten = 'Bearbeiten'; sEdit = 'Edit'; ............ type TLanguage = (english, german, french, .... ); begin case Language of english: Menu.Items[0].Caption := sFile; german: Menu.Items[0].Caption := sDatei; french: ...; end; end; [/ot] Sprachdatei verwenden, ist natürlich auch ein Vorschlag. Werde das testen. Ich danke Euch noch einmal allen für Eure unkomplizierte schnelle Hilfe und grüße Euch DelphiSourcer |
Re: Menüs zur Laufzeit
Ich sehe gerade, dass die Tags zwar zu sehen sind, aber der eingeklammerte Text nicht so eingerückt wird, wie erwartet. Ich schlage vor, wir eröffnen ein neues Thema zu diesem Punkt. Werde gleich mal die Frage posten.
DelphiSourcer |
Re: Menüs zur Laufzeit
Wenn man Resourcestrings sinnvoll nutzen möchte, kann man auch gleich die "Sprachfunktion" der selbigen nutzen. Erstellt man eine .rc-Datei von Hand, kann man in etwa so vorgehen:
Code:
So bleibt es dann Windows überlassen, welche Sprache es verwendet, der Nutzer kann es Zentral in der Systemsteuerung ändern.
STRINGTABLE
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL { 65264, "Copying..." 65265, "Optimizing..." } LANGUAGE LANG_GERMAN, SUBLANG_GERMAN { 65264, "Kopiere..." 65265, "Optimiere..." } |
Re: Menüs zur Laufzeit
nur kurz zu den Tags (mehr schaue ich später an):
[ot] war nur als Hinweis für OffTopic gedacht Quelltext umschließt man mit [ delphi ] und [ / delphi] (ohne die Leerzeichen) Urs |
DP-Maintenance
Dieses Thema wurde von "Sharky" von "Datenbanken" nach "VCL-Komponenten und Controls" verschoben.
Menüs - Datenbanksparte? Bitte etwas auf die Spartenbeschreibungen achten. Danke. |
Re: Menüs zur Laufzeit
Zitat:
In einer Ressourcendatei stehen alle strings, so wie in Deinem Bsp. nach "ResourceString" Das eigentliche Programm weiß gar nichts von verschiedenen Sprachversionen, sondern Du schreibst einfach:
Delphi-Quellcode:
Das ist genau der Punkt daran, dass im eigentlichen Quelltext nicht auf verschiedene SPrachen Rücksicht genommen werden muss.
Menu.Items[0].Caption := sDatei;
Für verschiedene Sprachversionen werden einfach verschiedene Versionen der Ressourcendatei hergestellt. Da steht dann z.B.
Delphi-Quellcode:
drin. Wie man damit genau umgeht, findest Du in der OH unter "resourcestring" bzw. unter "Internationalisierung" und "Lokalisierung" von Anwendungen. Auf jeden Fall sollten die ResourceStrings in eine eigene Unit.
ResourceString
sDatei = 'File' Die Variante von scp kannte ich nicht, sieht aber sehr interessant aus. Urs |
Re: Menüs zur Laufzeit
Moin,
ich würde mal einen Blick auf GNU GetText werfen. Da brauchst Du, von ein paar Ausnahmen abgesehen, gar keine Captions per Hand zuzuweisen. Da gibt's, unter Anderem, zwei Funktionen :
Delphi-Quellcode:
und
TranslateComponent(Self);
Delphi-Quellcode:
welche automatisch die Captions, etc... der meissten Kompos anpassen (auch bei Laufzeit).
ReTranslateComponent(Self);
Alle Übersetzungen sind in Textdateien ausgelagert; für eine neue Sprache muss also nur eine Textdatei übersetzt werden, das Programm bleibt unverändert. Ich find's ganz praktisch und hatte bis jetzt noch kleine Probleme damit. Tschüss, Lutz |
Re: Menüs zur Laufzeit
Hai DelphiSourcer,
korriegiere doch bitte in deinen Postings die Tags. (Ich habe dazu nämlich keine Lust :stupid: ) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:04 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz