Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Menüs zur Laufzeit (https://www.delphipraxis.net/39744-menues-zur-laufzeit.html)

DelphiSourcer 7. Feb 2005 12:51


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

sniper_w 7. Feb 2005 13:04

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);

mr47 7. Feb 2005 13:14

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]

urs.liska 7. Feb 2005 13:36

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:

Zitat von DelphiSourcer
Delphi-Quellcode:
Menu.Items.Add(Datei); //Zeile 1
Menu.Items.Items[0].Insert(0,Neu); //Zeile 2 
// 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);

Wenn ich das richtig verstehe (ich habe das so noch nie gemacht), sieht die Sache so aus:
Zeile 1 erzeugt das Objekt
Delphi-Quellcode:
Menu.Items[0]
Das ist das Menü "Datei". Dieses hat noch keine Untermenüpunkte.
Der Aufruf in Zeile 2 ginge auch kürzer:
Delphi-Quellcode:
Menu.Items[0].Insert(0, Neu) // wg. Default-Property
// alternativ:
Menu.Items[0].Add(Neu)
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:
Delphi-Quellcode:
Menu.Items.Add(Datei);
Menu.Items[0].Add(Neu);
Menu.Items[0].Add(Oeffnen); /etc.
Den zweiten problematischen Abschnitt habe ich mir nicht angesehen, aber vielleicht hat sich das ja auch erledigt- sofern mein Vorschlag funktioniert.

HTH
Urs

roderich 7. Feb 2005 13:54

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

DelphiSourcer 7. Feb 2005 14:52

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

DelphiSourcer 7. Feb 2005 14:54

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

scp 7. Feb 2005 15:18

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:
STRINGTABLE
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
{
65264, "Copying..."
65265, "Optimizing..."
}
LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
{
65264, "Kopiere..."
65265, "Optimiere..."
}
So bleibt es dann Windows überlassen, welche Sprache es verwendet, der Nutzer kann es Zentral in der Systemsteuerung ändern.

urs.liska 7. Feb 2005 15:37

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 7. Feb 2005 15:40

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.

urs.liska 7. Feb 2005 16:27

Re: Menüs zur Laufzeit
 
Zitat:

Zitat von DelphiSourcer
Ich nehme an, das man damit verschiedene Stringkonstanten nach folgendem Muster anlegt:

Delphi-Quellcode:
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;

Nein, das geht anders (und noch wesentlich besser).
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:
Menu.Items[0].Caption := sDatei;
Das ist genau der Punkt daran, dass im eigentlichen Quelltext nicht auf verschiedene SPrachen Rücksicht genommen werden muss.
Für verschiedene Sprachversionen werden einfach verschiedene Versionen der Ressourcendatei hergestellt. Da steht dann z.B.
Delphi-Quellcode:
ResourceString
  sDatei = 'File'
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.

Die Variante von scp kannte ich nicht, sieht aber sehr interessant aus.

Urs

lume96 7. Feb 2005 16:57

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:
TranslateComponent(Self);
und
Delphi-Quellcode:
ReTranslateComponent(Self);
welche automatisch die Captions, etc... der meissten Kompos anpassen (auch bei Laufzeit).

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

Sharky 7. Feb 2005 19:59

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 14:10 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