How to Use a QSqlQueryModel in QML/es: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 9: Line 9:
En este articulo, recorreré los pasos para configurar un modelo personalizado para ser usado desde QML derivado de QSqlQueryModel.
En este articulo, recorreré los pasos para configurar un modelo personalizado para ser usado desde QML derivado de QSqlQueryModel.


Quiero agradecer a &quot;Christophe Dumez&amp;quot;:http://cdumez.blogspot.com/ por su articulo &quot;How to use C++ list model in QML&amp;quot;:http://cdumez.blogspot.com/2010/11/how-to-use-c-list-model-in-qml.html.<br />Este articulo me permitió crear el siguiente ejemplo:
Quiero agradecer a "Christophe Dumez":http://cdumez.blogspot.com/ por su articulo "How to use C++ list model in QML":http://cdumez.blogspot.com/2010/11/how-to-use-c-list-model-in-qml.html.
Este articulo me permitió crear el siguiente ejemplo:


(La fuente de datos para este ejemplo ha sido tomada de unos de los ejemplosde SQL que se incluyen con Qt, &quot;examples\sql\masterdetail&amp;quot;:http://doc.qt.nokia.com/stable/sql-masterdetail-database-h.html)
(La fuente de datos para este ejemplo ha sido tomada de unos de los ejemplosde SQL que se incluyen con Qt, "examples\sql\masterdetail":http://doc.qt.nokia.com/stable/sql-masterdetail-database-h.html)


=== Paso 1: Crear una clase C++ que derive de QSqlQueryModel: ===
=== Paso 1: Crear una clase C++ que derive de QSqlQueryModel: ===
Line 17: Line 18:
Toda la magia ocurre en el constructor y en el método sobrecargado data().
Toda la magia ocurre en el constructor y en el método sobrecargado data().


<code><br />class ArtistsSqlModel : public QSqlQueryModel<br />{<br /> Q_OBJECT<br />public:<br /> explicit ArtistsSqlModel(QObject '''parent);<br /> void refresh();<br /> QVariant data(const QModelIndex &amp;index, int role) const;<br />signals:<br />public slots:<br />private:<br /> const static char''' COLUMN_NAMES[];<br /> const static char* SQL_SELECT;<br />};<br /></code>
<code>
class ArtistsSqlModel : public QSqlQueryModel
{
Q_OBJECT
public:
explicit ArtistsSqlModel(QObject '''parent);
void refresh();
QVariant data(const QModelIndex &amp;index, int role) const;
signals:
public slots:
private:
const static char''' COLUMN_NAMES[];
const static char* SQL_SELECT;
};
</code>


=== Paso 2: Implementar dos constantes estáticas ===
=== Paso 2: Implementar dos constantes estáticas ===
Line 23: Line 38:
Siempre tengo dos constantes estáticas en cada uno de mis modelos que derivan de QSqlQueryModel, COLUMN_NAMES y SQL_SELECT. El orden de los nombres de las columnas en COLUMN_NAMES debe coincidir con el orden en que aparece en la instrucción SELECT.
Siempre tengo dos constantes estáticas en cada uno de mis modelos que derivan de QSqlQueryModel, COLUMN_NAMES y SQL_SELECT. El orden de los nombres de las columnas en COLUMN_NAMES debe coincidir con el orden en que aparece en la instrucción SELECT.


<code>const char* ArtistsSqlModel::COLUMN_NAMES[] = {<br /> &quot;artist&amp;quot;,<br /> &quot;title&amp;quot;,<br /> &quot;year&amp;quot;,<br /> NULL<br />};<br />const char* ArtistsSqlModel::SQL_SELECT =<br />&quot;SELECT artists.artist, albums.title, albums.year&amp;quot;<br />&quot; FROM albums&amp;quot;<br />&quot; JOIN artists ON albums.artistid = artists.id&amp;quot;;<br /></code>
<code>const char* ArtistsSqlModel::COLUMN_NAMES[] = {
"artist",
"title",
"year",
NULL
};
const char* ArtistsSqlModel::SQL_SELECT =
"SELECT artists.artist, albums.title, albums.year"
" FROM albums"
" JOIN artists ON albums.artistid = artists.id";
</code>


=== Paso 3: Establecer el roleNames en el constructor ===
=== Paso 3: Establecer el roleNames en el constructor ===
Line 29: Line 54:
Aquí es donde toda la magia realmente ocurre. QML hará referencia a las distintas columnas por el nombre del role establecido en el modelo.
Aquí es donde toda la magia realmente ocurre. QML hará referencia a las distintas columnas por el nombre del role establecido en el modelo.


<code>ArtistsSqlModel::ArtistsSqlModel(QObject *parent) :<br /> QSqlQueryModel(parent)<br />{<br /> int idx = 0;<br /> QHash&amp;lt;int, QByteArray&amp;gt; roleNames;<br /> while( COLUMN_NAMES[idx]) {<br /> roleNames[Qt::UserRole + idx + 1] = COLUMN_NAMES[idx];<br /> idx++;<br /> }<br /> setRoleNames(roleNames);<br /> refresh();<br />}</code>
<code>ArtistsSqlModel::ArtistsSqlModel(QObject *parent) :
QSqlQueryModel(parent)
{
int idx = 0;
QHash<int, QByteArray> roleNames;
while( COLUMN_NAMES[idx]) {
roleNames[Qt::UserRole + idx + 1] = COLUMN_NAMES[idx];
idx++;
}
setRoleNames(roleNames);
refresh();
}</code>


=== Paso 4: Implementar el método data() : ===
=== Paso 4: Implementar el método data() : ===
Line 35: Line 71:
Mientras el role que se solicita no es un role de usuario, se devuelve el valor predeterminado. Pero si role es un role de usuario, devuelve la columna correcta:
Mientras el role que se solicita no es un role de usuario, se devuelve el valor predeterminado. Pero si role es un role de usuario, devuelve la columna correcta:


<code>QVariant ArtistsSqlModel::data(const QModelIndex &amp;index, int role) const<br />{<br /> QVariant value = QSqlQueryModel::data(index, role);<br /> if(role &lt; Qt::UserRole)<br /> {<br /> value = QSqlQueryModel::data(index, role);<br /> }<br /> else<br /> {<br /> int columnIdx = role - Qt::UserRole - 1;<br /> QModelIndex modelIndex = this-&gt;index(index.row(), columnIdx);<br /> value = QSqlQueryModel::data(modelIndex, Qt::DisplayRole);<br /> }<br /> return value;<br />} </code>
<code>QVariant ArtistsSqlModel::data(const QModelIndex &amp;index, int role) const
{
QVariant value = QSqlQueryModel::data(index, role);
if(role < Qt::UserRole)
{
value = QSqlQueryModel::data(index, role);
}
else
{
int columnIdx = role - Qt::UserRole - 1;
QModelIndex modelIndex = this->index(index.row(), columnIdx);
value = QSqlQueryModel::data(modelIndex, Qt::DisplayRole);
}
return value;
} </code>


=== Paso 5: Permitir a QML ver el modelo: ===
=== Paso 5: Permitir a QML ver el modelo: ===
Line 41: Line 91:
Cree una instancia de el modelo (tome nota de que el constructor del modelo consulte la base de datos la primera vez). A continuación, establezcalo como una propiedad en el contexto del viewer, en este caso lo he llamado artistModel:
Cree una instancia de el modelo (tome nota de que el constructor del modelo consulte la base de datos la primera vez). A continuación, establezcalo como una propiedad en el contexto del viewer, en este caso lo he llamado artistModel:


<code><br /> ArtistsSqlModel *artistsSqlModel = new ArtistsSqlModel( qApp);<br /> QmlApplicationViewer viewer;<br /> viewer.rootContext()-&gt;setContextProperty(&quot;artistsModel&amp;quot;, artistsSqlModel);<br /> viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);<br /> viewer.setMainQmlFile&amp;amp;#40;QLatin1String(&quot;qml/SQLListView/main.qml&amp;quot;&amp;#41;);<br /> viewer.showExpanded();
<code>
ArtistsSqlModel *artistsSqlModel = new ArtistsSqlModel( qApp);
QmlApplicationViewer viewer;
viewer.rootContext()->setContextProperty("artistsModel", artistsSqlModel);
viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);
viewer.setMainQmlFile(QLatin1String("qml/SQLListView/main.qml"));
viewer.showExpanded();


</code>
</code>
Line 49: Line 105:
Desde el modelo que hemos expuesto en el paso 5, el modelo existe y esta listo para ser usado por QML. Simplemente establezca el modelo de el ListView con el nombre dado en el paso 5.
Desde el modelo que hemos expuesto en el paso 5, el modelo existe y esta listo para ser usado por QML. Simplemente establezca el modelo de el ListView con el nombre dado en el paso 5.


<code><br /> ListView {<br /> id: list_view1<br /> clip: true<br /> anchors.margins: 10<br /> anchors.fill: parent<br /> model: artistsModel<br /> delegate: ArtistItemDelegate {}<br /> }<br /></code>
<code>
ListView {
id: list_view1
clip: true
anchors.margins: 10
anchors.fill: parent
model: artistsModel
delegate: ArtistItemDelegate {}
}
</code>


Y finalmente la implementación de el delegado, note aquí como los nombres establecidos en el roleModel son usados como los valores a enlazar a la propiedad text de los objetos Text:
Y finalmente la implementación de el delegado, note aquí como los nombres establecidos en el roleModel son usados como los valores a enlazar a la propiedad text de los objetos Text:


'''ArtistItemDelegate.qml'''<br /><code>import Qt 4.7
'''ArtistItemDelegate.qml'''
<code>import Qt 4.7


Item {<br /> id: delegate<br /> width: delegate.ListView.view.width;<br /> height: 30<br /> clip: true<br /> anchors.margins: 4
Item {
id: delegate
width: delegate.ListView.view.width;
height: 30
clip: true
anchors.margins: 4


Row {<br /> anchors.margins: 4<br /> anchors.fill: parent<br /> spacing: 4;
Row {
anchors.margins: 4
anchors.fill: parent
spacing: 4;


Text {<br /> text: artist<br /> width: 150<br /> }
Text {
text: artist
width: 150
}


Text {<br /> text: title<br /> width: 300;<br /> }
Text {
text: title
width: 300;
}


Text {<br /> text: year<br /> width: 50;<br /> }<br /> }<br />}</code>
Text {
text: year
width: 50;
}
}
}</code>


Siéntase libre de contactase conmigo para obtener el código fuente completo, estaré muy feliz de compartirlo. (mas información en la &quot;versión original&amp;quot;:How_to_use_a_QSqlQueryModel_in_QML del articulo)
Siéntase libre de contactase conmigo para obtener el código fuente completo, estaré muy feliz de compartirlo. (mas información en la "versión original":How_to_use_a_QSqlQueryModel_in_QML del articulo)

Revision as of 11:00, 25 February 2015

Spanish English Italian

Como usar un QSqlQueryModel en QML

El software que estoy desarrollando, Photo Parata, es una aplicación cliente servidor que usa un backend SQL. La mayor parte del tiempo, lo datos mostrados por Photo Parata requieren de alguna relación (join). Debido a esto, la mayoría de las veces los modelos derivan de QSqlQueryModel no de QSqlTableModel.

En este articulo, recorreré los pasos para configurar un modelo personalizado para ser usado desde QML derivado de QSqlQueryModel.

Quiero agradecer a "Christophe Dumez":http://cdumez.blogspot.com/ por su articulo "How to use C++ list model in QML":http://cdumez.blogspot.com/2010/11/how-to-use-c-list-model-in-qml.html. Este articulo me permitió crear el siguiente ejemplo:

(La fuente de datos para este ejemplo ha sido tomada de unos de los ejemplosde SQL que se incluyen con Qt, "examples\sql\masterdetail":http://doc.qt.nokia.com/stable/sql-masterdetail-database-h.html)

Paso 1: Crear una clase C++ que derive de QSqlQueryModel:

Toda la magia ocurre en el constructor y en el método sobrecargado data().

class ArtistsSqlModel : public QSqlQueryModel
{
 Q_OBJECT
public:
 explicit ArtistsSqlModel(QObject '''parent);
 void refresh();
 QVariant data(const QModelIndex &amp;index, int role) const;
signals:
public slots:
private:
 const static char''' COLUMN_NAMES[];
 const static char* SQL_SELECT;
};

Paso 2: Implementar dos constantes estáticas

Siempre tengo dos constantes estáticas en cada uno de mis modelos que derivan de QSqlQueryModel, COLUMN_NAMES y SQL_SELECT. El orden de los nombres de las columnas en COLUMN_NAMES debe coincidir con el orden en que aparece en la instrucción SELECT.

const char* ArtistsSqlModel::COLUMN_NAMES[] = {
 "artist",
 "title",
 "year",
 NULL
};
const char* ArtistsSqlModel::SQL_SELECT =
"SELECT artists.artist, albums.title, albums.year"
" FROM albums"
" JOIN artists ON albums.artistid = artists.id";

Paso 3: Establecer el roleNames en el constructor

Aquí es donde toda la magia realmente ocurre. QML hará referencia a las distintas columnas por el nombre del role establecido en el modelo.

ArtistsSqlModel::ArtistsSqlModel(QObject *parent) :
 QSqlQueryModel(parent)
{
 int idx = 0;
 QHash<int, QByteArray> roleNames;
 while( COLUMN_NAMES[idx]) {
 roleNames[Qt::UserRole + idx + 1] = COLUMN_NAMES[idx];
 idx++;
 }
 setRoleNames(roleNames);
 refresh();
}

Paso 4: Implementar el método data() :

Mientras el role que se solicita no es un role de usuario, se devuelve el valor predeterminado. Pero si role es un role de usuario, devuelve la columna correcta:

QVariant ArtistsSqlModel::data(const QModelIndex &amp;index, int role) const
{
 QVariant value = QSqlQueryModel::data(index, role);
 if(role < Qt::UserRole)
 {
 value = QSqlQueryModel::data(index, role);
 }
 else
 {
 int columnIdx = role - Qt::UserRole - 1;
 QModelIndex modelIndex = this->index(index.row(), columnIdx);
 value = QSqlQueryModel::data(modelIndex, Qt::DisplayRole);
 }
 return value;
}

Paso 5: Permitir a QML ver el modelo:

Cree una instancia de el modelo (tome nota de que el constructor del modelo consulte la base de datos la primera vez). A continuación, establezcalo como una propiedad en el contexto del viewer, en este caso lo he llamado artistModel:

 ArtistsSqlModel *artistsSqlModel = new ArtistsSqlModel( qApp);
 QmlApplicationViewer viewer;
 viewer.rootContext()->setContextProperty("artistsModel", artistsSqlModel);
 viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);
 viewer.setMainQmlFile(QLatin1String("qml/SQLListView/main.qml"));
 viewer.showExpanded();

h3.Paso 6: Crear la lista y el delegado en QML

Desde el modelo que hemos expuesto en el paso 5, el modelo existe y esta listo para ser usado por QML. Simplemente establezca el modelo de el ListView con el nombre dado en el paso 5.

 ListView {
 id: list_view1
 clip: true
 anchors.margins: 10
 anchors.fill: parent
 model: artistsModel
 delegate: ArtistItemDelegate {}
 }

Y finalmente la implementación de el delegado, note aquí como los nombres establecidos en el roleModel son usados como los valores a enlazar a la propiedad text de los objetos Text:

ArtistItemDelegate.qml

import Qt 4.7

Item {
 id: delegate
 width: delegate.ListView.view.width;
 height: 30
 clip: true
 anchors.margins: 4

Row {
 anchors.margins: 4
 anchors.fill: parent
 spacing: 4;

Text {
 text: artist
 width: 150
 }

Text {
 text: title
 width: 300;
 }

Text {
 text: year
 width: 50;
 }
 }
}

Siéntase libre de contactase conmigo para obtener el código fuente completo, estaré muy feliz de compartirlo. (mas información en la "versión original":How_to_use_a_QSqlQueryModel_in_QML del articulo)