Foros del Web » Programación para mayores de 30 ;) » C/C++ »

[SOLUCIONADO] Qt. Borrar el contenido de un Widget de forma efectiva

Estas en el tema de Qt. Borrar el contenido de un Widget de forma efectiva en el foro de C/C++ en Foros del Web. Bueno, a ver si consigo describir el problema de forma mas efectiva que en el título: Tengo un QMainWindow que en el centro tiene un ...
  #1 (permalink)  
Antiguo 27/03/2015, 05:52
 
Fecha de Ingreso: septiembre-2010
Mensajes: 494
Antigüedad: 13 años, 7 meses
Puntos: 10
Qt. Borrar el contenido de un Widget de forma efectiva

Bueno, a ver si consigo describir el problema de forma mas efectiva que en el título:

Tengo un QMainWindow que en el centro tiene un Widget en blanco. Este está creado en el Designer.

El contenido del Widget está en una clase aparte, y la composición está creada a mano.

La idea es: (no sé si aquí ya estaré empezando a pifiarla)

Tengo un puntero a la clase donde está contenida la información del contenido (y la lógica y demás)

Código C++:
Ver original
  1. Datos* datos;

En el constructor, se desarrollan todos los widgets y demás, quedando un layout externo que engloba todo el tinglado, y que queda ligado al widget vacío del QMainWindow.

Código C++:
Ver original
  1. Datos::Datos (QWidget *parent):QWidget(parent)
  2. {
  3. //toda la composición y demás cosas del constructor
  4.  
  5. mainLayout= new QVBoxLayout(parent); //el layout exterior
  6. }

Y ahora la llamada desde QMainWindow:
Código C++:
Ver original
  1. if (Contenido)
  2.         {
  3.             delete Contenido;
  4.         }
  5.         Contenido= new Datos(ui->Lienzo); //el widget en blanco creado en el designer

El problema que tengo, y esta es la duda...probablemente mas de mal aprendiz de C++ que otra cosa es:

Si en la clase datos borro de forma explícita el lienzo exterior:
Código C++:
Ver original
  1. Datos::~Datos()
  2. {
  3.     --------------
  4.     delete mainLayout;
  5.     ----------------

El programa falla, entiendo que porque estoy intentando borrar dos veces el mainLayout.

Pero si no lo borro de manera expresa, cuando abro un fichero y luego quiero abrir otro, el programa me lanza un error diciendo que no puede añadir otro layout a ui->Lienzo porque ya hay uno existente.

En fin, ya sé que es un poco jaleoso lo que describo, pero como siempre, toda ayuda será bien recibida. Yo mientras voy a pegarme otro rato con esto, a ver si encuentro la solución

Saludos y gracias!
__________________
Mi calculadora en Qt
  #2 (permalink)  
Antiguo 27/03/2015, 06:35
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 7 meses
Puntos: 204
Respuesta: Qt. Borrar el contenido de un Widget de forma efectiva

QWidget tiene un sistema de borrado automático. Este mecanismo funciona de la siguiente forma: Cuando se elimina un QWidget, todos sus QWidget hijos son eliminados también.

Si borras un QWidget de forma manual, este widget se desligará de su widget "parent" antes de borrarse, de forma que el padre no se queda con punteros no válidos.

Fíjate en el detalle, un QWidget puede depender, o no, de otro QWidget... la gracia de esto es que un QLayout no hereda de QWidget, luego el padre de un QWidget no puede ser nunca un QLayout... sí puedes insertar un QWidget en un layout... pero esa acción no modifica la relación "parent".

Dicho esto, si tu tienes QWidget(1)->QLayout->QWidget(2) y borras QWidget(2), te vas a quedar con QWidget(1)->QLayout, y claro, Qt te dice que a un widget que ya tiene layout no puedes asignarle otro (aquí el segundo error ).

Sin embargo, si borras el layout, verás que éste no borra los widgets contenidos en el mismo (ojo, si los quita de la ventana... pero estos objetos siguen vivos)... así como tampoco eliminará sublayouts... te tendrás que encargar de eso de forma explícita so pena de quedarte con lagunas de memoria.

Con todo, dado que "Datos" es un widget, lo que uno esperaría encontrar es, bien un diseño realizado con el QtDesigner, o bien un código que trate de una composición de widgets que únicamente afecte al widget en cuestión y no al padre... ese "mainLayout" es como un puñetazo en la cara porque estás tocando la composición del padre... estás rompiendo toda la encapsulación con una sola línea.

Un Widget debe preocuparse únicamente de "su" contenido, no del contenido del padre.

Si, por contra, "Datos" no es un widget, no sería tampoco recomendable dejar a este widget la responsabilidad de manipular el layout principal del padre... ya que eso te limita a que el widget padre únicamente pueda contener la composición indicada en "Datos"... para eso haz la composición directamente en el padre y olvídate de "Datos".

Un saludo.
  #3 (permalink)  
Antiguo 27/03/2015, 11:35
 
Fecha de Ingreso: septiembre-2010
Mensajes: 494
Antigüedad: 13 años, 7 meses
Puntos: 10
Respuesta: Qt. Borrar el contenido de un Widget de forma efectiva

Cita:
Iniciado por eferion Ver Mensaje

Fíjate en el detalle, un QWidget puede depender, o no, de otro QWidget... la gracia de esto es que un QLayout no hereda de QWidget, luego el padre de un QWidget no puede ser nunca un QLayout... sí puedes insertar un QWidget en un layout... pero esa acción no modifica la relación "parent".
En un párrafo me has aclarado la duda que llevaba 2 días rumiando. Ahora entiendo mucho mejor muchas cosas que he estado viendo y trasteando desde ayer.
Cita:
Iniciado por eferion Ver Mensaje
Dicho esto, si tu tienes QWidget(1)->QLayout->QWidget(2) y borras QWidget(2), te vas a quedar con QWidget(1)->QLayout, y claro, Qt te dice que a un widget que ya tiene layout no puedes asignarle otro (aquí el segundo error ).

Sin embargo, si borras el layout, verás que éste no borra los widgets contenidos en el mismo (ojo, si los quita de la ventana... pero estos objetos siguen vivos)... así como tampoco eliminará sublayouts... te tendrás que encargar de eso de forma explícita so pena de quedarte con lagunas de memoria.
Esta parte sin embargo no me ha quedado muy clara.
Yo entiendo que tengo esto:
QWidget(1); //en el padre

Y cuando creo el objeto, en el constructor ligo el "mainlayout" al parent. Pero así ha de ser siempre, no?

mainLayout= new QVBoxLayout(parent); //el hijo

Que en definitiva me quedaría: QWidget(1)->mainLayout->QWidget(2)

Y entonces, al borrar el objeto Datos, por propagación, yo pensaba que borraría el mainLayout y de ahí para abajo, pero por lo que me dices eso no es así. Si lo he de hacer de forma manual, debería borrar los widgets que hay dentro de ese "mainLayout" y luego borrar el propio "mainLayout" ?


Cita:
Iniciado por eferion Ver Mensaje

Con todo, dado que "Datos" es un widget, lo que uno esperaría encontrar es, bien un diseño realizado con el QtDesigner, o bien un código que trate de una composición de widgets que únicamente afecte al widget en cuestión y no al padre... ese "mainLayout" es como un puñetazo en la cara porque estás tocando la composición del padre... estás rompiendo toda la encapsulación con una sola línea.

Un Widget debe preocuparse únicamente de "su" contenido, no del contenido del padre.

Si, por contra, "Datos" no es un widget, no sería tampoco recomendable dejar a este widget la responsabilidad de manipular el layout principal del padre... ya que eso te limita a que el widget padre únicamente pueda contener la composición indicada en "Datos"... para eso haz la composición directamente en el padre y olvídate de "Datos".

Un saludo.
Ciertamente, toda esta historia era un apaño para reciclar la clase que he usado para hacer pruebas modelo/vista/delegado, e insertarla en un QMainWindow a martillazos.
Pero claro, cuando he estado haciendo pruebas con las tablas y los delegados y demás, he metido todo a cascoporro en una clase, la fuente de datos, los delegados, la tabla, etc...y realmente es el momento de separar los datos de los widgets y hacer las cosas algo menos peor.

Gracias como siempre!!


Edito:

Realmente no había entendido bien la segunda parte de tu explicación. Ahora sí que lo tengo claro, y ya me funciona el ejemplo.
__________________
Mi calculadora en Qt

Última edición por dehm; 29/03/2015 a las 03:39

Etiquetas: contenido, forma, int, programa
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 17:58.