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

[SOLUCIONADO] QMenu, abrir multiples ventanas

Estas en el tema de QMenu, abrir multiples ventanas en el foro de C/C++ en Foros del Web. Hola Tengo un programa el cual tiene un QMainWindow en el que hay un QMenu, con bastantes opciones, muchas de ellas lo que hacen es ...
  #1 (permalink)  
Antiguo 08/05/2015, 03:37
Avatar de jc_moj  
Fecha de Ingreso: septiembre-2009
Ubicación: Andalucía
Mensajes: 137
Antigüedad: 15 años, 2 meses
Puntos: 12
QMenu, abrir multiples ventanas

Hola

Tengo un programa el cual tiene un QMainWindow en el que hay un QMenu, con bastantes opciones, muchas de ellas lo que hacen es abrir una ventana para que el usuario introduzca datos, algunas de las cuales incluso tengo que mirar el valor de retorno al cerrarse para hacer alguna acción en el QMainWindow.

El caso es que quiero "automatizar" todo esto un poco, por que no me gusta tener toda la clase llena de métodos que lo único que hagan es abrir una ventana.

Se me ha ocurrido una cosa, he usado la propiedad "whatsThis" de cada QAction para poner un número. Y he creado un método que me recorre todo el menú buscando todas las opciones y uso ese número como código para añadir cada una a un QSignalMapper.

Luego, en el SLOT recibo ese código y mediante un switch creo la ventana que corresponde. Funciona, pero no me termina de gustar. Para empezar, si creo una opción de menú nueva tengo que mirar para no repetir el numero y luego añadir la correspondiente opción al switch. Y claro, el switch pues va creciendo y es grande.

Mi pregunta es sencilla ¿Alguna idea alternativa? ¿Cómo lo hacéis vosotros?

Un saludo

Última edición por jc_moj; 08/05/2015 a las 03:39 Razón: Corregir ortografía :)
  #2 (permalink)  
Antiguo 08/05/2015, 04:09
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 10 años, 1 mes
Puntos: 204
Respuesta: QMenu, abrir multiples ventanas

Pues mira, yo te propongo una solución algo diferente.

Pasos a seguir:

1. Crea una función miembro en la ventana principal tal que:

Código C++:
Ver original
  1. class MainWindow : public QMainWindow
  2. {
  3.   private:
  4.     template< typename Class >
  5.     QDialog* NewWindow( )
  6.     {
  7.       return new Class( this );
  8.     }
  9. };

Este template nos va a permitir crear cualquier ventana que herede de QDialog. Ahora veremos cómo usarla.

2. Creamos un mapa que nos permita asociar los QAction. En este caso, cada QAction irá asociado a la llamada correcta a la función que hemos creado en el paso anterior. Esto lo conseguimos así:

Código C++:
Ver original
  1. #include <functional>
  2. #include <map>
  3.  
  4. class MainWindow
  5. {
  6.   private:
  7.     std::map< QAction*, std::function< QDialog*( MainWindow* ) > > _newWindows;
  8. };

Usamos std::function por legibilidad más que nada. El mapa anterior tiene como clave un QAction. El segundo parámetro es un puntero a una función miembro de MainWindow, con el siguiente prototipo: "QDialog* MainWindow::X( )".

3. Rellenamos el mapa. Esto lo suyo sería hacerlo en una función que se llame desde el constructor, para mantener la limpieza del código:

Código C++:
Ver original
  1. QAction* newAction = new QAction( "Test", this );
  2. connect( newAction, SIGNAL( triggered( ) ), this, SLOT( MenuTriggered( ) ) );
  3.  
  4. QMenu* menu = menuBar( )->addMenu( "File" );
  5. menu->addAction( newAction );
  6.  
  7. _newWindows[ newAction ] = &MainWindow::NewWindow< TestDialog >;

En el ejemplo estamos creando primero el QAction, por defecto, todos los QAction llamarán al slot MenuTriggered( ), ahí es donde terminaremos de obrar la magia. A continuación añadimos el QAction al menu. Finalmente añadimos una entrada en el mapa creado anteriormente. En este caso "TestDialog" es el nombre de un diálogo que he creado para la ocasión. Lo que estamos haciendo en esta última línea es devolver el puntero a una versión especializada de "NewWindow" que nos devolverá un objeto de tipo "TestDialog".

4. Para terminar, el código del slot. Este código después se puede ampliar para hacer comprobaciones o para añadir otro tipo de opciones:

Código C++:
Ver original
  1. void MainWindow::MenuTriggered( )
  2. {
  3.   auto it = _newWindows.find( dynamic_cast< QAction* >( sender( ) ) );
  4.   if( it != _newWindows.end( ) )
  5.   {
  6.     QDialog* dlg = it->second( this );
  7.     dlg->exec( );
  8.   }
  9. }

La función "sender" está presente en todos los QObject y almacena el objeto que ha generado la última señal... en nuestro caso el objeto en cuestión será el QAction sobre el que hayamos clickado. Una vez tenemos el objeto en cuestión, buscamos en el mapa para conocer cual es la función a la que debemos llamar... la llamamos y lanzamos la ventana que corresponda. Magia!!! jejejeje

Espero que te sirva esta solución.

Un saludo
  #3 (permalink)  
Antiguo 08/05/2015, 09:04
Avatar de jc_moj  
Fecha de Ingreso: septiembre-2009
Ubicación: Andalucía
Mensajes: 137
Antigüedad: 15 años, 2 meses
Puntos: 12
Respuesta: QMenu, abrir multiples ventanas

Que te gustan los templates XD

Sin duda me gusta, el código queda mucho más reducido y no tengo que preocuparme por el código de cada opción que yo antes añadía a cada QAction.

Me queda por ver que uso el valor de retorno de algunas ventanas para saber si tengo que actualizar algo.

Por cierto, ¿algún motivo especial para usar std::map y no QMap?

Saludos
  #4 (permalink)  
Antiguo 08/05/2015, 09:19
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 10 años, 1 mes
Puntos: 204
Respuesta: QMenu, abrir multiples ventanas

Cita:
Iniciado por jc_moj Ver Mensaje
Que te gustan los templates XD
Creo que bien usados pueden ser tremendamente útiles. Es una forma de delegar parte del trabajo en el compilador jejeje

Cita:
Iniciado por jc_moj Ver Mensaje
Me queda por ver que uso el valor de retorno de algunas ventanas para saber si tengo que actualizar algo.
Dado que el parent() de cada ventana es la ventana principal puedes aprovechar ese puntero para que la ventana le pase a la principal la información que necesite. Otra opción puede pasar por tener varios tipos de mapas, uno para cada tipo de retorno. Todo es cuestión de darle al coco jejeje.

Cita:
Iniciado por jc_moj Ver Mensaje
Por cierto, ¿algún motivo especial para usar std::map y no QMap?
La stl ha sido optimizada hasta la saciedad, mientras que los contenedores de Qt únicamente reciben mantenimiento por parte de los desarrolladores de Qt y sirven para sus propósitos. Si miras en internet verás que el rendimiento de los contenedores de la stl tiende a ser mejor.

Además, las clases de Qt suelen abusar del patrón pimpl, lo que impide observar el contenido de los contenedores en depuración.

Y, como tercer argumento, la stl se usa en casi cualquier librería externa de c++, mientras que el uso de los contenedores de Qt esta restringido a Qt.

Los contenedores de Qt los reservo para interactuar directamente con partes de Qt que hacen uso de dichos contenedores... Para todo lo demás prefiero la stl
  #5 (permalink)  
Antiguo 08/05/2015, 15:07
Avatar de jc_moj  
Fecha de Ingreso: septiembre-2009
Ubicación: Andalucía
Mensajes: 137
Antigüedad: 15 años, 2 meses
Puntos: 12
Respuesta: QMenu, abrir multiples ventanas

hola

Cita:
Iniciado por eferion Ver Mensaje
Dado que el parent() de cada ventana es la ventana principal puedes aprovechar ese puntero....
Pues al principio lo tenía así y luego lo cambié a comprobar el valor de retorno (no recuerdo porqué), total, lo único que hago es comprobar si se cerró la ventana con acept() y si es así llamar a un método, así que puedo volver a ponerlo como estaba.

Por cierto, una duda que siempre tengo, el cast, si mal no recuerdo, tenía que hacer un cast para poder usar los métodos de mi clase MainWindow y he aquí mi duda, nunca sé cual es el más apropiado, a ver si puedes "iluminarme" un poco sobre el tema.

Cita:
Iniciado por eferion Ver Mensaje
La stl ha sido optimizada hasta la saciedad, mientras que los contenedores de Qt únicamente ...
Tomo nota.

Un saludo
  #6 (permalink)  
Antiguo 08/05/2015, 17:06
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 10 años, 1 mes
Puntos: 204
Respuesta: QMenu, abrir multiples ventanas

Cita:
Iniciado por jc_moj Ver Mensaje
Por cierto, una duda que siempre tengo, el cast, si mal no recuerdo, tenía que hacer un cast para poder usar los métodos de mi clase MainWindow y he aquí mi duda, nunca sé cual es el más apropiado, a ver si puedes "iluminarme" un poco sobre el tema.
dynamic_cast: este cast se usa cuando hay polimorfismo. Realiza una conversión segura de una clase base a otra hija. Si la conversión no se puede realizar devolverá un puntero nulo. Si tienes una clase base A y dos clases hijas, B y C; en un puntero de tipo A puedes almacenar objetos de tipo A, B, y C. La única forma de saber si en el puntero A hay almacenado un objeto de tipo B o C es usando dynamic_cast.

static_cast: este cast se usa entre tipos compatibles, como una conversión de int a flota o viceversa. También se puede usar con polimorfismo. Si tu sabes, en base al ejemplo anterior, que lo que hay almacenado en un puntero de tipo A es un objeto de tipo B, puedes usar static_cast, que es mas ligero que dynamic_cast. Eso sí, como realmente lo que haya en A no sea un objeto de tipo C vete preparando el saco de errores porque lo vas a llenar.

reinterpret_cast: este cast es el más parecido al cast de c. Es como decirle al compilador... " se que esto que voy a hacer puede parecer una burrada, pero no te preocupes que se lo que me hago". Este cast es especialmente útil si, por ejemplo, tienes que convertir un puntero de void* en el tipo de datos que corresponda.

const_cast: este cast te permite eliminar el modificador const a un puntero. Este cast hay que usarlo con cuidado, ya que si el objeto apuntado ha sido creado como const, el resultado de la operación puede ser indeterminado. Una cosa es crear un objeto como const y otra es pasar un objeto no const como argumento constante... No se si me explico.

Si algo no te ha quedado claro te lo explico con mas detalle en otro momento, que con el móvil escribir código es un suplicio.

Un saludo
  #7 (permalink)  
Antiguo 09/05/2015, 11:16
Avatar de jc_moj  
Fecha de Ingreso: septiembre-2009
Ubicación: Andalucía
Mensajes: 137
Antigüedad: 15 años, 2 meses
Puntos: 12
Respuesta: QMenu, abrir multiples ventanas

Hola

Cita:
Iniciado por eferion Ver Mensaje
Si algo no te ha quedado claro te lo explico con mas detalle en otro momento, que con el móvil escribir código es un suplicio.
Creo que es la explicación más clara sobre cast que he leído, debería estar fijo al inicio

Tengo un serio problema con el inglés

Marco como solucionado, pues la consulta original fue resuelta.

Un saludo

Etiquetas: funcion, int, multiples, numero, programa, ventanas
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 13:52.