Entwickler-Ecke
Sonstiges (Delphi) - Menü aus INI ??
matze - Mi 07.08.02 09:28
Titel: Menü aus INI ??
Hallo !!!
Ich habe ein Programm entwickelt, das eine Linkliste besitzt. Wenn ich jetzt aber dieser Linkliste eine Link hinzufügt, muss ich den Leuten jedesmal eine neue Version meines Proggis geben, damit die auch die aktuellen Links haben !!! Das ist umständlich !!!
Ich habe mir daher gedacht, die Links in eine INI auszulagern, die dann nurnoch übers Internet geupdatet wird.
Aber wie mach ich sowas ??
wenn meine INI z.B. so ausschaut:
Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| [1] name = Web.de url = www.web.de
[2] name = Auq.de url = www.auq.de |
Wie kann ich aus einer InI die so ausschaut ein Menü erzeugen, das mir bei klick auf einen Menüeintrag die URL in dem Browserfenter läd oder per ShellExecute in dem Standardbrowser des systems ausgibt ???
Ich denke mal, dass sich das mit einer for- schleife machen liese, aber ich weiss nicht, wie ich die anzahl der sections rausbekomme und wie ich dann bei klick die URL aufrufe !!!
wwerner - Mi 07.08.02 09:36
Mit ReadSections bekommst du schon mal die Sectionen:
Auszug asu Hilfe:
Zitat: |
Reads the names of all sections in an INI file into a string list.
procedure ReadSections(Strings: TStrings); override; |
cbs - Mi 07.08.02 10:23
Tag auch
speicher doch einfach vorher die anzahl der sektoren ab
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| [main] anzahl=3
[1] name=web.de url=www.web.de
[2] name=auq.de url=www.auq.de
[3] name=google.de url=www.google.de |
dann weißt du ja wieviele einträge die ini hat und ließt sie entsprechend aus
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| var ini: TIniFile; cnt, anz: LongInt; name, url: string; begin ini:= TIniFile.Create(FileName); anz:= ini.ReadInteger('main', 'anzahl', 0); for cnt:= 1 to anz do begin name:= ini.ReadString(IntToStr(cnt), 'name', ''); url:= ini.ReadString(IntToStr(cnt), 'url', ''); // erstelle jetzt den menü eintrag mit name und url end; ini.Free; end; |
PS: ich glaube zwischen bezeichner dem '=' und dem wert darf kein leerzeichen sein
matze - Mi 07.08.02 10:53
jo das wäre ne Idee, mit dem Anzahl abspeichern !!!
Aber wie bekommt ich den Befehl zum URL aufrufen in den Menü eintrag rein ???
Geht das vielleicht, dass man abfragt, welcher Menüeintrag geklickt wuirde und die nummer des menü eintrages der geklickt wurde irgendwie mit der nummer der INI section vergelicht :?
cbs - Mi 07.08.02 11:09
@matze: könnte so gehen ja. jeder menüeintrag hat doch die eigenschaft tag vom typ integer. diese eigenschaft wird nicht gebraucht, kannst sie also für dich nutzen. darin speicherst du dann zb. den index des eintrags in der ini.
wenn der tag=1 ist dann ließt du die url des ini eintrags 1 aus wenn tag=5 dann den ini eintrag 5 usw.
du kannst natürlich auch die ganzen urls auch gleich in ein TStringList object speichern. so das der index (tag) des menüeintrags dem des index in der StringListe eintspricht.
klickt der user auf ein menüeintag ließt du den tag aus und öffnest dann die url die dem index in der TStringListe entspricht
matze - Mi 07.08.02 11:12
hmmm..... das könnt klappen:
hier mal meine überlgeung (noch nicht getestet). könntet ihr die mla bite anschauen und mir sagen ob die funzen täte ??
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| procedure TForm1.FormCreate(Sender: TObject); var NewItem: TMenuItem; ini: TIniFile; cnt, anz: LongInt; name, url: string; begin ini:= TIniFile.Create(FileName); anz:= ini.ReadInteger('main', 'anzahl', 0); for cnt:= 1 to anz do begin
NewItem := TMenuItem.Create(Self); NewItem.Caption := ini.ReadString(IntToStr(cnt), 'name', ''); NewItem.OnClick := ShellExecute (ini.ReadString(IntToStr(cnt), 'URL', ''); //Ich weiss, dass der Befehl schmarrn ist, aber ich weiss momentan den genauen ShellExecute Befehl nicht. Fonts1.Add(NewItem);
end; end; |
Ähmm aber in welches Menü schreibt der des dann eigendlich rein ??? Ich will das in ein PopUp menü reinhaben !!!
Delete - Mi 07.08.02 12:50
Das extra Abspeichern der Anzahl halte ich (mit Verlaub!) für umständlich. Mit der schon von wwerner erwähnten Funktion
ReadSections bekommst du eine Stringliste mit allen gültigen Sektionen der INI.
Sollte aus irgendeinem Grund nämlich die INI mal so aussehen:
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| [1] name = Web.de url = www.web.de
[2] name = Auq.de url = www.auq.de
[4] name = Irgendwo url = www.irgendwo.net |
weil irgendwer versehentlich oder aus Dummheit den Punkt #3 entfernt hat, dann wird deine Schleife mit großer Wahrscheinlich nicht mehr funktionieren, da du die Schleifenvariable ja als Sektionsreferenz benutzt. Sie liest also die Sektionen 1, 2 ... findet aber keine 3. :-(
Des Weiteren ließe sich die "Hint"-Variable des Menüeintrags für die URL zweckentfremden. Also, beim Einlesen die Caption auf den Namenseintrag, und den Hint auf die URL setzen, und im "OnClick" nur den Hint an
ShellExecute weiterreichen. Ist einfacher und spart den ständigen Zugriff auf die INI-Datei.
wwerner - Mi 07.08.02 13:09
Hey Mathias :!: Gute Idee :D
Delete - Mi 07.08.02 13:36
Wie wäre es damit?
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:
| uses IniFiles, ShellAPI;
// als private Prozedur deklarieren! procedure TForm1.UrlClick(Sender: TObject); begin with(Sender as TMenuItem) do if(Hint <> '') then ShellExecute(self.Handle,'open',pchar(Hint),nil,nil,SW_SHOWNORMAL); end;
procedure TForm1.FormCreate(Sender: TObject); var cIni : TIniFile; sl : TStringList; i : integer; mi : TMenuItem; begin cIni := TIniFile.Create(Filename); with cIni do try sl := TStringList.Create; try ReadSections(sl);
if(sl.Count > 0) then for i := 0 to sl.Count - 1 do begin mi := TMenuItem.Create(nil); mi.Caption := ReadString(sl.Strings[i],'name',''); mi.Hint := ReadString(sl.Strings[i],'url','');
if(mi.Caption <> '') and (mi.Hint <> '') then begin mi.OnClick := UrlClick; PopupMenu1.Items.Add(mi); end; end; finally sl.Free; end; finally Free; end; end; |
matze - Mi 07.08.02 16:03
ähmmm. nur mal so ne frage: vergisst du nicht am ende die INI zu "free"en ?? oder ist das nicht wichtig, oder wird das mit den FREE gemacht ??
Und nur mal verständnis halber: Wieso muss man das als private Prozedur deklarieren ?
Ansonsten: DANKE MANN !!! Du bist meine Rettung !!! Das ist genau das was ich suche !!!!
Delete - Mi 07.08.02 18:06
matze hat folgendes geschrieben: |
ähmmm. nur mal so ne frage: vergisst du nicht am ende die INI zu "free"en ?? oder ist das nicht wichtig, oder wird das mit den FREE gemacht ?? |
Dann noch mal die gekürzte Form:
Quelltext
1: 2: 3: 4: 5: 6: 7:
| cIni := TIniFile.Create(Filename); with cIni do try // Mach hier irgendwas mit der INI finally Free; end; |
Frage beantwortet? :wink:
Das einzige, was man noch machen könnte, wäre, die TMenuItems wieder freizugeben, wenn sie
weder Caption
noch Hint haben. Dann haben sie nämlich keine Bezeichnung und keine URL und werden ohnehin nicht ins Menü aufgenommen (s.
if).
Zitat: |
Und nur mal verständnis halber: Wieso muss man das als private Prozedur deklarieren? |
Ich hoffe, du meinst jetzt nicht die "OnCreate" der Form. Mit der privaten Prozedur ist nur "UrlClick" gemeint - und die muss man nicht unbedingt so deklarieren. "public" wäre auch okay. Aber wenn du sie nur in der Form1 benötigst, dann ist gegen "private" nichts einzuwenden. Und verkehrt ist es ja auch nicht.
Gruß.
matze - Mi 07.08.02 20:23
also reicht es die INI einfach mit free; freizugeben statt mit cINI.free; ??
cbs - Mi 07.08.02 20:27
@matze: ne, wenn dann muss es schon cINI.free; sein.
in dem fall reicht aber auch Free wegen dem with
schau mal in die hilfe wenn de nich weißt was das ist und macht
@MathiasSimmack: hast völlich recht. das mit der anzahl war nich so gut :oops:
Delete - Do 08.08.02 10:43
@cbs: Normalerweise wäre das mit der Anzahl auch meine erste Idee gewesen. Allerdings hätte ich sie nicht gespeichert, sondern gleich die for-Schleife von 1 bis X hochgezählt ... und abgebrochen, wenn er die Sektion nicht finden kann. Aber das hätte genau die selben Probleme verursacht, wenn irgendjemand eine Sektion mutwillig entfernt. Deswegen finde ich den Weg über
ReadSections sicherer.
@matze: Sorry, für einen Augenblick dachte ich, du willst mich verar.... Ich hatte angenommen, du kennst die Vorteile von
with. Kurz gesagt: in diesem Fall sparst du dir die Angabe von
Das funktioniert eigentlich bei allen Komponenten und Objekten. Du kannst auch mehrere Eigenschaften durch Komma getrennt angeben, etwa:
dann kannst du sowohl auf die Membervariablen von "TreeView1" zugreifen (zu denen ja "Items" auch gehört), als auch direkt auf die Membervariablen von "Items".
Eine bessere Erklärung findest du in der Hilfe, denke ich. :-)
matze - Mi 21.08.02 08:00
So, nach langer Zeit (urlaub) hab ich mal das getesten und ich habe folgendes Probelm:
Immer wenn ich den Code
Quelltext
1: 2: 3: 4: 5:
| procedure TForm1.UrlClick(Sender: TObject); begin with(Sender as TMenuItem) do if(Hint <> '') then ShellExecute(self.Handle,'open',pchar(Hint),nil,nil,SW_SHOWNORMAL); end; |
unter
private in meinem Quelltext schreibe kommen hein Haufen Fehlermeldungen.
END erwartet aber BEGIN gefunden.
Undefinierter Bezeichner URLklick.
Undefinierter Bezeichner TForm1.
Undefinierter Bezeichner TObject.
usw...
Was mache ich da falsch :cry:
Tino - Mi 21.08.02 09:15
Du musst natürlich in der Privatesection nur den Procedure-Kopf definieren:
Quelltext
1: 2:
| Private Procedure UrlClick (Sender: tObject); |
Und dann kannst Du die Proceduer im Implementations-Teil Deiner Unit hinzufügen.
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| Implementation
{...}
procedure TForm1.UrlClick(Sender: TObject); begin with Sender as TMenuItem do if Hint <> '' then ShellExecute ( Handle, 'open', PChar (Hint), nil, nil, SW_SHOWNORMAL ); End; |
Du musst tForm1 dann wahrscheinlich noch umbennen. So wie halt das Objekt heißt in dem es definiert wurde.
Gruß
TINO
matze - Mi 21.08.02 13:36
jo ich hab alles so gemacht, wie du es gesagt hast, aber wie muss ich das denn umbennen ?? ich hab folgendes probiert:
Quelltext
1: 2: 3:
| Tpopupmenu1.UrlClick; Tpopupmenu.UrlClick; Tform1.UrlClick; |
das alles klappt nicht
Tino - Mi 21.08.02 14:14
Es muss so heißen wie das Objekt in dem die Procedure definert ist. Ansonsten poste mal den Code.
Gruß
TINO
matze - Mi 21.08.02 15:00
ich hba den code von MatthiasSimmack (oben) unverändert übernommen !!!
Nur dass ich das procedure TForm1.UrlClick(Sender: TObject); (das ja nicht funzt) in procedure TPopUpMenu1.UrlClick(Sender: TObject); umgeändert habe. Das funzt allerdings auch nicht :cry:
Tino - Mi 21.08.02 16:10
matze hat folgendes geschrieben: |
Das funzt allerdings auch nicht :cry: |
Was kommt denn für eine Fehlermeldung?
matze - Mi 21.08.02 16:45
wenn ich TpopUpMenu1. benutze, kommen viele Fehlermeldungen: Z.B.
Fehler: . gefunden aber ; erwartet
Undefinierter Bezeicher: sender
Undefinierter Bezeicher: self
Wenn ich TForm1. beutze kommt nur
URLklick ist ein undefinierter Bezeichner und er markiert folgende stelle rot: mi.OnClick := UrlClick;
Tino - Mi 21.08.02 22:59
Wie heißt denn jetzt die Form in der Du diese Procedure implementieren willst/hast? tPopUpMenu1 oder tForm1?
matze - Do 22.08.02 08:42
halt stopp !!! ich hab den fehler gefunden !!!!
Ich hatte nicht, wie in dem Wuellext von MatthiasSimmack die Funktioenen für das laden des Menüs in Form1.Create, sondern ich hab das komplette Zeugs in eine eigene Procedure reingeschrieben. Ich hab jetzt das aus der Procedure ausgenmmen und in Form1. Create reingeschrieben und alles funzt bestens !!!
Aber: wie muss ich das ändern, wenn ich das in eine eigene Procedure reinschreiben will: also z.B:
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:
| procedure Menuladen; var cIni : TIniFile; sl : TStringList; i : integer; mi : TMenuItem; begin cIni := TIniFile.Create(Filename); with cIni do try sl := TStringList.Create; try ReadSections(sl);
if(sl.Count > 0) then for i := 0 to sl.Count - 1 do begin mi := TMenuItem.Create(nil); mi.Caption := ReadString(sl.Strings[i],'name',''); mi.Hint := ReadString(sl.Strings[i],'url','');
if(mi.Caption <> '') and (mi.Hint <> '') then begin mi.OnClick := UrlClick; PopupMenu1.Items.Add(mi); end; end; finally sl.Free; end; finally Free; end; end; |
Tino - Do 22.08.02 09:17
Du musst Deine Procedure
Menuladen so umbauen das diese das PopupMenu und den Dateinamen als Parameter bekommt.
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:
| procedure Menuladen (aPopupMenu: tPopupMenu; aFilename: String); var cIni : TIniFile; sl : TStringList; i : integer; mi : TMenuItem; begin cIni := TIniFile.Create(aFilename); with cIni do try sl := TStringList.Create; try ReadSections(sl);
if(sl.Count > 0) then for i := 0 to sl.Count - 1 do begin mi := TMenuItem.Create(nil); mi.Caption := ReadString(sl.Strings[i],'name',''); mi.Hint := ReadString(sl.Strings[i],'url','');
if(mi.Caption <> '') and (mi.Hint <> '') then begin mi.OnClick := UrlClick; aPopupMenu.Items.Add(mi); end; end; finally sl.Free; end; finally Free; end; end; |
Im Event
FormCreate kannst Du dann diese Procedrue aufrufen:
Quelltext
1: 2: 3: 4:
| Procedure tForm1.FormCreate (aSender: tObject); Begin MenuLaden (PopupMenu1, 'c:\test.ini'); End; |
Gruß
TINO
PS: Ich hoffe das das funktioniert... hab es nicht getestet!
matze - Do 22.08.02 09:23
und wie muss ich dann die Funktion URLklick umbauen ??
Tino - Do 22.08.02 11:07
Stimmt das OnClick-Event habe ich vergessen. Das OnClick-Event ist vom Type TNotifyEvent. Das heißt das Du der Menuladen Procedure einen weiteren Parameter übergeben musst: nämlich das OnClickEvent und diesen Parameter kannst Du dann den OnClickEvents der MenuItems zuweisen.
Wenn Du die Procedure dann aufrufst müsste das ungefähr so aussehen:
Quelltext
1: 2: 3: 4:
| Procedure tForm1.FormCreate (aSender: tObject); Begin MenuLaden (PopupMenu1, UrlClick 'c:\test.ini'); End; |
matze - Do 22.08.02 13:13
also die URLKlick routine kann ich unverändert lassen, richtig ???
Köntest du mal den neuen Quellcode der Load Routine und der URLKlick Routine posten !!! Das würe mir sehr helfen !!!
Danke !!!
Delete - Do 22.08.02 17:08
Boah, mattttttttttttze :wink: Was sind das denn für Fragen?
Die "UrlClick"-Routine kann unverändert bleiben, weil du sie ja ganz offensichtlich nicht verändert sondern einfach nur aufgerufen hast, s.:
Quelltext
1:
| mi.OnClick := UrlClick; |
Durch die Benutzung des "OnClick" ist die Syntax für die Funktion (oder besser: Prozedur) ja bereits vorgegeben.
Wenn du deine "Menuladen"-Routine auch noch als private Form-Prozedur deklarierst:
Quelltext
1:
| procedure TDEINEFORM.Menuladen(aFilename: string); |
kannst du a) die Angabe des Popupmenüs direkt im Code unterbringen, weil die Prozedur nun ja auf die Form-Komponenten zugreifen kann (oder du lässt es so wie Tino vorschlägt, was die Funktion universell für andere Programme einsetzbar machen würde), und b) dürfte es keine Probleme geben, wenn du die "OnClick"-Funktion festlegst (s. Codeauszug oben)
matze - Fr 23.08.02 08:23
danke !!!
Ich werds mal testn !!! :D
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!