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

[SOLUCIONADO] Qt.QTableView. Varias dudas

Estas en el tema de Qt.QTableView. Varias dudas en el foro de C/C++ en Foros del Web. Hola de nuevo: Estaba trasteando de nuevo (es lo malo de retomar proyectos después de un año, aunque por otro lado uno se acerca con ...
  #1 (permalink)  
Antiguo 12/09/2016, 04:27
 
Fecha de Ingreso: septiembre-2010
Mensajes: 494
Antigüedad: 13 años, 6 meses
Puntos: 10
Qt.QTableView. Varias dudas

Hola de nuevo:

Estaba trasteando de nuevo (es lo malo de retomar proyectos después de un año, aunque por otro lado uno se acerca con otras perspectivas y hay cosas que ahora se ven muy claras) con QTableView, y me ha surgido una batería de dudas:

1.- Como quiero que haya algunos comportamientos especiales a la hora de manejar el tabulador y cursores, entiendo que tengo que manejar esas teclas con eventos del teclado, lo que me obliga a hacer uso de la función installEventFilter() para la tabla.
Hasta ahí bien, sin embargo ahora me encuentro que la tecla F2 ya no activa el modo de edición, y no sé cómo hacer para que vuelva a tener esa funcionalidad.
Por otro lado, me gustaría que la tecla Supr eliminara la fila entera si ésta está seleccionada, o solo el contenido de la celda actual. No veo en QTableView ni en QAbstractItemView ninguna función que indique si hay una fila seleccionada.

2.- Me gustaría que cuando cambiase el contenido de una celda se activase una función o señal que llamase a una función que se encargara de hacer alguna función asociada (realmente sería actualizar el dato en la fuente original, más allá del modelo)
Mi intento ha sido crear un delegado, y dentro de la función createEditor(), a la hora de crear el widget de edición, añadir una señal, algo así como:

Código C++:
Ver original
  1. class DelegadoCiudades : public QStyledItemDelegate
  2. {
  3.  
  4. public:
  5.     DelegadoCiudades(QObject* parent);
  6.     QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem&option, const QModelIndex&index) const;
  7.     void setEditorData(QWidget * editor, const QModelIndex&index)const;
  8.     void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex&index) const;
  9.  
  10. public slots:
  11.     void CambiarAlgo(int n);
  12. };

Y luego en la función createEditor():
Código C++:
Ver original
  1. QWidget *DelegadoCiudades::createEditor(QWidget *parent,
  2.                                         const QStyleOptionViewItem &option,
  3.                                         const QModelIndex &index) const
  4. {
  5.     const QAbstractItemModel * model = index.model();
  6.     if (!model) return QStyledItemDelegate::createEditor(parent,option, index);
  7.     QComboBox * box = new QComboBox(parent);
  8.     box->setEditable(true);
  9.     box->setAutoCompletion(true);
  10.     box->setModel(const_cast<QAbstractItemModel* >(model));
  11.     box->setModelColumn(index.column());
  12.     box->installEventFilter(const_cast<DelegadoCiudades * >(this));
  13.     connect(box,SIGNAL(currentIndexChanged(int)),this,SLOT(CambiarAlgo(int)));//<--Aquí el invento
  14.     return box;
  15. }

Código C++:
Ver original
  1. void DelegadoCiudades::CambiarAlgo(int n)
  2. {
  3.     qDebug()<<"Cambiar Algo: "<<n;
  4.  
  5. }

Pero no me funciona la señal, cuando el editor (un QComboBox) cambia el índice me sale el error de que la función CambiarAlgo() no es un slot.

3.- Esta la pregunté hace un año, pero no fui capaz de resolver el tema incluso con la ayuda que recibí del foro (gracias @eferion )
El caso es que una de las columnas es un QComboBox donde se pide/muestra el sexo de una persona, pero en lugar de poner texto sale un pequeño icono de un niño o una niña (es para los sobrinos, je je). Pero para que me mantenga el índice actual cuando paso por esa celda en modo de edición, he de enviar junto al icono, el índice asociado, y entonces se me ve el icono junto a un número (0 niños, 1 niñas). Y me gustaría que no se viera el número pero que no se perdiera el índice.

Bueno, me ha salido un post largo y me explico como un libro cerrado, así que me disculpo de antemano.

Saludos
(voy a ver si consigo poner el ejemplo completo en github), si lo hago, actualizo el hilo
__________________
Mi calculadora en Qt
  #2 (permalink)  
Antiguo 12/09/2016, 04:40
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 6 meses
Puntos: 204
Respuesta: Qt.QTableView. Varias dudas

Cita:
Iniciado por dehm Ver Mensaje
ahora me encuentro que la tecla F2 ya no activa el modo de edición
Con eso ahora mismo no puedo ayudarte. Quiero decir, no se qué cambios has realizado por lo que no puedo deducir qué tienes que cambiar para que vuelva a funcionar.

Publicar el código del filtro de eventos así como de su uso sería un buen punto de partida.

Cita:
Iniciado por dehm Ver Mensaje
No veo en QTableView ni en QAbstractItemView ninguna función que indique si hay una fila seleccionada.
La selección corre a cargo de QItemSelectionModel. Mira en QTableView::selectionModel().

Cita:
Iniciado por dehm Ver Mensaje
Me gustaría que cuando cambiase el contenido de una celda se activase una función o señal que llamase a una función que se encargara de hacer alguna función asociada (realmente sería actualizar el dato en la fuente original, más allá del modelo)
El modelo tiene un método llamado setData que es llamado cuando se realizan cambios en el modelo... prueba a colocar ahí la lógica correspondiente.

Código C++:
Ver original
  1. bool Modelo::setData(const QModelIndex &index, const QVariant &value, int role)
  2. {
  3.   if( role == Qt::EditRole )
  4.     emit HaCambiadoElModelo();
  5. }

Cita:
Iniciado por dehm Ver Mensaje
El caso es que una de las columnas es un QComboBox donde se pide/muestra el sexo de una persona, pero en lugar de poner texto sale un pequeño icono de un niño o una niña (es para los sobrinos, je je). Pero para que me mantenga el índice actual cuando paso por esa celda en modo de edición, he de enviar junto al icono, el índice asociado, y entonces se me ve el icono junto a un número (0 niños, 1 niñas). Y me gustaría que no se viera el número pero que no se perdiera el índice.
Los modelos gestionan la información en base a roles. DisplayRole se llama cuando se quiere visualizar el contenido de la celda mientras que DecorationRole se usa para mostrar una imagen junto al contenido de la celda... por poner un par de ejemplos.

Siguiendo esa dinámica encuentras UserRole que sirve como punto de partida para definir roles personalizados. La idea es definir un rol personalizado para recuperar el identificador asociado a una imagen. La vista nunca va a preguntar por ese rol porque no sabe ni que existe ni tampoco qué hacer con el. Es un rol para tus usos propios:

Código C++:
Ver original
  1. const int ImageIndexRole = Qt::UserRole+1;
  2.  
  3. QVariant Modelo::data(const QModelIndex &index, int role) const
  4. {
  5.   switch( role )
  6.   {
  7.     case ImageIndexRole:
  8.       // Devuelves el índice de la imagen
  9.       break;
  10.    }
  11. }

Y para preguntar por este dato:

Código C++:
Ver original
  1. Modelo model;
  2. QModelIndex index = model.index(0,0);
  3. qDebug() << model->data(index,ImageIndexRole);

Un saludo.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.

Última edición por eferion; 12/09/2016 a las 04:53
  #3 (permalink)  
Antiguo 12/09/2016, 09:58
 
Fecha de Ingreso: septiembre-2010
Mensajes: 494
Antigüedad: 13 años, 6 meses
Puntos: 10
Respuesta: Qt.QTableView. Varias dudas

Hola eferion:

Bueno, pues el tema del borrado ya está resuelto, usando ahora el método selectionModel() de la tabla (el borrado de la celda no está implementado pero vamos, que la duda principal era que al pulsar la tecla hubiera dos comportamientos, en función de si está la fila seleccionada o no)

Voy ahora a corregir lo de los iconos.

Adjunto cómo tengo resuelto el filtro de eventos (todavía me peleo con github y la verdad es que cualquiera de estos ejemplillos es demasiado extenso para pegar aquí el código completo).

Código C++:
Ver original
  1. bool Widget::eventFilter(QObject *watched, QEvent *e)
  2. {
  3.     if (e->type() == QEvent::KeyPress)
  4.     {
  5.         QModelIndex indice = tabla->currentIndex();        
  6.         QKeyEvent *ke =static_cast<QKeyEvent*>(e);
  7.         switch (ke->key())
  8.         {
  9.         case (Qt::Key_F5):
  10.         {
  11.             modelo->insertRow(indice.row());
  12.             break;
  13.  
  14.         }
  15.         case (Qt::Key_Delete):
  16.         {          
  17.             if (tabla->selectionModel()->isRowSelected(indice.row(),QModelIndex()))
  18.             {
  19.                 modelo->removeRow(indice.row());
  20.             }
  21.             else
  22.             {
  23.                 qDebug()<<"Borrar celda";
  24.             }
  25.             break;
  26.         }
  27.         case (Qt::Key_Tab):
  28.         {          
  29.             QModelIndex ind;
  30.             if (indice.column() < modelo->columnCount(QModelIndex())-1)
  31.             {
  32.                 ind = modelo->index(indice.row(), indice.column()+1);
  33.             }
  34.             else if (indice.row() == modelo->rowCount(QModelIndex())-1
  35.                      && indice.column() == modelo->columnCount(QModelIndex())-1
  36.                      && !NombreVacio())
  37.             {
  38.                 modelo->insertRow(modelo->rowCount(QModelIndex()));
  39.                 ind = modelo->index(indice.row()+1,0);
  40.  
  41.             }
  42.             else if (indice.row() == modelo->rowCount(QModelIndex())-1
  43.                      && indice.column() == modelo->columnCount(QModelIndex())-1
  44.                      && NombreVacio())
  45.             {
  46.                 ind = modelo->index(indice.row(),indice.column());
  47.             }
  48.             else if (indice.column() == modelo->columnCount(QModelIndex())-1)
  49.             {
  50.                 ind = modelo->index(indice.row()+1,0);
  51.             }
  52.             tabla->setCurrentIndex(ind);
  53.             break;
  54.         }
  55.         case (Qt::Key_Up):
  56.         {
  57.             if (indice.row()>0)
  58.             {
  59.                 QModelIndex ind = modelo->index(indice.row()-1,indice.column(), QModelIndex());
  60.                 tabla->setCurrentIndex(ind);
  61.             }
  62.             break;
  63.         }
  64.         case (Qt::Key_Down):
  65.         {
  66.             if (indice.row() < modelo->rowCount(QModelIndex())-1)
  67.             {
  68.                 QModelIndex ind = modelo->index(indice.row()+1,indice.column(), QModelIndex());
  69.                 tabla->setCurrentIndex(ind);
  70.             }
  71.             else if (indice.row() == modelo->rowCount(QModelIndex())-1 && !NombreVacio())
  72.             {
  73.                 modelo->insertRow(modelo->rowCount(QModelIndex()));
  74.                 QModelIndex ind = modelo->index(indice.row()+1,indice.column(), QModelIndex());
  75.                 tabla->setCurrentIndex(ind);                
  76.             }
  77.             break;
  78.         }
  79.         case (Qt::Key_Left):
  80.         {
  81.             if (indice.column()>0)
  82.             {
  83.                 QModelIndex ind = modelo->index(indice.row(),indice.column()-1, QModelIndex());
  84.                 tabla->setCurrentIndex(ind);
  85.             }
  86.             break;
  87.         }
  88.         case (Qt::Key_Right):
  89.         {
  90.             if (indice.column() < modelo->columnCount(QModelIndex())-1)
  91.             {
  92.                 QModelIndex ind = modelo->index(indice.row(),indice.column()+1, QModelIndex());
  93.                 tabla->setCurrentIndex(ind);
  94.             }
  95.             break;
  96.         }
  97.         case (Qt::Key_F2):
  98.         {
  99.             qDebug()<<"Editar";
  100.             break;
  101.         }
  102.         default:
  103.         {
  104.             break;
  105.         }
  106.         }
  107.         return true;
  108.     }
  109.     return QWidget::eventFilter(watched, e);
  110. }

La idea es que si estoy situado en la última fila y le doy a la tecla hacia abajo, o estoy situado en la última fila y ultima columna, y le doy al tabulador, se cree una fila vacía que permita que sea rellenada. Pero si esa fila no tiene al menos el nombre relleno, no se seguirán creando más filas vacías al final.
Por otro lado, si lo que queremos es insertar una fila en cualquier otro sitio, se pulsaría la tecla F5.
__________________
Mi calculadora en Qt
  #4 (permalink)  
Antiguo 12/09/2016, 14:17
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 6 meses
Puntos: 204
Respuesta: Qt.QTableView. Varias dudas

El filtro de eventos debería retornar false para las teclas no procesadas. Tal y como está implementado tu filtro hará que qt entienda que tu filtro proceda todas las teclas. El efecto será que no le llegarán teclas a la tabla.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #5 (permalink)  
Antiguo 14/09/2016, 02:33
 
Fecha de Ingreso: septiembre-2010
Mensajes: 494
Antigüedad: 13 años, 6 meses
Puntos: 10
Respuesta: Qt.QTableView. Varias dudas

Cita:
Iniciado por eferion Ver Mensaje
El filtro de eventos debería retornar false para las teclas no procesadas. Tal y como está implementado tu filtro hará que qt entienda que tu filtro proceda todas las teclas. El efecto será que no le llegarán teclas a la tabla.
Vaya metedura de pata la mía. Así podía estar definiendo todas y cada una de las teclas que quería que tuvieran efecto en la tabla!
__________________
Mi calculadora en Qt
  #6 (permalink)  
Antiguo 14/09/2016, 02:55
 
Fecha de Ingreso: septiembre-2010
Mensajes: 494
Antigüedad: 13 años, 6 meses
Puntos: 10
Respuesta: Qt.QTableView. Varias dudas

Bueno, sigo con otra pega, que no sabía si ponerla en hilo aparte, pero bueno, como ha surgido a raíz de este ejercicio, la pongo aquí.

La cosa viene por el tema de no tener los iconos de la tabla duplicados, y que en cualquier parte del programa se acceda a una única instancia de ellos*. Así que he intentado implementar una clase con el patrón Singleton. Cuando hago ejemplos con la clase sola no tengo problemas, pero cuando intento usar un miembro de esa clase dentro de otra, me salen dos errores:
1.- Que la instancia de la clase no está inicializada
2.- Que el constructor copia es privado, así como la sobrecarga del operador =

Esta es la implementación (típica y copiada de las muchas que hay):

Código C++:
Ver original
  1. #include <QIcon>
  2.  
  3.  
  4. class IconoSexo
  5. {
  6.  
  7. private:
  8.      IconoSexo();
  9.      ~IconoSexo();
  10.     IconoSexo(const IconoSexo& I);
  11.     const IconoSexo& operator=(const IconoSexo& I);
  12.     QIcon imagen[2];
  13.  
  14.  
  15. public:
  16.     static IconoSexo& getIcon();
  17.     int male();
  18.     int female();
  19.  
  20. };



Código C++:
Ver original
  1. #include "iconsexo.h"
  2.  
  3. IconoSexo::IconoSexo()
  4. {
  5.     icono[0].addFile(QStringLiteral(":./iconos/niño.png"), QSize(), QIcon::Normal, QIcon::Off);
  6.     icono[1].addFile(QStringLiteral(":./iconos/niña.png"), QSize(), QIcon::Normal, QIcon::Off);
  7. }
  8.  
  9. IconoSexo::~IconoSexo()
  10. {
  11.  
  12. }
  13.  
  14. IconoSexo& IconoSexo::getIcon()
  15. {
  16.     static IconoSexo instance;
  17.     return instance;
  18. }
  19.  
  20. int IconoSexo::male()
  21. {
  22.     return imagen[0];
  23. }
  24.  
  25. int IconoSexo::female()
  26. {
  27.     return imagen[1];
  28. }

Y ahora intento hacer uso de ellos, por ejemplo en el modelo:

mimodelo.h:

Código C++:
Ver original
  1. class MiModel : public QAbstractTableModel
  2. {
  3.     //Q_OBJECT
  4.  
  5. public:
  6.     MiModel(QObject *parent=0);
  7.     int rowCount(const QModelIndex &parent)const;
  8.     int columnCount(const QModelIndex &parent)const;
  9.     QVariant headerData(int section, Qt::Orientation orientation, int role)const;
  10.     QVariant data(const QModelIndex &index, int role)const;
  11.     Qt::ItemFlags flags(const QModelIndex&index) const;
  12.     bool setData(const QModelIndex &index, const QVariant &value, int role);
  13.     bool insertRows(int row, int count, const QModelIndex &parent);
  14.     bool removeRows(int row,int count, const QModelIndex&parent);
  15.  
  16.     void rellenarLista();
  17.  
  18. signals:
  19.     void HaCambiadoElModelo(const QModelIndex &index, const QVariant &value);
  20.  
  21. private:
  22.  
  23.     const int ImageIndexRole = Qt::UserRole+1;
  24.     QList<QStringList>lista;
  25.     IconoSexo &icono;
  26. };
Código C++:
Ver original
  1. MiModel::MiModel(QObject *parent):QAbstractTableModel(parent)
  2. {
  3.     icono = IconoSexo::getIcon();
  4.     rellenarLista();
  5. }

Y aquí aparece el problema

*sugerencia de eferion en este otro hilo que abrí, que ahora he remirado y que ya estaba preguntando muchas de las cosas que pregunto ahora, y que encima veo que hace un año sabía más que ahora :(
http://www.forosdelweb.com/f96/qt-de...strar-1123072/
__________________
Mi calculadora en Qt

Última edición por dehm; 14/09/2016 a las 02:58 Razón: añadir la definicion de la clase MiModel
  #7 (permalink)  
Antiguo 14/09/2016, 03:14
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 6 meses
Puntos: 204
Respuesta: Qt.QTableView. Varias dudas

Código C++:
Ver original
  1. class IconoSexo
  2. {
  3.   public:
  4.     static IconoSexo& getIcon();
  5.     int male();
  6.     int female();
  7.  
  8. };

Con esa interfaz es imposible recuperar los iconos ya que no hay ningún método público que devuelva un QIcon.

Por otro lado es poco práctico tener un método exclusivo para cada icono a devolver. En su lugar es mejor declarar un enumerado:

Código C++:
Ver original
  1. enum class IconosSexo
  2. {
  3.   Undefined,
  4.   Male,
  5.   Female
  6. };
  7.  
  8. class IconoSexo
  9. {
  10.   public:
  11.     static IconoSexo& getIcon();
  12.  
  13.     QIcon GetIcon(IconosSexo tipo);
  14. };

Aunque quizás sería más adecuado disponer de un único reservorio de iconos en vez de ir creando clases como si fuesen champiñones. Además para este uso no veo necesario crear un singletone. A mi modo de ver es más práctico tener una clase estática.

Código C++:
Ver original
  1. enum IconType
  2. {
  3.   Undefined,
  4.   Male,
  5.   Female,
  6.   AnotherOne,
  7. };
  8.  
  9. class IconWareHouse
  10. {
  11.   public:
  12.     static QIcon GetIcon(IconType type)
  13.     {
  14.       auto it = _icons.find(type);
  15.       if( it == _icons.end() )
  16.       {
  17.         // algoritmo para cargar el icono
  18.         // ...
  19.  
  20.         // Se añade el icono a la caché
  21.         it = _icons.insert(std::make_pair(type,icon));
  22.       }
  23.  
  24.       return it->second;
  25.     }
  26.  
  27.   private:
  28.  
  29.     static std::map<IconType,QIcon> _icons;
  30. };

En cuanto al fallo que comentas al usar el singletone, el problema es que estás intentando hacer una copia de la clase, cosa que al ser singleton no está permitido.

Deberías recuperar una referencia en ese caso.

Eso sí, nota que las variables creadas como referencia únicamente se pueden asignar una vez y que la misma ha de realizarse en la creación de la variable. Necesitarías algo así:

Código C++:
Ver original
  1. class MiModel
  2. {
  3.   IconosSexo& icono;
  4.  
  5.     MiModel::MiModel(QObject *parent):QAbstractTableModel(parent)
  6.       : icono(IconoSexo::getIcon())
  7.     {
  8.         rellenarLista();
  9.     }
  10. };

Aunque quizás lo más recomendable sería crear una variable local cuando la necesites:

Código C++:
Ver original
  1. void MiModel::rellenarLista()
  2. {
  3.   auto& icon = IconoSexo::getIcon();
  4.   // ...
  5. }

Todo esto suponiendo que no optas por convertir el repositorio de iconos en una clase estática... en ese caso no será necesario almacenar referencias en ningún sitio.

PD.: También podrías almacenar un puntero a la instancia, aunque no es una acción recomendable:

Código C++:
Ver original
  1. IconoSexo* ptr = &IconoSexo::getIcon();

Un saludo.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #8 (permalink)  
Antiguo 15/09/2016, 12:16
 
Fecha de Ingreso: septiembre-2010
Mensajes: 494
Antigüedad: 13 años, 6 meses
Puntos: 10
Respuesta: Qt.QTableView. Varias dudas

Cita:
Hola eferion:

Con esa interfaz es imposible recuperar los iconos ya que no hay ningún método público que devuelva un QIcon.
La verdad es que las pruebas las hago en CodeBlocks, y para no andar configurándolo para que funcione con Qt, la clase que estaba haciendo devolvía un int en lugar de un QIcon, suficiente para mis pruebas. Luego he intentado adaptarla en el mensaje y se me pasó corregir eso

Pero bueno, al lío. La cosa es que no he pillado la idea de la clase que planteas. Es decir, estas líneas, qué han de hacer?:
Código C++:
Ver original
  1. if( it == _icons.end() )
  2.             {
  3.             // algoritmo para cargar el icono
  4.             // ...
  5.  
  6.             // Se añade el icono a la caché
  7.             it = _icons.insert(std::make_pair(type,icon));

Yo por ahora he hecho esto, pero creo que no es para nada la idea que me estás planteando:

Código C++:
Ver original
  1. #include <iostream>
  2. #include <map>
  3.  
  4. using namespace std;
  5.  
  6. enum class Sexo
  7. {
  8.     undefined, male, female
  9. };
  10.  
  11. std::map<Sexo,string>init()
  12. {
  13.     std::map<Sexo,string>temp;
  14.     temp.insert(std::pair<Sexo, string>(Sexo::undefined,"No definido"));
  15.     temp.insert(std::pair<Sexo, string>(Sexo::male,"Niño"));
  16.     temp.insert(std::pair<Sexo, string>(Sexo::female,"Niña"));
  17.     return temp;
  18. }
  19.  
  20. class IconoWareHouse
  21. {
  22.     private:
  23.         static std::map<Sexo,string>_icons;
  24.  
  25.     public:
  26.         IconoWareHouse() {}
  27.         static string GetIcon(Sexo type)
  28.         {
  29.             auto it = _icons.find(type);
  30.             cout<<&it->second<<endl;//compruebo que es la misma variable
  31.             if( it == _icons.end() )
  32.             {
  33.             // algoritmo para cargar el icono
  34.             // ...
  35.  
  36.             // Se añade el icono a la caché
  37.             //it = _icons.insert(std::make_pair(type,icon));
  38.             }
  39.             cout<<(int)it->first<<endl;
  40.             return it->second;
  41.         }
  42. };
  43.  
  44. std::map<Sexo,string> IconoWareHouse::_icons(init());
  45.  
  46. //Funcion principal
  47. int main()
  48. {
  49.     IconoWareHouse I;
  50.     cout<<I.GetIcon(Sexo::female)<<endl;
  51.     IconoWareHouse II;
  52.     cout<<II.GetIcon(Sexo::female)<<endl;
  53.  
  54.     return 0;
  55. }

Como ves, en este caso he sustituido el
__________________
Mi calculadora en Qt
  #9 (permalink)  
Antiguo 16/09/2016, 01:11
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 6 meses
Puntos: 204
Respuesta: Qt.QTableView. Varias dudas

Cita:
Iniciado por dehm Ver Mensaje
La cosa es que no he pillado la idea de la clase que planteas. Es decir, estas líneas, qué han de hacer?:
Código C++:
Ver original
  1. if( it == _icons.end() )
  2. {
  3.   // algoritmo para cargar el icono
  4.   // ...
  5.  
  6.   // Se añade el icono a la caché
  7.   it = _icons.insert(std::make_pair(type,icon));
  8. }
se supone que la clase que actua como proveedor de iconos debe inicializar la colección en algún momento.

La colección puedes inicializarla bajo demanda o completa del tirón y cada opción se programa de una forma diferente.

En el caso de cargar todos los iconos de una vez podría ser algo tal que (aprovechando el código que has hecho):

Código C++:
Ver original
  1. enum class Sexo
  2. {
  3.     undefined, male, female
  4. };
  5.  
  6. class IconoWareHouse
  7. {
  8.     // Clase estática. No debe tener constructores disponibles
  9.     IconoWareHouse() = delete;
  10.  
  11.   public:
  12.     static std::string GetIcon(Sexo type)
  13.     {
  14.       auto it = _icons.find(type);
  15.  
  16.       if( it == _icons.end() )
  17.         it = _icons.find(Sexo::undefined);
  18.  
  19.       return it->second;
  20.     }
  21.  
  22.   private:
  23.     static std::map<Sexo,std::string>_icons;
  24.  
  25.     static decltype(_icons) InitMap()
  26.     {
  27.       // Opción con inicializadores de lista
  28.       return decltype(_icons){ std::make_pair(Sexo::undefined,"error"),
  29.                                std::make_pair(Sexo::male,"niño"),
  30.                                std::make_pair(Sexo::female,"niña") };
  31.     }
  32. };
  33.  
  34. std::map<Sexo,string> IconoWareHouse::_icons(InitMap());

Nota el uso de decltype para evitar repetir todo el rato la declaración del mapa. Piensa que no suele ser adecuado repetir un tipo cada dos por tres porque luego al intentar portar la solución a Qt te obliga a hacer demasiados cambios.

También puedes usar typedef o using (typedef sirve para estándares anteriores a C++11):



Código C++:
Ver original
  1. class IconoWareHouse
  2. {
  3.     // Clase estática. No debe tener constructores disponibles
  4.     IconoWareHouse() = delete;
  5.  
  6.   public:
  7.  
  8.     // Alias declarado con typedef
  9.     typedef std::map<Sexo,std::string> IconsMap;
  10.  
  11.     // Alias declarado con using
  12.     using IconsMap = std::map<Sexo,std::string>;
  13.  
  14.     static std::string GetIcon(Sexo type)
  15.     {
  16.       auto it = _icons.find(type);
  17.  
  18.       if( it == _icons.end() )
  19.         it = _icons.find(Sexo::undefined);
  20.  
  21.       return it->second;
  22.     }
  23.  
  24.   private:
  25.     static IconsMap_icons;
  26.  
  27.     static IconsMap InitMap()
  28.     {
  29.       // Opción con inicializadores de lista
  30.       return IconsMap{ std::make_pair(Sexo::undefined,"error"),
  31.                        std::make_pair(Sexo::male,"niño"),
  32.                        std::make_pair(Sexo::female,"niña") };
  33.     }
  34. };

Por cierto, nota que make_pair es más cómodo y limpio que tener que hacer una declaración explícita de pair cada vez que insertas un elemento en el mapa.

Un saludo.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #10 (permalink)  
Antiguo 16/09/2016, 04:41
 
Fecha de Ingreso: septiembre-2010
Mensajes: 494
Antigüedad: 13 años, 6 meses
Puntos: 10
Respuesta: Qt.QTableView. Varias dudas

Hola eferion:

Interesante el uso de decltype. Ya me has tenido un rato leyendo acerca del tema .Al final vas a conseguir que aprenda cosas del estandar C++11 en adelante!

Y si que es verdad que teniendo esas buenas prácticas bien interiorizadas, luego uno se facilita mucho la vida, realmente. Aún así he optado por la opción de "using" (no sabía que typedef ya estaba obsoleto).

Pero el caso es que el código que me has puesto no me compila. Me da dos errores.
1.-Al estar la función encargada de llenar el map dentro de la clase, al llamarla desde fuera me dice que:
Código C++:
Ver original
  1. std::map<Sexo,std::string> IconoWareHouse::_icons(initMap());//llamada a la función

error: cannot call member function ‘std::map<Sexo, std::basic_string<char> > IconoWareHouse::initMap()’ without object

Soslayo provisionalmente ese error sacando la función otra vez de la clase. Y ahora me da este error:
error: use of deleted function ‘IconoWareHouse::IconoWareHouse()’

Y ya puestos, si quito delete del constructor....
referencia a `IconoWareHouse::IconoWareHouse()' sin definir
__________________
Mi calculadora en Qt
  #11 (permalink)  
Antiguo 16/09/2016, 04:49
 
Fecha de Ingreso: septiembre-2010
Mensajes: 494
Antigüedad: 13 años, 6 meses
Puntos: 10
Respuesta: Qt.QTableView. Varias dudas

Perdón, los errores del constructor ya sé que son debidos a que no he de crear ningún objeto del tipo IconoWareHouse, sino sólo llamar a los miembros estáticos, que no pertenecen a ninguna instancia de la clase.

Eso ya lo he arreglado.(quiero decir que no instancio la clase, sino que sólo llamo al método)
Esto:
Código C++:
Ver original
  1. std::cout<<IconoWareHouse::GetIcon(Sexo::female)<<std::endl;
en lugar de esto:

Código C++:
Ver original
  1. IconoWareHouse I;
  2.     std::cout<<I.GetIcon(Sexo::female)<<std::endl;
Ahora entiendo el por qué de usar el delete de forma expresa.

Pero sigo sin poder usar la función que rellena el map dentro de la clase. Sólo me funciona si es una función externa.
__________________
Mi calculadora en Qt
  #12 (permalink)  
Antiguo 16/09/2016, 05:10
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 6 meses
Puntos: 204
Respuesta: Qt.QTableView. Varias dudas

Cita:
Iniciado por dehm Ver Mensaje
Pero sigo sin poder usar la función que rellena el map dentro de la clase. Sólo me funciona si es una función externa.
Pon un ejemplo del código que reproduzca el problema :)
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #13 (permalink)  
Antiguo 16/09/2016, 05:19
 
Fecha de Ingreso: septiembre-2010
Mensajes: 494
Antigüedad: 13 años, 6 meses
Puntos: 10
Respuesta: Qt.QTableView. Varias dudas

Cita:
Iniciado por eferion Ver Mensaje
Pon un ejemplo del código que reproduzca el problema :)
Perdón, no lo había puesto porque prácticamente es una copia de lo que mas puesto:

Esto me funciona:
Código C++:
Ver original
  1. #include <iostream>
  2. #include <map>
  3.  
  4.  
  5. enum class Sexo
  6. {
  7.     undefined, male, female
  8. };
  9.  
  10. using IconsMap = std::map<Sexo,std::string>;
  11.  
  12. IconsMap initMap()
  13. {
  14.     return
  15.     {
  16.         std::make_pair(Sexo::undefined,"No definido"),
  17.         std::make_pair(Sexo::male,"Niño"),
  18.         std::make_pair(Sexo::female,"Niña")
  19.     };
  20. }
  21.  
  22. class IconoWareHouse
  23. {
  24.  
  25. private:
  26.     static IconsMap _icons;
  27.  
  28. public:
  29.     IconoWareHouse()=delete;//no debe haber constructor disponible al ser clase estática
  30.     static std::string GetIcon(Sexo type)
  31.     {
  32.         auto it = _icons.find(type);
  33.         if(it == _icons.end())
  34.         {
  35.             it = _icons.find(Sexo::undefined);
  36.         }
  37.         return it->second;
  38.     }
  39. };
  40.  
  41. IconsMap IconoWareHouse::_icons(initMap());
  42.  
  43.  
  44. int main()
  45. {
  46.     std::cout<<IconoWareHouse::GetIcon(Sexo::female)<<std::endl;
  47.     return 0;
  48. }

Pero esto no:
Código C++:
Ver original
  1. #include <iostream>
  2. #include <map>
  3.  
  4.  
  5. enum class Sexo
  6. {
  7.     undefined, male, female
  8. };
  9.  
  10. using IconsMap = std::map<Sexo,std::string>;
  11.  
  12. class IconoWareHouse
  13. {
  14.  
  15. private:
  16.     static IconsMap _icons;
  17.  
  18. public:
  19.     IconoWareHouse()=delete;//no debe haber constructor disponible al ser clase estática
  20.     static std::string GetIcon(Sexo type)
  21.     {
  22.         auto it = _icons.find(type);
  23.         if(it == _icons.end())
  24.         {
  25.             it = _icons.find(Sexo::undefined);
  26.         }
  27.         return it->second;
  28.     }
  29.     IconsMap initMap()
  30.     {
  31.         return
  32.         {
  33.             std::make_pair(Sexo::undefined,"No definido"),
  34.             std::make_pair(Sexo::male,"Niño"),
  35.             std::make_pair(Sexo::female,"Niña")
  36.         };
  37.     }
  38. };
  39.  
  40. IconsMap IconoWareHouse::_icons(initMap());
  41.  
  42.  
  43. int main()
  44. {
  45.     std::cout<<IconoWareHouse::GetIcon(Sexo::female)<<std::endl;
  46.     return 0;
  47. }

En este segundo caso me da este error:

error: cannot call member function ‘IconsMap IconoWareHouse::initMap()’ without object
__________________
Mi calculadora en Qt
  #14 (permalink)  
Antiguo 16/09/2016, 06:16
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 6 meses
Puntos: 204
Respuesta: Qt.QTableView. Varias dudas

El problema en el segundo caso es que InitMap no está etiquetado como estático, por lo que para llamarlo necesitarías disponer de una instancia ya creada de IconoWareHouse.

Prueba a ponerle static al método y verás como ya si funciona.

Por cierto, lo suyo es que ese método sea privado.

Un saludo.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #15 (permalink)  
Antiguo 16/09/2016, 08:58
 
Fecha de Ingreso: septiembre-2010
Mensajes: 494
Antigüedad: 13 años, 6 meses
Puntos: 10
Respuesta: Qt.QTableView. Varias dudas

Cita:
Iniciado por eferion Ver Mensaje
El problema en el segundo caso es que InitMap no está etiquetado como estático, por lo que para llamarlo necesitarías disponer de una instancia ya creada de IconoWareHouse.

Prueba a ponerle static al método y verás como ya si funciona.

Por cierto, lo suyo es que ese método sea privado.

Un saludo.
Los chicos del forosdelweb tendrían que ponerte un sueldo
Pues subtema solucionado. Ya he puesto el método static (y privado).
Cierro este paréntesis y voy a llevarme el tinglado a la QTableView.
Aunque sospecho que todavía tendré algún que otro problema, a ver si este fin de semana fuera capaz de resolverlo sólo. Espero no tener que molestarte de nuevo.
Saludos y gracias!
__________________
Mi calculadora en Qt
  #16 (permalink)  
Antiguo 16/09/2016, 15:02
 
Fecha de Ingreso: septiembre-2010
Mensajes: 494
Antigüedad: 13 años, 6 meses
Puntos: 10
Respuesta: Qt.QTableView. Varias dudas

Al final la cosa no esta tan clara.
Al crear la clase "bien", con elementos QIcon y ya dentro del proyecto en Qt, me arroja este error:
QPixmap: Must construct a QGuiApplication before a QPixmap

Por lo que veo en Google, se ve que un objeto de la clase Pixmap no puede tener vida fuera de una Applicatión, y esa es la causa del error.

Este es el código:

//h

Código C++:
Ver original
  1. #ifndef RECURSOS_H
  2. #define RECURSOS_H
  3.  
  4. #include <map>
  5. #include <QIcon>
  6.  
  7. enum class Sexo
  8. {
  9.     undefined, male, female
  10. };
  11.  
  12. using IconsMap = std::map<Sexo,QIcon>;
  13.  
  14. class RepoIconos
  15. {    
  16.  
  17. private:
  18.     static IconsMap _iconos;
  19.     static IconsMap initMap()
  20.     {
  21.         return
  22.         {
  23.             std::make_pair(Sexo::undefined, QIcon(QStringLiteral("../Primos/iconos/undefined.png"))),
  24.             std::make_pair(Sexo::male, QIcon(QStringLiteral("../Primos/iconos/niño.png"))),
  25.             std::make_pair(Sexo::female, QIcon(QStringLiteral("../Primos/iconos/niña.png")))
  26.         };
  27.     }
  28.  
  29.  
  30. public:
  31.     RepoIconos()=delete;//no debe haber constructor disponible al ser clase estática
  32.     static QIcon GetIcon(Sexo type)
  33.     {
  34.         auto it = _iconos.find(type);
  35.         if(it == _iconos.end())
  36.         {
  37.             it = _iconos.find(Sexo::undefined);
  38.         }
  39.         return it->second;
  40.     }
  41. };
  42.  
  43. namespace DatosGenerales
  44. {
  45.     enum Columnas{Nombre,Ciudad,Color,Sexo};
  46. }
  47.  
  48.  
  49. #endif // RECURSOS_H

Código C++:
Ver original
  1. //cpp
  2. #include "recursos.h"
  3.  
  4. IconsMap RepoIconos::_iconos(initMap());

¿Sugerencias?¿Debería abandonar este diseño?
__________________
Mi calculadora en Qt
  #17 (permalink)  
Antiguo 17/09/2016, 13:16
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 6 meses
Puntos: 204
Respuesta: Qt.QTableView. Varias dudas

Tienes que crear una aplicación gráfica para poder usar los QIcon.

Yo de ti crearía el proyecto desde el qt creator para que te aparezca ya configurado.

Un saludo
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #18 (permalink)  
Antiguo 18/09/2016, 00:39
 
Fecha de Ingreso: septiembre-2010
Mensajes: 494
Antigüedad: 13 años, 6 meses
Puntos: 10
Respuesta: Qt.QTableView. Varias dudas

Hola eferion:

La cosa es que el fichero de recursos lo añadí al proyecto de la tabla, desde qtcreator.

Al final lo he subido a sourceforge (sé que no es muy correcto usar estos servicios como almacenes personales de proyectos sin interés...en unos días lo borro)

https://sourceforge.net/projects/tabla-primos/

Si te apetece echarle un vistazo, aunque sólo sea para ver cómo está organizado el proyecto o si hay que tocar el archivo .pro, te lo agradeceré.
__________________
Mi calculadora en Qt
  #19 (permalink)  
Antiguo 19/09/2016, 01:22
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 6 meses
Puntos: 204
Respuesta: Qt.QTableView. Varias dudas

¿sería mucho pedir que incluyeses un fichero comprimido con todo el proyecto para no tener que bajar fichero a fichero? :)
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #20 (permalink)  
Antiguo 19/09/2016, 02:14
 
Fecha de Ingreso: septiembre-2010
Mensajes: 494
Antigüedad: 13 años, 6 meses
Puntos: 10
Respuesta: Qt.QTableView. Varias dudas

Debería haber un botón para clonar el proyecto al disco duro...estos de SF están anticuados

Bueno, pues ya está subido el zip. Si lo ves con un poco de detalle, verás que a las miles de barbaridades se le suma que no hay fuente de datos como tal, el modelo bebe directamente de una QStringList que no está respaldada por nada. Eso es porque la cosa empezó al revés (la tabla), y los datos son sólo una herramienta sólo para controlar la visualización de los mismos dentro de dicha tabla.

Bueno, pues saludos y gracias de nuevo!
__________________
Mi calculadora en Qt
  #21 (permalink)  
Antiguo 19/09/2016, 02:25
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 6 meses
Puntos: 204
Respuesta: Qt.QTableView. Varias dudas

vale, como suponía, el problema está en la inicialización de la clase estática:

Código C++:
Ver original
  1. IconsMap RepoIconos::_iconos(initMap());

Las clases estáticas se inicializan antes de ejecutar nada de código del main, luego con la inicialización que tienes actualmente se intentan cargar los iconos antes de tener inicializada la librería de Qt.

Solución: muy sencila.

1. Deja la inicialización vacía

Código C++:
Ver original
  1. IconsMap RepoIconos::_iconos;

2. Inicializa el mapa con el primer uso:

Código C++:
Ver original
  1. static QIcon GetIcon(Sexo type)
  2. {
  3.   if( _iconos.empty() )
  4.     _iconos = initMap();
  5.  
  6.   // ...
  7. }

Un saludo
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #22 (permalink)  
Antiguo 19/09/2016, 03:41
 
Fecha de Ingreso: septiembre-2010
Mensajes: 494
Antigüedad: 13 años, 6 meses
Puntos: 10
Respuesta: Qt.QTableView. Varias dudas

Perfecto, era eso.

Bueno, ahora sí que cierro el paréntesis de los iconos. A ver si soy capaz de sincronizarlos con los índices del QComboBox

Gracias de nuevo!
__________________
Mi calculadora en Qt
  #23 (permalink)  
Antiguo 06/10/2016, 11:01
 
Fecha de Ingreso: septiembre-2010
Mensajes: 494
Antigüedad: 13 años, 6 meses
Puntos: 10
Respuesta: Qt.QTableView. Varias dudas

Bueno, pues doy la tabla por terminada.

Mas o menos hace todo lo que estaba buscando. Sólo se me ha quedado la espinita de que el desplegable de ciudades no funciona con Tab la primera vez que se introduce una nueva ciudad.

Por otro lado, el diseño me ha obligado a usar por primera vez la palabra mutable, en la función void setModelData() const de uno de los delegados.

Pero bueno, creo que me ha quedado una cosa bastante flexible y fácilmente reutilizable para otra fuente de datos.

En fin, marco como solucionado, y aunque pensaba copiar el código aquí, es demasiado extenso, así que lo mantendré en sourceforge. https://sourceforge.net/projects/tabla-primos/

Gracias a todos, y en especial a eferion
__________________
Mi calculadora en Qt

Etiquetas: const, dudas, int
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:54.