MenuStrip

Iniciado por SilverLycan68, 21 Julio 2018, 00:42 AM

0 Miembros y 1 Visitante están viendo este tema.

SilverLycan68

Tengo un MDIParent con un menustrip y al darle click en un item me abre una nueva forma con otro menustrip que lleno con una funcion.
Problema 1: es que al abrir mas de un form solo se llena el menustrip del primero.

MDIParent:

Public Class MDI_principal
   Private Sub MenuStrip_ItemClicked(sender As Object, e As ToolStripItemClickedEventArgs) Handles MenuStrip.ItemClicked
        Try
            Dim form As New frmSubMenus
            form.MdiParent = Me
            form.Text = e.ClickedItem.Text
            form.Show()
        Catch ex As Exception
            MsgBox("ERROR." + ex.Message)
        End Try
    End Sub
End Class


Form hijo. Si quito el MsgBox(str) no llena el menu:

Public Class frmSubMenus
    Private Sub frmSubMenus_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        For Each ctr As Control In Me.Controls
            Me.ToolTip1.SetToolTip(ctr, ctr.ToString)
        Next
        Try
            Dim submenu As New ArrayList()
            submenu = MenuSecundario(Me.Text)
            If Not IsNothing(submenu) Then
                For Each str As String In submenu
                    MsgBox(str)
                    MenuStrip1.Items.Add(str)
                Next
            End If
        Catch ex As Exception
            MsgBox("ERROR." + vbLf + ex.Message + vbLf + ex.ToString)
        End Try
End Sub


Funcion para llenar menu del form hijo:

Public Function MenuSecundario(ByVal txt As String) As ArrayList
        Dim submenu As ArrayList = Nothing
        Select Case txt
            Case "Ventas"
                submenu = New ArrayList
                submenu.Add("Cotizacion")
                submenu.Add("Pedidos")
                submenu.Add("Clientes")
                submenu.Add("por Autorizar")
                submenu.Add("Calendario")
                submenu.Add("Estadisticas")
                Exit Select

           Case "Compras"
                submenu = New ArrayList
                submenu.Add("Pendientes")
                submenu.Add("Administrador")
                submenu.Add("Productos")
                submenu.Add("Proveedores")
                submenu.Add("Clientes")
                submenu.Add("Calendario")
                submenu.Add("Estadisticas")
                Exit Select

            Case Else
                Exit Select

        End Select
        Return submenu
    End Function


Me harian el favor de decirme donde tengo el error.

Serapis

#1
Al margen de que el código no es óptimo, no hay nada ilegal en él...

El comentario (siguiente, el tachado) es erróneo (aparece el constructor de clase, que pasé por alto). No obstante, tras su declaración la función llamada lo creará si lo precisa, luego sobra hacerlo aquí y por tanto basta su declaración: Dim submenu As ArrayList


(excepto que en esta línea declaraste un array de arraylist, y sobra como array, es decir elimina los paréntesis)
Dim submenu As New ArrayList()


Lo que sucede es que posiblemente no entiendas el formulario MDI.
Un formulari MDI, siempre subsume el menú,  del formulario hijo en su propio menú.
bueno siempre no... Esto está controlado por la propiedad AllowMerge del menustrip. (Abajo del todo, en la última sección, te pongo un ejemplo para dicho caso, son cambios ligeros)

Así cuando tú seleccionas Ventas, se crea el formulario con los menús asociados a él, y lo mismo con Compras... (o con alguno más si añadieras más), pero una vez que (por ejemplo) 'Ventas' tiene el foco, su menú se integra en el padre. A su vez el formulario hijo que pierde el foco (por ejemplo "Compras"), ve de vuelta su menú sobre sí, siendo retirado del formulario padre...

Una forma de verlo muy muy claro, es añadir el siguiente código al frmSubmenus
Haciendo que el formulario hijo ocupe toda el área cliente del formulario padre, no habría sitio para el menú del hijo...
Código (vbnet) [Seleccionar]
Private Sub frmSubmenus_GotFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.GotFocus
       Me.WindowState = FormWindowState.Maximized
   End Sub


Y eso es todo...





A continuación, lo que te presento es algunas correciones...

En VB, no hay "BREAK", para los bloques de control "select case", luego las sentencias 'Exit select', sobran si ya se llegó al final del código del propio 'case'.
Tampoco tiene sentido llamar al araylist 'submenú... conforme a la función simplemente genera una lista, luego no tiene sentido darle un nombre más propio que lista. Tampoco es necesario asignarlo Nothing, si luego lo vas a crear...
de hecho el 'case else' sobra, y se pone solo por lo molesto del 'warning'... aunque el propio compilador ya detectaría que como de entrada es nothing, eso es lo que devuelve y que por tanto el warning, es absurdo...
Código (vbnet) [Seleccionar]

Public Function MenuSecundario(ByVal txt As String) As ArrayList
       Dim lista As ArrayList
       Select Case txt
           Case "Ventas"
               lista = New ArrayList
               lista.Add("Cotizacion")
               lista.Add("Pedidos")
               lista.Add("Clientes")
               lista.Add("por Autorizar")
               lista.Add("Calendario")
               lista.Add("Estadisticas")
           Case "Compras"
               lista = New ArrayList
               lista.Add("Pendientes")
               lista.Add("Administrador")
               lista.Add("Productos")
               lista.Add("Proveedores")
               lista.Add("Clientes")
               lista.Add("Calendario")
               lista.Add("Estadisticas")
           Case Else
               lista = Nothing
       End Select
       Return lista
   End Function


en el siguiente código hay 3 cosas que decir...
1- submenu es un objeto arraylist, la función llamada lo creará si lo precisa, luego sobra hacerlo aquí, basta su declaración.
2- El try...catch, carece de sentido, la línea "If Not IsNothing(submenu) Then" ya previene el posible error que pudiera ser generado, el recorrido de la lista como se hace con 'for each' no va a generar error', lo mismo que añadir ítems al menu... ahí el único error posible es que no existiera el menustrip1. Algo que se va a detectar en diseño, a poco que se pruebe el proyecto... luego poner try....catch, donde no son necesarios es una práctica lastrante.
3 - El msgbox, también sobra, aunque en diseño, para probar puedes ponerlo, de todas manearas unas décimas de segundo, después se podrá ver sobre la ventana MDI, luego...
Código (vbnet) [Seleccionar]

Private Sub frmSubMenus_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
       For Each ctr As Control In Me.Controls
           Me.ToolTip1.SetToolTip(ctr, ctr.ToString)
       Next
       'Try
       Dim submenu As ArrayList  
       submenu = MenuSecundario(Me.Text)
       If Not IsNothing(submenu) Then
           For Each str As String In submenu
               'MsgBox(str)
               MenuStrip1.Items.Add(str)
           Next
       End If
       'Catch ex As Exception
       'MsgBox("ERROR." + vbLf + ex.Message + vbLf + ex.ToString)
       'End Try
   End Sub


En esta sección, hemos movido la declaración del form al módulo de clase, fuera de la funcionalidad del evento.
El try...catch, también sobra, pero puedes mantenerlo mientras lo pruebas, antes de compilar, coméntal dichas líneas...
Lo más importante... como no has limitado de ninguna manera que pueda seguir creando más formularios 'Ventas, 'Compras'...cada vez que pulses en el menuStrip "Ventas", ó "Compras", generarás un nuevo formulario, cada uno con su propio menú, el problema es que no sabrás distinguir uno de otro...
Entonces o bien limitas a que solo se cree un único menú de cada tipo o bien 'personaliza el nombre' para cada uno...
La forma más simple de personalizar el nombre, es autonumerarlos... Es el código que añado sobre lo que tú tienes...
Código (vbnet) [Seleccionar]

Dim form As frmSubmenus

   Private Sub MenuStrip_ItemClicked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles MenuStrip.ItemClicked
       Static childrens As Int16
       Try
           form = New frmSubmenus
           form.MdiParent = Me
           form.Text = e.ClickedItem.Text & "-" & childrens.ToString
           form.Show()
           childrens += 1
       Catch ex As Exception
           MsgBox("ERROR." + ex.Message)
       End Try
   End Sub






p.d.: añado los cambios para que cada formulario porte su propio menú... de forma independiente.

Ahora si tu prefieres que cada menú hijo tenga su propio menú sobre sí, y no subsumido en el 'padre', tienes que hacer estos cambios:

Ve a las propiedades del formulario MDI, selecciona el objeto MenuStrip1, cambia su propiedad
AllowMerge del menustrip1 a FALSE

Y ahora cambia el código en cada formulario según el code de cada uno que pongo a continuación...

Código (vbnet) [Seleccionar]

Private Sub frmSubMenus_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
       Dim submenu As ArrayList

       For Each ctr As Control In Me.Controls
           Me.ToolTip1.SetToolTip(ctr, ctr.ToString)
       Next
   
       
       ' Como ahora el texto de cada formulario está autonemuerado (pero comenzando con un guión)
       ' Tomamos la parte común del nombre...
       ' Esto tendría más fácil solución si en vez de pasar un string, se pasara un valor numérico
       ' por ejemplo:   (1=Ventas, 2=compras, otro=else) partiendo quizás de una enumeración...
       Dim strName As String
       Dim k As Integer = InStr(Me.Text, "-")
       If (k > 0) Then
           strName = Me.Text.Substring(0, k - 1)
       Else
           strName = Me.Text
       End If

       submenu = MenuSecundario(strName)
       If Not IsNothing(submenu) Then
           For Each str As String In submenu              
               Me.MenuStrip1.Items.Add(str)
           Next        
       End If        
   End Sub


El autonumerado sigue válido para el caso, así verás más ventanas del mismo tipo cada una con su propio menú... (esto es copia del código del último bloque antes de la linea de sección).
Código (vbnet) [Seleccionar]

Dim form As frmSubmenus

   Private Sub MenuStrip_ItemClicked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles MenuStrip.ItemClicked
       Static childrens As Int16
       Try
           form = New frmSubmenus
           form.MdiParent = Me
           form.Text = e.ClickedItem.Text & "-" & childrens.ToString
           form.Show()
           childrens += 1
       Catch ex As Exception
           MsgBox("ERROR." + ex.Message)
       End Try
   End Sub


Y si tienes activado El windowSTate Maximized... tendrás otra línea de menú bajo el principal, prueba con y sin estas líneas...
Código (vbnet) [Seleccionar]
Private Sub frmSubmenus_GotFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.GotFocus
       Me.WindowState = FormWindowState.Maximized
   End Sub







Aún así, debrrías limitar la creación de formularios, no es tolerable que cada vez que se pulse el menú, se cree una nueva ventana, porque durante una sesión un mismo menú podría ser pulsado 50 veces, crear 50 formularios... seguramente no sea necesario, creo que es algo que dejas abierto y no es adecuado.  Como mínimo habría que eliminar el formulario previo del mismo tipo...