Problemas con aplicación MDI
Hola de nuevo, siento molestarte otra vez pero me ha surgido un prblemilla que no se por donde atacarlo, a ver si me puedes echar una mano.
Solventado a mi manera el tema de los objetos COM y demás, me ha surgido otro relacionado con aplicaciones MDI.A groso modo mi aplicación tiene que estar monitorizando el valor de unas variables de un autómata, el problema viene cuando abro dos ventanas hijas del formulario MDI, el caso es que los valores que estoy monitorizando solo se ven los cambios cuando la ventana recibe el foco, a mi me gustaría que aunque pierda el foco la ventana siga monitorizando el valor o los valores, no se muy bien como puedo poner eso, he mirado alguna cosilla pero sin acierto, bueno pues nada más un saludo y gracias!
Solventado a mi manera el tema de los objetos COM y demás, me ha surgido otro relacionado con aplicaciones MDI.A groso modo mi aplicación tiene que estar monitorizando el valor de unas variables de un autómata, el problema viene cuando abro dos ventanas hijas del formulario MDI, el caso es que los valores que estoy monitorizando solo se ven los cambios cuando la ventana recibe el foco, a mi me gustaría que aunque pierda el foco la ventana siga monitorizando el valor o los valores, no se muy bien como puedo poner eso, he mirado alguna cosilla pero sin acierto, bueno pues nada más un saludo y gracias!
1 respuesta
Respuesta de hawkin
1
1
![hawkin](http://blob.todoexpertos.com/letters/H_106_48.png?v=1)
Tranquilo, no es molestia. Para eso estamos.
Bueno, he hecho una pequeña prueba para comprobar qué te puede estar pasando. El siguiente código funciona independientemente de cual es la ventana hija activa:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
hijo1 = New Form2
hijo2 = New Form2
hijo1.MdiParent = Me
hijo2.MdiParent = Me
hijo1.Show()
hijo2.Show()
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
hijo1.Label1.Text = Now.ToLongTimeString()
hijo2.Label1.Text = Now.AddHours(3).ToLongTimeString()
End Sub
Entiendo que haces algo por el estilo, con lo que debemos buscar algo que podría darte problemas.
La opción más directa que se me ocurre es la resolución de los eventos. Si los cambios en las pantallas vienen dados por eventos, es posible que no te estén llegando a las ventanas que no están activas (me parece raro, pero podría ocurrir), o quizás estos evento llegan pero no se ejecutan por tener que esperar en la cola si tienes alguna funcionalidad que consuma el procesador.
Si es este segundo caso, la solución es fácil. En ese proceso que consume tanto, haz que se pare de vez en cuando para que se ejecuten los eventos en cola. Esto se hace con Application. DoEvents()
Si es el primer caso, la solución podría ser más compleja, y depende de como tengas estructurado el programa.
Se me ocurre también que, dependiendo de cómo lo tengas hecho, hagas como yo, utilizar un temporizador en la ventana padre, y que sea éste el que se encargue de mirar a través del COM los valores que los dispositivos externos.
No sé si te estaré ayudando o te lio más. Si no te resuelve esto, por favor, dame más datos sobre si tienes eventos, temporizadores, etc.
Bueno, he hecho una pequeña prueba para comprobar qué te puede estar pasando. El siguiente código funciona independientemente de cual es la ventana hija activa:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
hijo1 = New Form2
hijo2 = New Form2
hijo1.MdiParent = Me
hijo2.MdiParent = Me
hijo1.Show()
hijo2.Show()
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
hijo1.Label1.Text = Now.ToLongTimeString()
hijo2.Label1.Text = Now.AddHours(3).ToLongTimeString()
End Sub
Entiendo que haces algo por el estilo, con lo que debemos buscar algo que podría darte problemas.
La opción más directa que se me ocurre es la resolución de los eventos. Si los cambios en las pantallas vienen dados por eventos, es posible que no te estén llegando a las ventanas que no están activas (me parece raro, pero podría ocurrir), o quizás estos evento llegan pero no se ejecutan por tener que esperar en la cola si tienes alguna funcionalidad que consuma el procesador.
Si es este segundo caso, la solución es fácil. En ese proceso que consume tanto, haz que se pare de vez en cuando para que se ejecuten los eventos en cola. Esto se hace con Application. DoEvents()
Si es el primer caso, la solución podría ser más compleja, y depende de como tengas estructurado el programa.
Se me ocurre también que, dependiendo de cómo lo tengas hecho, hagas como yo, utilizar un temporizador en la ventana padre, y que sea éste el que se encargue de mirar a través del COM los valores que los dispositivos externos.
No sé si te estaré ayudando o te lio más. Si no te resuelve esto, por favor, dame más datos sobre si tienes eventos, temporizadores, etc.
![cespar](http://blob.todoexpertos.com/letters/C_184_48.png?v=1)
Te mando los ejemplos tal y como los tengo aunque estoy seguro que le problema es como llamo a los hijos en el evento pero no se me ocurre como llamarlos, voy con ello:
Dim hijo As New FormHijo
'dim proy As New ClassLibrary1.Proyecto
hijo.MdiParent = Me
Static nVentana As Integer
hijo.Text = "Proyecto_" & nVentana.ToString
mdi_nombre = hijo.Text
FormMdi.activeChildForm = hijo
hijo.Show()
'Proyecto.NombreProyecto = hijo.Text
Me.activeChildForm.Proyecto = gProyectoActual
asi es como creo los hijos,ahora te mando el evento del cambio de foco
Private Sub FormMdi_MdiChildActivate(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.MdiChildActivate
If Me.ActiveMdiChild Is Nothing Then
Me.Text = "CLIENTE OPC [Sin Documentos]"
Else
Me.Text = "CLIENTE OPC [" & Me.ActiveMdiChild.Text & "]"
'gProyectoActual = Me.activeChildForm.Proyecto
'activeChildForm = Me.ActiveMdiChild
activeChildForm = CType(Me.ActiveMdiChild, FormHijo)
Dim i As Integer
If Not (gCliente.ContadorProyectos) = 0 Then
For i = LBound(gCliente.ListaProyectos) To UBound(gCliente.ListaProyectos)
If gCliente.ListaProyectos(i).NombreProyecto = Me.activeChildForm.Text Then
Me.activeChildForm.Proyecto = gCliente.ListaProyectos(i)
'gProyectoActual = gCliente.ListaProyectos(i)
End If
Next
End If
gProyectoActual = activeChildForm.Proyecto
End If
End Sub
Lo que hay de proyectos y eso es porque antes de poner nada aquí lo que hacia era si hacia click en una ventana me escribía en la otra siempre de la ventana 0 a la 1 en caso que tuviera 2
Ahora te mando el evento que sobre escribe en el listview en cada cambio, no te lo escribo todo porque es muy largo pero te pnogo lo que yo creo que es crucial
Private Sub gGrupo_DataChange(ByVal TransactionID As Integer, ByVal NumItems As Integer, ByRef ClientHandles As System.Array, ByRef ItemValues As System.Array, ByRef Qualities As System.Array, ByRef TimeStamps As System.Array) Handles gGrupo.DataChange
''Esto de arriba es la declaracion y asi es como llamo al listview del otro de la ventna hija
FormMdi.activeChildForm.ListView1.Items
Se que de esta manera lo que hace es solo escribir en la ventana que esta activa porque se lo estoy diciendo yo pero lo que no se es llamar al listview de todas las ventanas y aunque no tengan el foco que siga escribiendo el valor de las variables.
Espero que lo puedas ver claro porque segundo lo estoy escribiendo sale en mil rengolones y no se ve nada, creo que te he puesto lo fundamental para que veas el problema, si necesitas alguna aclaración más estoy a tu disposición y muchas gracias de nuevo
Un saludo!
Dim hijo As New FormHijo
'dim proy As New ClassLibrary1.Proyecto
hijo.MdiParent = Me
Static nVentana As Integer
hijo.Text = "Proyecto_" & nVentana.ToString
mdi_nombre = hijo.Text
FormMdi.activeChildForm = hijo
hijo.Show()
'Proyecto.NombreProyecto = hijo.Text
Me.activeChildForm.Proyecto = gProyectoActual
asi es como creo los hijos,ahora te mando el evento del cambio de foco
Private Sub FormMdi_MdiChildActivate(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.MdiChildActivate
If Me.ActiveMdiChild Is Nothing Then
Me.Text = "CLIENTE OPC [Sin Documentos]"
Else
Me.Text = "CLIENTE OPC [" & Me.ActiveMdiChild.Text & "]"
'gProyectoActual = Me.activeChildForm.Proyecto
'activeChildForm = Me.ActiveMdiChild
activeChildForm = CType(Me.ActiveMdiChild, FormHijo)
Dim i As Integer
If Not (gCliente.ContadorProyectos) = 0 Then
For i = LBound(gCliente.ListaProyectos) To UBound(gCliente.ListaProyectos)
If gCliente.ListaProyectos(i).NombreProyecto = Me.activeChildForm.Text Then
Me.activeChildForm.Proyecto = gCliente.ListaProyectos(i)
'gProyectoActual = gCliente.ListaProyectos(i)
End If
Next
End If
gProyectoActual = activeChildForm.Proyecto
End If
End Sub
Lo que hay de proyectos y eso es porque antes de poner nada aquí lo que hacia era si hacia click en una ventana me escribía en la otra siempre de la ventana 0 a la 1 en caso que tuviera 2
Ahora te mando el evento que sobre escribe en el listview en cada cambio, no te lo escribo todo porque es muy largo pero te pnogo lo que yo creo que es crucial
Private Sub gGrupo_DataChange(ByVal TransactionID As Integer, ByVal NumItems As Integer, ByRef ClientHandles As System.Array, ByRef ItemValues As System.Array, ByRef Qualities As System.Array, ByRef TimeStamps As System.Array) Handles gGrupo.DataChange
''Esto de arriba es la declaracion y asi es como llamo al listview del otro de la ventna hija
FormMdi.activeChildForm.ListView1.Items
Se que de esta manera lo que hace es solo escribir en la ventana que esta activa porque se lo estoy diciendo yo pero lo que no se es llamar al listview de todas las ventanas y aunque no tengan el foco que siga escribiendo el valor de las variables.
Espero que lo puedas ver claro porque segundo lo estoy escribiendo sale en mil rengolones y no se ve nada, creo que te he puesto lo fundamental para que veas el problema, si necesitas alguna aclaración más estoy a tu disposición y muchas gracias de nuevo
Un saludo!
![cespar](http://blob.todoexpertos.com/letters/C_184_48.png?v=1)
Jode macho va a ser que si que controlas un poco del tema.
A ver la manera en que creas los hijos si lo hago de la misma manera que tu, pero como el programa se va haciendo bastante largo pues hago cosas de otra manera que pueden ser la clave del error, te explico:
Bueno referente a llas opciones que has planteado lamento decirte que es mediante eventos, uno en cuestión, es un evento que lo que salta en cuanto hay un cambio en las variables que monitoriza y los puede actualizar cada milisegundo para que te has una idea de los datos que maneja.
La ventana hija básicamente es un treeview donde se explora el autmata y un listview donde se visualizan los datos de las variables, no se si esto ayuda pero te lo digo.
Yo creo que se por donde van los tiros pero las soluciones que se me han ocurrido no me han funcionado te explico:
Ahora estoy en casa y no te puedo poner los ejemplos pero por ejemplo controlo el evento MDIChildActivate que es el que me sigue el foco de los formularios por eso de los botones y demás, y a mayores siempre que hago referencia al listview que es donde se tiene que ver el cambio lo hago con
FormMDI.mdichildActive.listview
Creo que ahí esta la chicha pero no se como llamar al listview del hijo desde otra clase, también he pensado en recorrer todos los formularios hijo darles de alguna manera el foco y que se actualize llamando al evento que me cambia los datos pero no se como hacerlo y no se si esta bien, esto lo mismo te resulta un poco lio mañana te pongo los ejemplos bien puestos pero creo que estoy cometiendo alguna incoherencia por ahí por mi falta de conocimientos, bueno pues lo dicho muchas gracias y mañana a primera hora te pongo los ejemplos a ver is te ayudan algo.
Al final tengo que poner tu nombre en mi proyecto en la parte de agradecimientos, ja ja, bueno, ya me dirás
A ver la manera en que creas los hijos si lo hago de la misma manera que tu, pero como el programa se va haciendo bastante largo pues hago cosas de otra manera que pueden ser la clave del error, te explico:
Bueno referente a llas opciones que has planteado lamento decirte que es mediante eventos, uno en cuestión, es un evento que lo que salta en cuanto hay un cambio en las variables que monitoriza y los puede actualizar cada milisegundo para que te has una idea de los datos que maneja.
La ventana hija básicamente es un treeview donde se explora el autmata y un listview donde se visualizan los datos de las variables, no se si esto ayuda pero te lo digo.
Yo creo que se por donde van los tiros pero las soluciones que se me han ocurrido no me han funcionado te explico:
Ahora estoy en casa y no te puedo poner los ejemplos pero por ejemplo controlo el evento MDIChildActivate que es el que me sigue el foco de los formularios por eso de los botones y demás, y a mayores siempre que hago referencia al listview que es donde se tiene que ver el cambio lo hago con
FormMDI.mdichildActive.listview
Creo que ahí esta la chicha pero no se como llamar al listview del hijo desde otra clase, también he pensado en recorrer todos los formularios hijo darles de alguna manera el foco y que se actualize llamando al evento que me cambia los datos pero no se como hacerlo y no se si esta bien, esto lo mismo te resulta un poco lio mañana te pongo los ejemplos bien puestos pero creo que estoy cometiendo alguna incoherencia por ahí por mi falta de conocimientos, bueno pues lo dicho muchas gracias y mañana a primera hora te pongo los ejemplos a ver is te ayudan algo.
Al final tengo que poner tu nombre en mi proyecto en la parte de agradecimientos, ja ja, bueno, ya me dirás
![cespar](http://blob.todoexpertos.com/letters/C_184_48.png?v=1)
De todas formas cuando desde otra clase quiero hacer lo que me indicas cuando pongo
FormMdi.
No me da la opción de añadirle MdiChildren pero en cambio desde el mismo formulario con me.mdichildren si me deja, ¿a lo mejor tengo que guardar el formulario MDI en una variable global?
FormMdi.
No me da la opción de añadirle MdiChildren pero en cambio desde el mismo formulario con me.mdichildren si me deja, ¿a lo mejor tengo que guardar el formulario MDI en una variable global?
![hawkin](http://blob.todoexpertos.com/letters/H_106_48.png?v=1)
Vale, el problema que me planteas ahora se llama polimorfismo. Tu tienes un formulario que herada de Form, y lo que te devuelve MdiChildren son forms. Él, a priori, no sabe que es una clase nueva que hereda de Form.
La forma de solucionar esto es por dos caminos (creo que los dos funcionan, no estoy seguro...):
1. Utilizar ForEach, diciendo que los objetos son FormHijo:
For Each frm As FormHijo In FormMdi.Mdichildren
...
Next
Aquí, en cada pasada, tendrás cada uno de los objetos de la colección, pero como si fueran la clase que tu creaste.
2. Algo parecido a lo que tú has hecho, pero con una asignación importante.
Dim frm As FormHijo
for i=0 to FormMdi.Mdichildren.length-1
FormMdi.Mdichildren(i) <- Esto es un Form
frm = FormMdi.Mdichildren(i) <- Ahora es un FormHijo, lo acabamos de convertir usando polimorfismo.
La forma de solucionar esto es por dos caminos (creo que los dos funcionan, no estoy seguro...):
1. Utilizar ForEach, diciendo que los objetos son FormHijo:
For Each frm As FormHijo In FormMdi.Mdichildren
...
Next
Aquí, en cada pasada, tendrás cada uno de los objetos de la colección, pero como si fueran la clase que tu creaste.
2. Algo parecido a lo que tú has hecho, pero con una asignación importante.
Dim frm As FormHijo
for i=0 to FormMdi.Mdichildren.length-1
FormMdi.Mdichildren(i) <- Esto es un Form
frm = FormMdi.Mdichildren(i) <- Ahora es un FormHijo, lo acabamos de convertir usando polimorfismo.
![cespar](http://blob.todoexpertos.com/letters/C_184_48.png?v=1)
Ya creo que se por donde vas pero me sucede una cosa, el evento gGrupo_DataChange no pertenece al contenedor de MDI esta implementado en otra clase pero da lo mismo el caso es que cuando lo hago pongo
for i=0 to FormMdi.Mdichildren.length-1
FormMdi.Mdichildren(i).
despues del punto no me deja escoger el Listview1 que tenia como Friend pero ahora tengo coomo publico,pero vamos no solo no me deja acceder a ese sino que tampoco me deja a ningun otro control ni variable,vamos que solo me deja acceder a propiedades de los formularios,no se si hago algo mal.
Respecto a las dos opciones utilizaría la segunda pero si esto que me propones lo lograra funcionar creo que lo echaría a andar.
Parecía más difícil, vamos si funciona esto
Muchas Gracias, Un Saludo
for i=0 to FormMdi.Mdichildren.length-1
FormMdi.Mdichildren(i).
despues del punto no me deja escoger el Listview1 que tenia como Friend pero ahora tengo coomo publico,pero vamos no solo no me deja acceder a ese sino que tampoco me deja a ningun otro control ni variable,vamos que solo me deja acceder a propiedades de los formularios,no se si hago algo mal.
Respecto a las dos opciones utilizaría la segunda pero si esto que me propones lo lograra funcionar creo que lo echaría a andar.
Parecía más difícil, vamos si funciona esto
Muchas Gracias, Un Saludo
![hawkin](http://blob.todoexpertos.com/letters/H_106_48.png?v=1)
Je, creo que al final estamos dando vueltas a algo muy sencillo.
Entiendo que el evento gGrupo_DataChange es del contenedor de mdi, y este se encarga de escribir los datos en los hijos. Si este es el caso, es sencillo de solucionar.
Veo dos posibles casos:
1. Que todas las ventanas tengan que tener los mismos datos. Si este es el caso, en FormMdi. MdiChildren tienes la colección de ventanas hijas. Es una colección de formularios, y con un ForEach tienes solucionado el problema.
2. Que dependiendo de los datos del evento haya que escribir en una ventana hija o en otra. Para esto deberemos utilizar también la colección, pero en la búsqueda ir mirando si la ventana es en la que debes escribir o no.
Para ambos casos, el ListView1 debe ser público en todos los formularios hijos para poder acceder a él, como imagino que estás haciendo.
¿Te soluciona esto el problema?
Entiendo que el evento gGrupo_DataChange es del contenedor de mdi, y este se encarga de escribir los datos en los hijos. Si este es el caso, es sencillo de solucionar.
Veo dos posibles casos:
1. Que todas las ventanas tengan que tener los mismos datos. Si este es el caso, en FormMdi. MdiChildren tienes la colección de ventanas hijas. Es una colección de formularios, y con un ForEach tienes solucionado el problema.
2. Que dependiendo de los datos del evento haya que escribir en una ventana hija o en otra. Para esto deberemos utilizar también la colección, pero en la búsqueda ir mirando si la ventana es en la que debes escribir o no.
Para ambos casos, el ListView1 debe ser público en todos los formularios hijos para poder acceder a él, como imagino que estás haciendo.
¿Te soluciona esto el problema?
- Compartir respuesta
- Anónimo
ahora mismo
![](/content/images/user_nophoto_small.png)