Qt wiki will be updated on October 12th 2023 starting at 11:30 AM (EEST) and the maintenance will last around 2-3 hours. During the maintenance the site will be unavailable.

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

From Qt Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 15: Line 15:
Tutta la magia avviene nel costruttore e nei dati del metodo overload().
Tutta la magia avviene nel costruttore e nei dati del metodo overload().


<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>


=== Fase 2: Implementare due costanti statiche ===
=== Fase 2: Implementare due costanti statiche ===
Line 21: Line 35:
Ho sempre due variabili costanti statiche in ciascuno dei miei modelli che derivano da QSqlQueryModel, COLUMN_NAMES e SQL_SELECT. L'ordine dei nomi delle colonne in COLUMN_NAMES deve corrispondere l'ordine in cui sono elencati nella SELECT
Ho sempre due variabili costanti statiche in ciascuno dei miei modelli che derivano da QSqlQueryModel, COLUMN_NAMES e SQL_SELECT. L'ordine dei nomi delle colonne in COLUMN_NAMES deve corrispondere l'ordine in cui sono elencati nella SELECT


<code>const char* ArtistsSqlModel::COLUMN_NAMES[] = {<br /> "artist",<br /> "title",<br /> "year",<br /> NULL<br />};<br />const char* ArtistsSqlModel::SQL_SELECT =<br />"SELECT artists.artist, albums.title, albums.year"<br />" FROM albums"<br />" JOIN artists ON albums.artistid = artists.id";<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>


=== Fase 3: Settare roleNames nel costruttore ===
=== Fase 3: Settare roleNames nel costruttore ===
Line 27: Line 51:
Questa fase è dove tutta la magia accade realmente. Il QML farà riferimento alle varie colonne con le roleNames nomi ruolo impostata sul modello.
Questa fase è dove tutta la magia accade realmente. Il QML farà riferimento alle varie colonne con le roleNames nomi ruolo impostata sul modello.


<code>ArtistsSqlModel::ArtistsSqlModel(QObject *parent) :<br /> QSqlQueryModel(parent)<br />{<br /> int idx = 0;<br /> QHash<int, QByteArray> 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>


=== Fase 4: Implementare il metodo data(): ===
=== Fase 4: Implementare il metodo data(): ===
Line 33: Line 68:
Finché il ruolo che viene richiesto non è un ruolo utente, restituisce il valore predefinito. Ma se il ruolo è un ruolo utente, riporta la colonna corretta:
Finché il ruolo che viene richiesto non è un ruolo utente, restituisce il valore predefinito. Ma se il ruolo è un ruolo utente, riporta la colonna corretta:


<code>QVariant ArtistsSqlModel::data(const QModelIndex &amp;index, int role) const<br />{<br /> QVariant value = QSqlQueryModel::data(index, role);<br /> if(role < Qt::UserRole)<br /> {<br /> value = QSqlQueryModel::data(index, role);<br /> }<br /> else<br /> {<br /> int columnIdx = role - Qt::UserRole - 1;<br /> QModelIndex modelIndex = this->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>


=== Fase 5: Abilitare QML a riconoscere il modello: ===
=== Fase 5: Abilitare QML a riconoscere il modello: ===
Line 39: Line 88:
Create un istanza del modello (prendete nota che il costruttore del modello deve interrogare il DB la prima volta). Poi settatelo come proprietà sul contenuto della vista, in questo caso l'ho chiamato artistModel:
Create un istanza del modello (prendete nota che il costruttore del modello deve interrogare il DB la prima volta). Poi settatelo come proprietà sul contenuto della vista, in questo caso l'ho chiamato artistModel:


<code><br /> ArtistsSqlModel *artistsSqlModel = new ArtistsSqlModel( qApp);<br /> QmlApplicationViewer viewer;<br /> viewer.rootContext()->setContextProperty("artistsModel", artistsSqlModel);<br /> viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);<br /> viewer.setMainQmlFile(QLatin1String("qml/SQLListView/main.qml"));<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 47: Line 102:
Poiché il modello è stato esposto alla fase 5, il modello esiste e può essere usato in QML. Semplicemente settate il modello della ListView con il nome usato nella fase 5.
Poiché il modello è stato esposto alla fase 5, il modello esiste e può essere usato in QML. Semplicemente settate il modello della ListView con il nome usato nella fase 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>


E infine l'implementazione del delegato. Si noti come i nomi indicati nella roleModel vengono utilizzati come i valori da associare alla proprietà Text degli oggetti di testo:
E infine l'implementazione del delegato. Si noti come i nomi indicati nella roleModel vengono utilizzati come i valori da associare alla proprietà Text degli oggetti di testo:


'''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>


Tutti i miei esempi in Qt si possono trovare a questo indirizzo. "http://www.miltonstreet.com/qt/":http://www.miltonstreet.com/qt/
Tutti i miei esempi in Qt si possono trovare a questo indirizzo. "http://www.miltonstreet.com/qt/":http://www.miltonstreet.com/qt/

Revision as of 11:31, 25 February 2015

English Spanish Italiano

Come usare QSqlQueryModel in QML

Il software che ho sviluppato, Photo Parata, è un applicazione client server che usa come backend sql. Per la maggior parte del tempo i dati da visualizzare di Photo Parata displays richiedono alcune joins. Per questo motivo,i modelli sono derivati da QSqlQueryModel, non QSqlTableModel.

In questa guida, vi guiderà attraverso le fasi della creazione di un modello personalizzato per QML, derivato da QSqlQueryModel.

Voglio ringraziare "Christophe Dumez":http://cdumez.blogspot.com/ per il suo blog "How to use C++ list model in QML":http://cdumez.blogspot.com/2010/11/how-to-use-c-list-model-in-qml.html. Grazie a questo blog che sono riuscito a mettere insieme le seguenti cose:

(La sorgente dei dati per questo esempio è stato preso da uno degli esempi di Sql che viene fornito con Qt, "examples\sql\masterdetail":http://doc.qt.nokia.com/stable/sql-masterdetail-database-h.html)

Fase 1: Creare una classe C++ derivata da QSqlQueryModel:

Tutta la magia avviene nel costruttore e nei dati del metodo overload().

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;
};

Fase 2: Implementare due costanti statiche

Ho sempre due variabili costanti statiche in ciascuno dei miei modelli che derivano da QSqlQueryModel, COLUMN_NAMES e SQL_SELECT. L'ordine dei nomi delle colonne in COLUMN_NAMES deve corrispondere l'ordine in cui sono elencati nella 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";

Fase 3: Settare roleNames nel costruttore

Questa fase è dove tutta la magia accade realmente. Il QML farà riferimento alle varie colonne con le roleNames nomi ruolo impostata sul modello.

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();
}

Fase 4: Implementare il metodo data():

Finché il ruolo che viene richiesto non è un ruolo utente, restituisce il valore predefinito. Ma se il ruolo è un ruolo utente, riporta la colonna corretta:

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;
}

Fase 5: Abilitare QML a riconoscere il modello:

Create un istanza del modello (prendete nota che il costruttore del modello deve interrogare il DB la prima volta). Poi settatelo come proprietà sul contenuto della vista, in questo caso l'ho chiamato 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();

Fase 6: Creare la lista QML e delegati

Poiché il modello è stato esposto alla fase 5, il modello esiste e può essere usato in QML. Semplicemente settate il modello della ListView con il nome usato nella fase 5.

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

E infine l'implementazione del delegato. Si noti come i nomi indicati nella roleModel vengono utilizzati come i valori da associare alla proprietà Text degli oggetti di testo:

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;
 }
 }
}

Tutti i miei esempi in Qt si possono trovare a questo indirizzo. "http://www.miltonstreet.com/qt/":http://www.miltonstreet.com/qt/