# Tray Icon mit Array erstellen



## Xervek (25. Februar 2006)

Hallo,

http://www.vbarchiv.net/archiv/tipp_details.php?pid=517 in diesem Tut wird ja wunderbar erklärt, wie man das Programm im Tray verschwinden lassen und auch wieder anzeigen lassen kann. Funktioniert auch wunderbar.

Nun habe ich allerdings ein Array in meinem Programm und würde gern für jedes gefüllte Array einen weiteren Menü-Punkt in diesem Tray anlegen. Das ganze würde dann ja variabel passieren. Das Problem ist jetzt nur, ich habe keine Ahnung wie ich das ganze Variabel machen soll.

Diesen Teil hier


```
Private Sub mnuPopUp_Click(Index As Integer)
  ' Symbol aus dem Systray entfernen
  Shell_NotifyIcon NIM_DELETE, nid
  
  Select Case Index
    Case 0
      ' Wiederherstellen
      Me.Show
      
    Case 1
      ' Beenden
      End
  End Select
End Sub
```

Nehme ich doch mal an, kann ich genau so gut mit einer For-Schleife versehen, sodass er irgendwie am Ende so aussieht


```
Private Sub mnuPopUp_Click(Index As Integer)
  ' Symbol aus dem Systray entfernen
  Shell_NotifyIcon NIM_DELETE, nid

for i = 1 to bla

  Select Case Index
    Case i
      "Ich tue, was mir im Array i befohlen wird"

  End Select

next i

  End Select
End Sub
```

Nur *wie* lege ich die ganzen Menüpunkte an, sodass sie überhaupt zur Auswahl stehen? Es steht dort, dass man diese per Menü-Editor erstellen soll, wenn ich nun beim ersten Programm start mein Array aber nur von 1-4 gefüllt habe, brauche ich nur 4 einträge, wenn ich es beim nächsten Mal aber von 1-10 gefüllt habe brauche ich 10 Einträge. Wie kann ich das denn jetzt am Besten machen?

Hoffe ihr versteht wie und was ich meine.

Liebe Grüße


----------



## Shakie (25. Februar 2006)

Deinen Thread-Titel hast du da aber sehr unpassend gewählt. Dein Problem hat doch gar nichts mit einem Tray Icon zu tun, sondern du möchtest wissen wie man zur Laufzeit dynamische Menüs erstellt.
Das ist ganz einfach, es geht genau so wie man auch Arrays mit Textboxen oder anderen Steuerelementen erstellt.

angenommen du hast ein Menü namens "Menü1" das verschiedene Untermenüs ("Menü2") enthalten soll.
Lege dazu im Menüeditor das Menü1 und das Menü2 an und stelle beim Menü2 die Eigenschaft "Index" auf 0.
Dann kannst du so ein neues Menü erstellen:

```
Load Me.Menü2(Me.Menü2.UBound + 1)

'Jetzt beispielsweise den Text im neuen Menü verändern:
Me.Menü2(Me.Menü2.UBound).Caption = "Menü Nr." & Me.Menü2.Count
```

*Noch ein Hinweis: du solltest in deinem Programm nicht den End-Befehl verwenden!*
Denn beim End-Befehl wird dein Formular nicht richtig aus dem Arbeitsspeicher gelöscht. Statt dessen solltest du mit "Unload Me" die Form richtig schließen (und alle anderen Formen in deinem Programm natürlich ebenfalls).


----------



## Xervek (26. Februar 2006)

Hallo,

vielen Dank es funktioniert fast wunderbar. Und ja, der Name ist sicher falsch, mir fiel nur nichts besseres ein.

Denoch tut sich mir jetzt eine weitere Frage dazu auf.

Besteht die möglichkeit, ein Untermenü zu erzeugen, indem nichts außer der variabel vorhandene Inhalt steht? Beispielweise habe ich 10 Dateien die dort aufgelistet werden, kann ich diese in einem Untermenü erscheinen lassen, ohne das ein weiterer Eintrag vorhanden ist? Denn irgendwie verbietet VB mir die ganze Zeit, dass ich das ganze in ein Untermenü eintrage. Es kommt jedesmal "Mitgliedsdaten nicht..." naja.

Edit: Außerdem noch eine Frage: Wie kann ich denn auf den Inhalt dieser Variabel erstellen Einträge zugreifen? Also beispielweise werden mir mal 10 einträge angelegt wenn 10 Dateien vorhanden sind und mal 12, da muss ich ja irgendwie variabel drauf zugreifen können, oder?


----------



## Shakie (26. Februar 2006)

Tut mir leid, ich versteh nicht was du meinst.


----------



## Xervek (27. Februar 2006)

Hallo,

okay also nochmal etwas ausführlicher und versuche es nochmal etwas besser zu erklären.

Also, ich habe bestimmte Dateien auf dem Desktop, beispielweise

Datei1.doc
Datei2.doc
Datei3.doc
Datei4.doc
Datei5.doc
Datei6.doc

Die Anzahl der Daten variiert. Also frage ich ab per "If fileexists (....."

Für jede existierende Datei soll er mir einen Eintrag in meinem Unsichtbaren Popup menü eintragen. Bis hierhin funktioniert es. Aber wie greife ich jetzt auf beispielweise "Eintrag 3" zu? Nehmen wir als Beispiel, ich möchte die jeweilige Datei öffnen.

Dann habe ich also in meinem Menü die ganzen Optionen hinzugefügt, diese werden mir auch korrekt angezeigt. (Ich habe mal ne Datei angefügt, ist glaube ich einfacher..).

Wie kann ich jetzt in meinem Programm eingeben, was passieren soll, wenn ich auf "Datei4.doc" klicke? Direkt ist mir ja nicht die möglichkeit gegeben, da es diesen "Eintrag" ja eigentlich nicht gibt und ich ihn per


```
Load Me.Menü2(Me.Menü2.UBound + 1)

'Jetzt beispielsweise den Text im neuen Menü verändern:
Me.Menü2(Me.Menü2.UBound).Caption = "Menü Nr." & Me.Menü2.Count
```

hinzufüge. Da es ja auch mal sein kann, das weniger als 4 Dateien vorhanden sind und dann würde nur von Datei1.doc bis Datei3.doc gezählt werden und damit bräuchte ich in dem Fall die "Datei4.doc" nicht und sie würde auch gar nicht angezeigt werden.


----------



## Shakie (27. Februar 2006)

Ok, jetzt verstehe ich was du meinst. Du kannst trotzdem wie gewohnt das Click-Ereignis des Menüs Verwenden. Denn alle deine Menüs, die du über einen Index zusammengefasst hast, sind praktisch zu einem Objekt "verschmolzen" und haben ein gemeinsames Click-Ereignis. Dabei wirst du feststellen, dass im Click-Ereignis eine zusätzliche Variable übergeben wird, nämlich "Index". Damit kannst du feststellen, auf welches Menü geklickt worden ist.

```
Private Sub Menü2_Click(Index As Integer)
    'Nummer des Menüs = Index 
    'niedrigster überhaupt möglicher Index = Menü2.LBound
    'höchster möglicher Index = Menü2.UBound
End Sub
```


----------



## Xervek (28. Februar 2006)

Hallo Shakie,

vielen Dank für die nette Hilfe! Es  jetzt wirklich fast bestens, eine kleinigkeit fehlt noch, dann funktioniert es perfekt 

Und zwar. Du siehst auf dem oben angefügten Bild ein Untermenue, genannt "Programme".
Visual Basic wollte von mir, dass ich dort ein weiteres Menue anlege, damit es überhaupt funktioniert. Dieses Menue nannte ich jetzt schlicht "untermenue". Dieser Eintrag liegt nun unter "Programme" mit dem Index = 0. Meine vorhandenen Items werden also alle ins Untermenue "Programme" hinzugefügt. Wenn ich nun allerdings versuche "untermenue.visible = 0" einzutragen, weigert sich VB und sagt, dass mind. ein Untermenue sichtbar sein muss. Okay denke ich mir, machst du es selbst "unsichtbar" wenn einer deiner Einträge erfolgreich geladen wurde. Jedoch sagt mir VB dann "Methode oder Mitgliedsdaten nicht gefunden". Sagt mir wohl, dass es nicht geht aufgrund des "Index = 0". Dieser Eintrag ist nun allerdings ziemlich unnutz und ich habe keine Chance ihn wegzubekommen da mir keine Möglichkeit gegeben ist. Habe ich irgendwas vergessen oder ist es tatsächlich nicht möglich?

Liebe Grüße und vielen Dank für die bisherige Hilfe!

Edit:

Außerdem noch ein kurze Frage. Ich habe jetzt herausgefunden, wie ich es schaffe, dass sich mein Programm ins Systray verzieht, sobald ich den "Minimieren-Button" klicke. Jedoch ist es mir danach nicht mehr möglich, ihn daraus zu bekommen, ich weiß selbst nicht ganz wieso. Folgender Code:


```
Private Sub Form_Resize()
  If Me.WindowState = vbMinimized Then
    trayicon_unten_einfuegen
  End If

  Exit Sub
End Sub
```

trayicon_unten_einfügen = Code ums zu tun

Er tut es auch so wie er soll, nur wie gesagt bekomme ich ihn dann nicht mehr raus da unten. Ich habe jetzt wirklich mir alles wissende getan, nur irgendwie will er nicht so wie ich das will.

Also ich möchte, beim Klick auf den Minimieren Button, dass er sich ins Systray verzieht und dann eben aus dem Systray wieder normal zu öffnen ist, nur geht das irgendwie nicht. Ohne diesen kleinen Codeteil  es wieder absolut bestens, nur eben dass er beim Klick auf den Minimieren-Button nur in der Taskleiste verschwindet.


----------



## Shakie (28. Februar 2006)

Es ist meines Wissens nach leider wirklich nicht möglich, alle Menüs eines Untermenüs auszublenden. Ich mache es deswegen immer so, dass ich das eine Menü das ich drinlassen muss deaktiviere, also "Untermenü(0).Enabled = Valse."
Zusätzlich gebe ich dem Menü einen Text so in der Art wie "Keine Auswahl möglich" oder ähnliches, je nach dem was gerade gut passt.

Zu deinem anderen Problem: Wie reagierst du denn auf das Klick-Ereignis im Systray? Oben hast du ja nur den Code geschrieben, wie du das Systray-Icon erstellst, wenn deine Form minimiert wird.

Mein Vorschlag: du erstellst eine PictureBox (PictureBox1) und machst sie unsichtbar (Visible = False); diese PictureBox soll dann lediglich den Sinn haben, das MouseMove-Ereignis vom Systray "abzufangen". In dem Beispielcode von deinem Link wird dazu die Form selber verwendet, meines Erachtens ist es aber übersichtlicher einfach eine PictureBox zu diesem Zweck zu erstellen:

```
Private Sub cmdHide_Click()
  ' Symbol der Anwendung zum SysTray hinzufügen
  With nid
    .cbSize = Len(nid)
    'festlegen, dass die PictureBox als Ereignis-Empfänger dienen soll:
    .hWnd = Me.PictureBox1.hWnd
    .uId = vbNull
    .uFlags = NIF_ICON Or NIF_TIP Or NIF_MESSAGE
    .uCallBackMessage = WM_MOUSEMOVE
    .hIcon = Me.Icon
    .szTip = Me.Caption & vbNullChar
  End With
  Shell_NotifyIcon NIM_ADD, nid
  
  ' Anwendung jetzt "verstecken"
  Me.Hide
End Sub


Private Sub PictureBox1_MouseMove(Button As Integer, _
  Shift As Integer, X As Single, Y As Single)
  
  ' Das MouseMove Ereignis wird ausgelöst, wenn die
  ' Maus über das Symbol im Systray geführt wird

  Dim lMsg As Long
  Dim sFilter As String
  
  lMsg = X / Screen.TwipsPerPixelX
  Select Case lMsg
     
     Case WM_LBUTTONDBLCLK
      ' linke Maustaste - Doppelklick --> Form wieder anzeigen:
      Me.Show
Me.WindowState = vbMaximized

     Case Sonstwas      
         [...]
      
  End Select
End Sub
```


----------



## Xervek (28. Februar 2006)

Hallo,

vielen, vielen Dank für deine Hilfe, ohne die wäre ich glaube ich schon verzweifelt.

Allerdings funktioniert das alles nur so zum Teil.

Also ich habe versucht die Funktion auf False zu stellen, so wie du es sagtest. Generell ist dieser Eintrag sogar gut, da ich ihn unter Umständen gebrauchen kann. Es ist mir allerdings nicht möglich den Eintrag per Enabled = False zu verbieten. Wenn ich das tue, ist der gesamte Inhalt nicht mehr enabled. Auch wenn ich versuche es direkt anzusprechen per add_program(0).enabled = false; wird mir der komplette bereit untersagt. Es ist mir also auch hierbei nicht möglich nur einen Eintrag zu deaktivieren. Oder besser, es ist mir nicht möglich grade DEN Eintrag zu deaktivieren.

Reagieren tue ich folgendermaßen (ist jetzt schon die von dir genannte, geänderte Funktion die auf das Picture1 zugreift...)


```
Private Sub Picture1_MouseMove(Button As Integer, _
  Shift As Integer, X As Single, Y As Single)
  
  ' Das MouseMove Ereignis wird ausgelöst, wenn die
  ' Maus über das Symbol im Systray geführt wird

  Dim lMsg As Long
  Dim sFilter As String
  
  lMsg = X / Screen.TwipsPerPixelX
  Select Case lMsg
     Case WM_LBUTTONDOWN
      ' linke Maustaste wird gedrückt
      
     Case WM_LBUTTONUP
      ' linke Maustaste wird losgelassen
      
     Case WM_LBUTTONDBLCLK
      ' linke Maustaste - Doppelklick
      
    Me.Show
    Me.WindowState = vbNormal
      
     Case WM_RBUTTONDOWN
      ' rechte Maustaste wird gedrückt
      
     Case WM_RBUTTONUP
       ' rechte Maustaste wird losgelassen
       ' (jetzt z.B. Popup-Menü öffnen)
       PopupMenu MenuPopUp
       
     Case WM_RBUTTONDBLCLK
      ' rechte Maustaste - Doppeklick
      
  End Select
End Sub
```

Klicke ich also doppelt auf das Icon unten passiert erst einmal gar nichts. Wenn ich dannach noch 2 mal klicke, also 4 mal insgesamt tut es, was ich will. Demnach also kein Doppelklick ereignis sondern 4-klick-ereignis. Außerdem wird das Trayicon unten nicht entfernt sobald das Programm erneut aufgeht. Das Problem liegt in folgendem Code
Hier der Code für den "Minimieren" Button.


```
Private Sub Form_Resize()
  If Me.WindowState = vbMinimized Then
    trayicon_unten_einfuegen
  End If
  'Exit Sub
End Sub
```

Nehme ich diesen Code raus und minimiere mein Programm über einen Button funktioniert alles. Ich meine wirklich ALLES (mit Ausnahme des einen Eintrags den ich nicht wegbekomme, wie ganz am Anfang gesagt).

Alles was ich möchte ist, bei klick auf den "minimieren button", dass das Programm im Tray verschwindet. Und wie gesagt, mit einem normalen button funktionierts.


----------



## Shakie (1. März 2006)

Das erscheint mir alles recht seltsam.
Damit dein Icon aus dem Tray wieder verschwindet, sobald das Programm wieder angezeigt wird, kannst du (theoretisch) einfach nach "Me.Show" in der Sub "Picture1_MouseMove" das hier einfügen:

```
Shell_NotifyIcon NIM_DELETE, nid
```
 Damit sollte das Icon wieder verschwinden.

Kannst du mal dein ganzes Projekt hier hochladen? Dann schaue ich es mir mal an.


----------



## Xervek (1. März 2006)

Hallo,

hochladen wollte ich es hier komplett eher nicht. Allerdings habe ich das ganze jetzt wirklich mal mit einem Button gemacht, der mein Programm "hiden" soll. Mit einem Button funktioniert es, wie es soll. Die Abfrage des "minimieren buttons" muss also irgendwie falsch sein.

Soll ich es dir vielleicht mal per PM schicken? Bzw. hochladen bei mir und dir den Link zum download per PM schicken?

Kann man den "minimieren-button" irgendwie direkt ansprechen? Sodass ich dort einfach eintrage, dass er ins Systray geschoben werden soll? Aufgefallen ist mir nämlich außerdem, wenn ich den Code so einsetzte:


```
Private Sub Form_Resize()
'  If Me.WindowState = vbMinimized Then
    trayicon_unten_einfuegen
'  End If
'  Exit Sub
End Sub
```

Dann wird das Programm direkt beim Programmstart ins Systray geschickt und es kommt wieder zu diesem "4-klick-ereignis".

Also irgendwie sollte das Problem zu lösen sein, wenn ich den Minimieren-Button direkt ansprechen kann.

Und wie gesagt, per PM mache ich das gerne nur so möchte ich es erst einmal nicht.

Edit: Bleibt dann außerdem noch der eine, letzte Button den ich nicht disablen kann. Wie gesagt, sag bescheid obs auch per PN geht, dann mache ich das so...

Vielen Dank!


----------

