Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Como gestionar la destruccion de un widget de mi GUI

Iniciado por tamat, 14 de Noviembre de 2006, 09:50:20 PM

« anterior - próximo »

tamat

Hace meses que llego mejorando mi sistema de GUI pero hasta ahora no había añadido la opción de que el usuario cierre un dialog, lo he implementado pero ahora tengo el problema de qué pasa cuando se destruye si alguien tiene un puntero a ese widget, me gustaría que lo supiese.

Para solucionar esto se me ocurren muchas opciones (como usar handlers en lugar de punteros o forzar al programador a checkear si existe el objeto de una manera explicita), pero mi framework se caracteriza por usar siempre soluciones elegantes para el programador, y para ello me gusta hacer uso de los recursos que C++ me da, por rebuscados que sean, así me sirve para más adelante.

Estoy seguro de que puedo crear algun tipo de smartpointer, haciendo uso de un template de punteros, en lugar de usar los punteros mismos. Si no lo uso no causa overhead, pero si lo uso entonces al destruirse avisa al smartpointer de que ya no es valido, convirtiendo la direccion en NULL, pero no quiero que cada widget tenga un overhead para eso, no quiero que cada uno tenga una lista de "smartpointers" que lo usan.

Seguro que se puede hacer algo más limpio, tal vez indexarlos en algun tipo de map y que al destruirse los busque y borre la dirección.

Realmente no me interesa solucionar este problema en concreto, pero me gustaría saber qué soluciones aplicais vosotros a casos así.
Por un stratos menos tenso

bnl

Quiza te sirva el patron observador
http://www.dofactory.com/Patterns/PatternObserver.aspx

La idea es que cada clase se registra como observador de una clase y esta al cambiar notifica a todos los observadores que ha cambiado.
Mi web: http://www.brausoft.com/
No sabían que era imposible, así que lo hicieron.

tamat

el problema que tiene el observador es lo que ya comenté, que obliga a cada clase "observable" a tener una lista de "observadores" y en mi caso sería muchisimo overhead, busco algo externo a la clase.
Por un stratos menos tenso

tamat

Empiezo a pensar que tengo dudas muy raras. Ya me ha pasado otras veces pero cuando mi pregunta no es de librerias o algoritmos sino de ingenieria del software la gente no suele responder. Debo ser el unico al que le interesan esos temas. :/
Por un stratos menos tenso

bnl

Se me ocurre que podrias llevar la lista de observadores a una clase externa  llamada GestorDeObservacion por ejemplo. Realmente seria lo mismo pero llevando la mayoria del código a otra clase.

Quiza podrias implementarlo utilizando handlers y que el cliente pregunte antes de usarlo si el handler sigue siendo valido.
Mi web: http://www.brausoft.com/
No sabían que era imposible, así que lo hicieron.

zupervaca

El sistema nativo de windows tiene una funcion que se llama "IsWindow" o algo asi, lo que hace windows es tener una lista, tabla hash o llamalo X con todas las ventanas existentes, siempre que quieras saber si un puntero a una ventana es valido llamarias a esta funcion, usando una tabla hash y el valor de direccion del puntero no consume velocidad alguna.
No obstante uses este u otro sistema, el acceso a una lista secuencial o enumerador de todas las ventanas creo que seria necesario.

Otro sistema que puedes hacer es uno de eventos, en el que puedas agragar objetos que recibiran los eventos de la ventana aparte de que esta tambien los va a recibir, asi puedes hacer que una ventana reciba en una funcion especial los eventos de otra ventana, algo asi como el sistema de eventos del c-sharp. Ten en cuenta que este sistema tiene un pequeño problema, y es que cuando la ventana B recibe los eventos de A y B es destruida A tiene que eliminar de la lista de eventos a B, es decir, A tendria una lista de las ventanas de las que recibe los eventos para que al destruirse esta lo notificara.

En conclusion, los dos sistemas son buenos, el primero es muy rapido, pero siempre tienes que andar comprobando que las ventanas sean validas, el segundo es algo mas lioso al programador, pero evita estar comprobando siempre si la ventana es valida.

Buffon

Cita de: "tamat"Empiezo a pensar que tengo dudas muy raras. Ya me ha pasado otras veces pero cuando mi pregunta no es de librerias o algoritmos sino de ingenieria del software la gente no suele responder. Debo ser el unico al que le interesan esos temas. :/

El problema no es tan sencillo.

librerias : se usa un par de busquedas en google, a lo sumo unas cuantas y si se saca algo en claro o se ha usado ya, se responde.

Ingenieria de software (requisitos) : no es tan sencillo como buscar en el google, sino que tienes que plantear la solución sin tener en cuenta todo lo que habias hecho ya.

Para esto último mi profesor de Ingenieria de Software lo tenía muy claro, cuando haces un estudio de requisitos, realizas el modelo conceptual de datos, haces el modelo de comportamento, etc etc etc yen un futuro o presente te das cuenta que necesitabas otro tipo de funcionalidad para algo en concreto, lo mejor era borrón y cuenta nueva ^^.

Es una putada realizar todo el camino de nuevo, pero te enseña a adoptar nuevos metodos de abstracción :)

PD1: Ahora mismo estoy en la hora de comer en el curro y cuando llegué a casa no me acordaré, pero la idea de bnl no está mal.

PD2: Hace más meses que cuaterniones tiene un protón que no posteo >.< !!!!!!

tamat

Na, si soy consciente de que la ingenieria del software es un terreno borroso en el que cada uno puede tener una visión distinta de las cosas, pero me parece enriquecedor compartir esas soluciones personales que aplicamos a aspectos genericos del codigo y que nos agilizan las cosas.

Al final lo que he hecho es mejorar mi clase Organizer, toda clase que herede de ella pasa a tener un contador de instancias y algunas features más que son interesantes. Además hace que la clase implemente un método llamado Exist(T*) que sirve para preguntar si esa instancia todavía es valida.

La verdad es que la clase Organizer la he ido mejorando conforme lo necesitaba y ahora medio framework hereda de ella, soy consciente de que tiene un overhead pero me simplifica tanto hacer algunas tareas.

De todo esto lo que veo es que tener unas pocas clases en templates, bien programadas y bastante genericas es una gran ayuda para resolver ciertos problemas que se dan constantemente cuando tienes un código un poco grande.
Por un stratos menos tenso

CoLSoN2

tamat, también piensa que para responderte a una pregunta específica de como cambiar o alterar una pequeña parte de tu arquitectura, los que no la conozcan (todos menos tú) van algo perdidos. Yo por ejemplo no tengo ese problema a la hora de crear diálogos procedurales (y no procedurales, aunque de estos no suelo destruír), y supongo que es por la forma que tengo de trabajar con mis widgets.

Mi sistema de GUI está organizado tal que así:

- Widgets: se definen jerárquicamente en archivos XML externos. Los estilos (su apariencia) también se define externamente en otros XML, de modo que sólo se definen sus características únicas: un nombre (id), posición y tamaño, etc.
- Widget Manager: algo así como el scene graph. Contiene una lista de los widgets a renderizar ordenador por Z, y después de renderizar/actualizar cada uno también lo hace con sus hijos. También se ocupa de delegar los eventos (MouseDown, MouseMove, etc.) a quien pertoque.
- Gui Manager: es el que se ocupa de cargar los XML y de mantener las instancias que corresponden a cada widget (porque WidgetManager añade y quita según interese). Además, también tiene una pila de GuiStates, que son los que reciben los eventos.
- Gui State: es una clase con método virtual (vacío, pero no puro) para cada evento de GUI posible: onButtonDown, onButtonPress, onTextInputChange, etc. la idea es que luego se crea una subclase de esta para cada "estado" de la GUI que quieras e implementas la respuesta a los eventos que te interese, por ejemplo:


class MainMenuState : public GuiState
{
virtual void OnButtonPress(Button* theButton)
{
if (theButton->GetName() == "Play")
 GUI_MGR->PushState(new PlayState());
else if (theButton->GetName() == "Options")
 GUI_MGR->PushState(new OptionsState());
// etc..
}
};


Y si quiero mostrar un widget en pantalla sería algo así:

WIDGET_MGR->PushWidget(GUI_MGR->GetWidget("Mainmenu/PlayButton")[, antesDeOtroWidget]);
Manuel F. Lara
Descargar juegos indie  - blog sobre juegos indie y casual
El Desarrollo Personal.com  - blog sobre productividad, motivación y espíritu emprendedor

tamat

Entiendo que la gente no puede conocer por completo mi sistema, pero me pareció una pregunta bastante específica, tal vez algo mal formulada.

Se podría resumir en: Como controlas que algo a lo que apuntas no ha sido destruido ya? Aplicado al caso de un GUI en el que un dialog podria ser destruido por el usuario. ¿Como te aseguras?

Sobre tu estructura de GUI es calcada a la mia y supongo que a la de muchos otros. Un SceneGraph 2D de widgets en el que los mensajes se propagan en profundidad.
Por un stratos menos tenso

Zaelsius

Cita de: "tamat"Como controlas que algo a lo que apuntas no ha sido destruido ya? Aplicado al caso de un GUI en el que un dialog podria ser destruido por el usuario. ¿Como te aseguras?

¿Por qué no obtienes el puntero al diálogo/widget del "GUI manager" en todos los métodos que jueguen con él?

Copiando el estilo de Colson
CitarWidget* w = GUI_MGR->GetWidget("Mainmenu/Mi_dialogo")
if ( w ) /*hacer_algo_con_w*/

Mientras que no se acceda a la GUI concurrentemente, esa sería una posible solución. Quien dice devolver un puntero, dice comprobar que un handle sigue siendo válido, o cualquier otra cosa. O sea, no te guardes el nunca el puntero al widget, sino una referencia(cadena en este caso) cuya valided puedas comprobar siempre antes de usar. Aunque creo que esto mismo ya se ha dicho más arriba..

tamat

Pero si la solucion ya la tengo, como ya dije no busco una solución, tan solo sondeaba para ver diferentes soluciones. Yo ahora tengo un contenedor estático de instancias en la clase widget que me permite preguntar a la propia clase si el widget aun existe.
Por un stratos menos tenso






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.