Populate Listview from Database
I want to populate listview ( a specific page in my app ) from a database .
Currently the page is static and look like this
image: https://s32.postimg.org/vrsdrl2p1/man.png
code :
Code:
import QtQuick 2.6
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.0
Pane {
padding: 0
property var delegateComponentMap: {
"page": itemDelegateComponent
}
Component {
id: itemDelegateComponent
ItemDelegate {
text: labelText
width: parent.width
}
}
ColumnLayout {
id: column
spacing: 40
anchors.fill: parent
anchors.topMargin: 20
Label {
id: label1
Layout.fillWidth: true
wrapMode: Label.Wrap
horizontalAlignment: Qt.AlignHCenter
text: "Offline Pages "
}
ListView {
id: listView
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
model: ListModel {
ListElement { type: "ItemDelegate"; labelText: "page1" }
ListElement { type: "ItemDelegate"; labelText: "page2" }
ListElement { type: "ItemDelegate"; labelText: "page3" }
}
spacing: 5
section.property: "type"
delegate: Component{
Item{
id: aItem
width: listView.width //rowLayout.width. We got width from children elements before, now get width from listView
height: 30
RowLayout{
id: rowLayout
anchors.fill: parent
spacing: 10
Label{
id:page_name
padding: 10
text: labelText
Layout.fillWidth: true // !!! to fill most part of row width
}
Button{
text: qsTr("Delete")
id: delete_button
}
Button{
text: qsTr("Update")
id: update_button
}
}
}
}
}
RowLayout{
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
Button{
text:"Update All"
}
Button{
text:"Delete All"
}
}
}
}
my databse only has 2 entries ( looks like this ) . the databse is stored in genericelocation
db : https://s32.postimg.org/jb4nhmoxh/image.png
how should i approach this task ?
Re: Populate Listview from Database
If the database is an Sqlite file compatible with QML LocalStorage then you can probably use that to add entries to the QML ListModel you have.
Alternatively you use a C++ list model for the ListView and expose either an instance of it to QML or register the model as a type an instantiate it from QML.
For the model there are a couple of approaches:
- derive from QAbstractListModel and do the database query inside of it
- derive from QSqlQueryModel and overwrite data() such that it maps QML roles to columns of the base class.
Cheers,
_
Re: Populate Listview from Database
Quote:
Originally Posted by
anda_skoa
If the database is an Sqlite file compatible with
QML LocalStorage then you can probably use that to add entries to the QML ListModel you have.
Alternatively you use a C++ list model for the ListView and expose either an instance of it to QML or register the model as a type an instantiate it from QML.
For the model there are a couple of approaches:
- derive from
QAbstractListModel and do the database query inside of it
- derive from
QSqlQueryModel and overwrite data() such that it maps QML roles to columns of the base class.
Cheers,
_
Hello , thanks for answering my question :D . about the first approach using " QML Localstorage" , i do have a sqlite DB but it is stored in some genericLocation
i am storing the database at this path
QString path = QStandardPaths::writableLocation(QStandardPaths::G enericDataLocation);
Can i still open the database ?
for ex :
this is where the db is stored : /home/arcade/.local/share/WTL_appdata/wtl.db
but this path will be different for everyone right .
Re: Populate Listview from Database
No, I don't think LocalStorage can be configured for a different path than the one it is using by default.
You'll have to create a model yourself.
If you already have database access code then the simplest solution is probably to create your own list model.
http://doc.qt.io/qt-5/qtquick-modelv...model-subclass
Cheers,
_
Re: Populate Listview from Database
Thanks !! . Just more thing is there any example which i can refer too ?
An example that fits my case ? :)
Re: Populate Listview from Database
The link in my previous comment is about an actual example.
Cheers,
_
Re: Populate Listview from Database
Hello , i am still not sure how to create the model for my need :confused: . If possible can you break the task for me ??
My project goes like this :
1. all of my program logic is in dbmanager.cpp file
2. main.cpp is just used to instantiate some files and settings
3. main.qml holds main UI
code base : https://github.com/hackertron/W2L/tree/master/UI
Re: Populate Listview from Database
First you need a data structure that can hold all values for a single list entry, e.g. something like
Code:
struct ListEntry
{
};
This is like the Animal class in the example.
Then you need a QAbstractListModel derived class that has a list or vector of that structure.
Code:
{
private:
QList<ListEntry> m_entries;
};
Then you need to implement rowCount(), data() and roleNames() like in the example.
Then you add methods that the database class can call to access the list of entries, so that it can fill it, update it, etc.
QAbstractItemModel defines a set of protected helper methods that need to be used if the model's content is changed after it has been passed to a view, e.g. calling beingInsertRows() and endInsertRows() when new entries need to be added to "m_entries"
Cheers,
_
1 Attachment(s)
Re: Populate Listview from Database
Hello , thanks for the breaking up the steps :D
Below is what i have tried
model.h
Code:
#include <QAbstractListModel>
#include <QStringList>
//![0]
class list
{
public:
//![0]
//type title size id animal list
private:
//![1]
};
{
Q_OBJECT
public:
enum listroles {
titlerole = Qt::UserRole + 1,
idrole
};
void addpages(const list &list);
protected:
QHash<int, QByteArray> roleNames() const;
private:
QList<list> m_list;
};
model.cpp
Code:
#include "model.h"
: m_title(title), m_id(id)
{
}
{
return m_title;
}
{
return m_id;
}
listmodel
::listmodel(QObject *parent
){
}
void listmodel::addpages(const list &list)
{
beginInsertRows
(QModelIndex(), rowCount
(), rowCount
());
m_list << list;
endInsertRows();
}
int listmodel
::rowCount(const QModelIndex & parent
) const { Q_UNUSED(parent);
return m_list.count();
}
if (index.row() < 0 || index.row() >= m_list.count())
const list &list = m_list[index.row()];
if (role == titlerole)
return list.title();
else if (role == idrole)
return list.id();
}
//![0]
QHash<int, QByteArray> listmodel::roleNames() const {
QHash<int, QByteArray> roles;
roles[titlerole] = "title";
roles[idrole] = "id";
return roles;
}
//![0]
main.cpp snippet
Code:
listmodel mod;
if(!db.open())
{
qDebug() <<"error in opening DB";
}
else
{
qDebug() <<"connected to DB" ;
}
QVector<QString> page_id;
QVector<QString> rev_id;
QSqlQuery quer
("SELECT page_ID , page_revision FROM Pages");
while (quer.next()) {
QString i
= quer.
value(0).
toString();
page_id.push_back(i);
QString r
= quer.
value(1).
toString();
rev_id.push_back(r);
}
for (int i = 0; i < page_id.size(); ++i)
{
qDebug() << page_id.at(i).toLocal8Bit().constData() << endl;
qDebug() << rev_id.at(i).toLocal8Bit().constData() << endl;
mod.addpages(list(page_id.at(i) , rev_id.at(i)));
}
QQmlContext *ctxt = engine.rootContext();
ctxt->setContextProperty("myModel", &mod);
qml
Code:
import QtQuick 2.6
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.0
import Qt.labs.folderlistmodel 2.1
Pane{
ListView {
width: 200; height: 250
model: myModel
delegate: Text { text: "pages: " + title + ", " + id }
}
}
OUTPUT :
Attachment 12061
As you can see it's not even close to my original view : https://s32.postimg.org/vrsdrl2p1/man.png
now i need to add buttons to it but how ?
Re: Populate Listview from Database
You just changed your model, so you can just keep using your already working QML code.
Your original QML code just needs to use the new role names or you change your model so that is uses the original role names.
Cheers,
_
1 Attachment(s)
Re: Populate Listview from Database
Yeah , i got it :D
See this : Attachment 12062 ( still need to do some work on it , but it's fine for now )
Now how to actually make it show/hide item dynamically :confused:
ex : when i save a new page it should show that page too . If i remove the page it should remove it from the view too .
what should i do ?
Re: Populate Listview from Database
Look at the code you have in listmodel::addpages()
That adds (in this case appends) a row to the model.
Removing a row is almost the same, just with beginRemoveRows() and endRemoveRows()
Cheers,
_
Re: Populate Listview from Database
hello :) . I am trying something like this
scene : when someone clicks on delete button , i handle it like this
Code:
Button{
text: "delete"
onClicked: {
dbman.del(id) // this one actually deletes file from db and from system , works fine
mod.deletepages(id) // this is what i am trying to implement
}
so what mod.deletepages(id) do is get the id of the page and send it to here
Code:
void listmodel
::deletepages(QString pageid
) {
qDebug() << pageid;
endInsertRows();
}
now what i have is the value not the index . how to get the index of that value .
i have tried to use m_list.indexOf(pageid) ;
but i get error " error: no matching function for call to 'QList<list>::indexOf(QString&)'
int remove = m_list.indexOf(pageid); "
^
so how to get the index
Re: Populate Listview from Database
The easiest way is to pass the row index, since the view and the model have the same concept of what a row is
In your delegate
Code:
mod.deletepages(model.index)
In your model
Code:
void listmodel::deletepages(int row)
{
m_list.remove(row);
endRemoveRows();
}
Ideally you don't do two calls from QML though, but have one C++ method that modifies the model and the database.
Otherwise you could forget one and model and database could get out of sync.
Cheers,
_
1 Attachment(s)
Re: Populate Listview from Database
Hello :) i got the index but i am not able to remove the item from m_list .
ERROR that i am getting is : Attachment 12063
Added after 8 minutes:
Yeah i got it :D . it was removeAt() instead of remove()
Thanks !!
Re: Populate Listview from Database
hey now if i add / save a page offline , i want it to show it in the view too .
ex : i opened my app click on save button to save page . it should show that saved page in the view too .
i tried to call the addpages function along with my save page function , but it is not adding or showing it in view .
Re: Populate Listview from Database
Hmm your addpages() method should append an entry to the list model.
How do you call it?
Cheers,
_
Re: Populate Listview from Database
Like this
Code:
save_file(text , pageid , revid , page_title);
listmodel mod;
mod.
addpages(list
(page_title,
QString(pageid
)));
Re: Populate Listview from Database
So you are creating a new model and adding the page there?
Don't you want to add the "list" entry to the existing model?
Cheers,
_
Re: Populate Listview from Database
Quote:
Originally Posted by
anda_skoa
So you are creating a new model and adding the page there?
Don't you want to add the "list" entry to the existing model?
Cheers,
_
yes i want to add it in the same model !!