¿Por qué cada widget necesitaría una referencia a su padre en un sistema de widget simple?

8

Estoy trabajando en un sistema de widgets simple (ventana única, tamaño fijo). Cada widget obtiene su padre (es decir, el widget que lo contiene) pasado a su constructor, excepto el widget raíz, que llamé Screen .

Tengo algunas dudas si ese enfoque tiene sentido. Lo hice porque la mayoría de los sistemas de widgets que usé antes lo hacen (Qt, GTK, ...), pero me di cuenta de que son bastante más complejos que los míos:

  • No tengo cambio de tamaño de ventana
  • No planeo dimensionar contenedores según el tamaño de sus hijos
  • No creo que lo necesite para la administración de la memoria (estoy usando C ++), puedo usar punteros compartidos (básicamente cómo funcionaría en Java)

¿Hay alguna razón por la que un widget necesite una referencia a su padre?

Es una refactorización importante cambiar esto. Entonces, antes de seguir adelante e implementar contenedores y diseños, quiero tener una buena idea de si voy a necesitar ese padre o no.

Editar: Tenga en cuenta que el padre conoce a todos sus hijos de todos modos, solo me pregunto si los niños también necesitan conocer al padre.

futlib
fuente

Respuestas:

5

Como señaló, el niño mismo rara vez necesita acceder al padre, siempre y cuando el padre haga todo el trabajo y haga un seguimiento de sus hijos. Sin embargo, el clásico getParentes más útil cuando usa el marco desde afuera.

Guión

Una operación simple que puede causar problemas es la siguiente: dados dos widgets concretos que están en algún lugar de su árbol general de widgets y un caso de uso que requiere que intercambie estos dos, ¿cómo funciona el intercambio?

Opción 1: dígales a los niños

Dile a tu widget de niño que swap(withOtherChild). Pero el intercambio implica actualizar la estructura de datos de los hijos de los padres de alguna manera. Como su hijo no conoce a su padre, ¿cómo logra esto?

Opción 2: dile a los padres

Dígale al padre de un niño que lo quite y agregue el otro. Oh espera, mismo problema. Solo tienes los objetos hijos y no hay ninguno getParentsobre ellos.

Opción 3: trabajo duro

Como opción final, puede recorrer todo su árbol de widgets para encontrar un padre con hasChild(x)y uno con hasChild(y)y luego volver a la opción 2.

Solución

Debe mantener el padre si alguna vez desea construir árboles de widgets grandes y realizar operaciones que requieren mover la posición de un widget en el árbol. Si sus árboles de widgets son muy pequeños, o solo tienen una profundidad muy pequeña, pero tienen accesos rápidos hasChild, entonces la Opción 3 puede ser aceptable para usted y puede omitir la referencia principal.

Referencias en estructuras de datos en general

Lo que planeas hacer aquí es construir una estructura de datos para un árbol. Consideremos una simplificación y, por el bien del argumento, supongamos que cada widget solo puede tener un hijo. El resultado, por supuesto, es una lista y su pregunta ahora se convierte en "¿debería tener una lista de enlace simple o doble?".

Y al igual que las listas, no hay una respuesta definitiva, sino solo pros y contras. Los profesionales obvios para el enlace único (es decir, sin referencia principal) son a) más fáciles de implementar yb) menos memoria. Pero las desventajas incluyen a) algunas operaciones se vuelven lentas ya que tienen que atravesar la estructura yb) no tener fácil acceso a esas operaciones puede significar que la estructura de datos es engorrosa de usar, yc) usa más memoria.

Por otro lado, la variante de doble enlace, es decir, con referencia principal, revierte estos pros y contras.

Sin embargo, en términos de una biblioteca / marco de GUI, los límites de memoria generalmente no son un problema que prohíba los punteros principales. Si descarta eso y se da cuenta de que es una biblioteca / marco, y por lo tanto, es preferible que sea difícil de implementar, pero fácil de usar, entonces esencialmente descarta las ventajas anteriores de un enfoque de enlace único.

No conozco las peculiaridades de su proyecto, por lo que quiero abstenerme de decirle que conserve la referencia de los padres, ya que algunos de mis razonamientos anteriores pueden no aplicarse en su caso. En general, sin embargo, considero que las referencias principales en una estructura de datos de widgets valen la pena por las razones anteriores.

Franco
fuente
2

En la mayoría de estos casos hay bastante comunicación entre padres e hijos en caso de eventos, señales o cambios de estado (o simplemente para destruir a los niños cuando sea necesario). Por ejemplo, un cuadro de agrupación puede manejar sus botones de radio contenidos para garantizar que solo uno de ellos esté "encendido" en un momento dado.

Puede o no planear tener una funcionalidad de este tipo. Personalmente dudaría si un sistema de widgets sin él vale la pena ya que no ofrecería mucho. Pero de todos modos, simplemente usaría una de las soluciones existentes.

Thorsten Müller
fuente
1
Todo eso parece posible cuando el padre conoce a sus hijos, que es el caso para mí. Me pregunto si el niño también necesita conocer al padre.
futlib
Felizmente usaría algo existente, pero estamos en un entorno bastante único aquí y pensamos que nuestro propio sistema simple es el mejor enfoque.
futlib
Siempre hay razones, por supuesto, y Qt, por ejemplo, es bastante pesado. La razón por la que el niño necesita conocer a su padre es principalmente para poder registrarse con él en la creación o luego enviarle cambios de estado.
thorsten müller
¿Quiere decir que cuando se hace clic en un botón de radio, debe informar al padre para que pueda desmarcar el botón marcado anteriormente? Sí, creo que sería difícil sin la conexión niño-> padre ... ¿Puedes pensar en otros ejemplos?
futlib
2
"Según el tamaño y la posición" podría dejarle un código realmente desagradable. Preferiría esbozar eventos. Al igual que el padre obtiene un evento de clic, luego "pregunta" a sus hijos si son responsables, lo que deciden en función de su propia información de posición y tamaño. ¿Otros ejemplos? Depende de lo complejos que sean tus widgets. Dices que no serán tan complicados. Pero por otro lado: si agrega el puntero principal desde el principio, no le hará mucho daño y los tendrá cuando los necesite. Las barras de desplazamiento son otro buen ejemplo, supongo. Informan de desplazamiento al padre, el padre le dice a la vista que actualice.
thorsten müller
2

Diría que, cuando los niños conocen a sus padres, un widget y todos sus antepasados ​​forman una cadena de responsabilidad . Un ejemplo típico es un evento de mouse recibido por un widget: el widget puede consumir el evento (y reaccionar en consecuencia), o pasar el evento a su padre, que puede consumir o pasar a su padre, etc.

En el caso de Qt, cada constructor le da a su widget su padre, y esto indica que el widget es propiedad del padre. En particular, la eliminación del padre desencadena la eliminación del widget.

barjak
fuente