I'm having some issues understanding how to display an image stored in a database in QML I would like to use a C++ model to do this. I believe from what I seen I will need an QQuickImageProvider and to over ride the requestImage() method.
Not quite sure how to set up the Image provider - subclass the image provider and over ride requestImage() ?
Not sure how to use the model and Image provider to display image in QML scrollView - model combines with ImageProvider to display image ?
I have a drop list for displaying the images name and once a user selects a image from the list I want the image to load into a scroll view...
I set up my database schema as such:
Code:
"CREATE TABLE IF NOT EXISTS picTable (id INT PRIMARY KEY, picName TEXT, pic BLOB)"
QML code
Code:
Item { id:checkList_item implicitHeight: 600 implicitWidth: 1000 signal exit() Rectangle { id: checkList_Rect anchors.fill: parent radius: 10 border.width:4 border.color: "black" layer.enabled: true enabled: true opacity: enabled ? 1.0 : .3 layer.effect: DropShadow { horizontalOffset: 8 verticalOffset: 8 radius: 8.0 samples: 16 color: "#80000000" source: checkList_Rect } gradient: Gradient { GradientStop { position: 0 color: "#ffffff" } GradientStop { position: 1 color: "#262626" } } //---Saves check list to database---// Action{ id: action_saveCheckList onTriggered: { /* * saves check list to database * saves the date the check list was verfied * operator that verified check list * Engineer who verified check list */ } } //---Closes Check List Dialog---// Action{ id: action_exit enabled:!inSequence onTriggered: { //checkList_item.exit(); window_contents.state = "" } } //---Calls function after QML loads---// Component.onCompleted: { //---calls initalize function--// PictureModel.init(); } FocusScope{ id: focusScope1 anchors.rightMargin: 0 anchors.bottomMargin: 0 anchors.leftMargin: 0 anchors.topMargin: 0 anchors.fill:parent //---List Check List Currently in the database---// ComboBox { id: checkList_comboBox width: 130 height: 48 anchors.left: parent.left anchors.leftMargin: 50 anchors.top: parent.top anchors.topMargin: 41 implicitHeight: 30 implicitWidth: 130 KeyNavigation.tab: addCheckListItem activeFocusOnTab: true model: PictureModel textRole: "picName" style: userListCombo Keys.onReturnPressed: { checkList_comboBox.focus = false; addItem.focus = true; } } //---Component for comboBox Style---// Component { id: userListCombo ComboBoxStyle { id: userListcomboxstyle textColor: "black" selectionColor: "yellow" selectedTextColor: "black" background: Rectangle { id: comboBackgroundRect color: "#f9f9f9" radius: 8 height: 22 width: 67 border.color: control.activeFocus ? "yellow" : "#242424" border.width: control.activeFocus ? 4 : 2 Image { id: name width: 12 height: 12 anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right anchors.rightMargin: 5 source: "/combo_expand.png" } } } } //---Rect to hold Image---// Rectangle { id: chekListView_rect radius: 8 width: 1000 height: 400 anchors.left: parent.left anchors.leftMargin: 10 anchors.right: parent.right anchors.rightMargin: 10 anchors.verticalCenter: parent.verticalCenter anchors.verticalCenterOffset: -5 border{ color: "black" width: 3 } //---Adds ScrollBars---// ScrollView{ id: userEvent_scrollView anchors.fill: parent //---Enables flickable Area---// flickableItem.interactive: true verticalScrollBarPolicy: Qt.ScrollBarAsNeeded style: edit_scrollbar_style //---Display image from C++ model---// Image{ //source: } } } //---Custom ScrollBar Component---// Component{ id: edit_scrollbar_style ScrollViewStyle { transientScrollBars: false handle: Item { implicitWidth: 17 implicitHeight: 25 Rectangle { color: "#424246" radius: 6 anchors.fill: parent anchors.topMargin: 6 anchors.leftMargin: 4 anchors.rightMargin: 4 anchors.bottomMargin: 6 } } decrementControl: Rectangle{ implicitWidth: 17 implicitHeight: 17 radius: 6 color:"#626262" Image{ anchors.centerIn: parent width: 15 height: 15 source: "up_arrow.png" } Rectangle { implicitWidth: 17 implicitHeight: 5 color:"#626262" anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter } } incrementControl: Rectangle{ implicitWidth: 17 implicitHeight: 17 radius: 6 color:"#626262" Image{ anchors.centerIn: parent width: 15 height: 15 source: "down_arrow.png" } Rectangle { anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter implicitWidth: 17 implicitHeight: 5 color:"#626262" } } scrollBarBackground: Rectangle { implicitWidth: 17 implicitHeight: 25 color:"grey" } } } } } }
Added after 20 minutes:
C++ here is the model code
header prototype
Code:
//---Data struct for stored checkLists---// struct PictureModelStruct{ QString id; QString picname; QPixmap pic; }; Q_OBJECT public: ~PictureModel(); void setContext(QQmlContext* root); Q_INVOKABLE void insertPic(); Q_INVOKABLE void displayPic(); enum pictureRoles{idRole= Qt::UserRole + 1, nameRole, picRole}; QHash<int, QByteArray> roleNames() const; Q_INVOKABLE void addPicture(const PictureModelStruct &picList); Q_INVOKABLE bool dbConnect(); Q_INVOKABLE void init(); Q_INVOKABLE bool selectPictureName(); signals: void showBusy(bool busy_state); public slots: private: //---Databse Class Instances---// QList<PictureModelStruct> m_picList; QSqlDatabase m_selectPictureDB; };
Code:
//---Constructor subclasses ListModel & ImageLoader---// QQuickImageProvider(QQmlImageProviderBase::Image, QQmlImageProviderBase::ForceAsynchronousImageLoading){ } } //---Destructor---// PictureModel::~PictureModel(){ } //---init() is called after QML loads---// void PictureModel::init(){ //insertPic(); displayPic(); selectPictureName(); } //---Connect to BLOB database---// bool PictureModel::dbConnect(){ //---check if database is connected---// if(!m_selectPictureDB.isValid()){ qDebug() << "PictureModel::dbConnect() error in connecting to DB"; m_selectPictureDB.setDatabaseName(Paths::root() + "/pictures.db"); qDebug() << "PictureModel::dbConnect() database connection path: "+Paths::root()+"/pictures.db"; m_selectPictureDB.open(); if(!tables.contains("picTable")){ q.exec("CREATE TABLE IF NOT EXISTS picTable (id INT PRIMARY KEY, picName TEXT, pic BLOB)"); qDebug() << "PictureModel::dbConnect() created picTable"; } } else{ qDebug() <<"PictureModel::dbConnect() connected to DB" ; m_selectPictureDB.open(); } return m_selectPictureDB.isValid(); } //---Inserts a pic into BLOB database void PictureModel::insertPic(){ dbConnect(); qDebug() << image.size(); QByteArray inByteArray; image.save(&buffer, "jpg"); bool sqlBool = query.prepare("INSERT INTO picTable (id, picName, pic) VALUES (?, ?, ?)"); query.addBindValue(5); query.addBindValue("flower"); query.addBindValue(inByteArray); if(sqlBool){ if(query.exec()){ qDebug() << "PictureModel::insertPic() sql insert executed fine!"; } } else{ qDebug() << "PictureModel::isertPic() sql insert did not execute!"; } } //---Displays pic stored in BLOB database---// void PictureModel::displayPic(){ dbConnect(); QByteArray outByteArray; bool sqlBool; sqlBool = query.prepare("SELECT pic FROM picTable"); if (sqlBool){ qDebug() << "prepare sql display pic executed fine!"; if(query.exec()){ qDebug() << "execute sql display pic executed fine!"; } else{ qDebug() << "execute sql display pic did not execute"; } } else{ qDebug() << "prepare sql display pic did not execute"; } PictureModelStruct picList; beginResetModel(); m_picList.clear(); while (query.next()){ picList.id = query.value(0).toString(); picList.picname = query.value(1).toString(); outByteArray = query.value(2).toByteArray(); addPicture(picList); } endResetModel(); emit showBusy(false); m_selectPictureDB.close(); } //---Function is called in xmui.cpp---// void PictureModel::setContext(QQmlContext* root){ //---Sets rootContext for model to be used in userListModel QML---// root->setContextProperty("PictureModel", this); } Q_UNUSED(parent); return m_picList.count(); } QHash<int, QByteArray> PictureModel::roleNames() const{ QHash<int, QByteArray> roleNames; roleNames.insert(nameRole, "picName"); return roleNames; } if (index.row() < 0 || index.row() >= m_picList.count()){ } QVariant text; if(role == nameRole){ PictureModelStruct pList = m_picList.at(index.row()); text = pList.picname; } return text; } void PictureModel::addPicture(const PictureModelStruct &picList){ m_picList.insert(0, picList); endInsertRows(); } //---Selects name of pictures from DB for display---// bool PictureModel::selectPictureName(){ dbConnect(); emit showBusy(true); bool sqlBool; sqlBool = selectQuery.prepare("SELECT DISTINCT picName FROM picTable ORDER BY picName ASC"); if(sqlBool){ if(selectQuery.exec()){ qDebug()<<"PictureModel::selectPictureName() select picName sql statement executed fine"; } } else{ emit xmui->alertMsg(QMessageBox::Warning, "Database selectPicture Error Message 1", "Error: sql select script..."+selectQuery.lastError().text()); qDebug()<<"PictureModel::selectPictureName() Error with sql statement execution " << selectQuery.lastError(); return selectQuery.exec(); } PictureModelStruct picList; beginResetModel(); m_picList.clear(); while (selectQuery.next()){ picList.picname = selectQuery.value(1).toString(); addPicture(picList); } endResetModel(); emit showBusy(false); m_selectPictureDB.close(); return selectQuery.exec(); }
updated header file
Code:
//---Data struct for stored checkLists---// struct PictureModelStruct{ QString id; QString picname; QPixmap pic; }; Q_OBJECT public: ~PictureModel(); void setContext(QQmlContext* root); Q_INVOKABLE void insertPic(); Q_INVOKABLE void displayPic(); enum pictureRoles{idRole= Qt::UserRole + 1, nameRole, picRole}; QHash<int, QByteArray> roleNames() const; Q_INVOKABLE void addPicture(const PictureModelStruct &picList); Q_INVOKABLE bool dbConnect(); Q_INVOKABLE void init(); Q_INVOKABLE bool selectPictureName(); signals: void showBusy(bool busy_state); public slots: private: //---Databse Class Instances---// QList<PictureModelStruct> m_picList; QSqlDatabase m_selectPictureDB; };
Added after 9 minutes:
thought about adding a call to requestImage() and pass it the id and image from the database...
Added after 7 minutes:
change form pixMap to Image
Added after 25 minutes:
updated c++ functions
Code:
//---Constructor subclasses ListModel & ImageLoader---// QQuickImageProvider(QQmlImageProviderBase::Image, QQmlImageProviderBase::ForceAsynchronousImageLoading){ } Q_UNUSED(id); Q_UNUSED(size); Q_UNUSED(reqSize); //return QImage::fromData(this->record(id.toInt(), "jpg")); } //---Destructor---// PictureModel::~PictureModel(){ } //---init() is called after QML loads---// void PictureModel::init(){ //insertPic(); displayPic(); selectPictureName(); } //---Connect to BLOB database---// bool PictureModel::dbConnect(){ //---check if database is connected---// if(!m_selectPictureDB.isValid()){ qDebug() << "PictureModel::dbConnect() error in connecting to DB"; m_selectPictureDB.setDatabaseName(Paths::root() + "/pictures.db"); qDebug() << "PictureModel::dbConnect() database connection path: "+Paths::root()+"/pictures.db"; m_selectPictureDB.open(); if(!tables.contains("picTable")){ q.exec("CREATE TABLE IF NOT EXISTS picTable (id INT PRIMARY KEY, picName TEXT, pic BLOB)"); qDebug() << "PictureModel::dbConnect() created picTable"; } } else{ qDebug() <<"PictureModel::dbConnect() connected to DB" ; m_selectPictureDB.open(); } return m_selectPictureDB.isValid(); } //---Inserts a pic into BLOB database void PictureModel::insertPic(){ dbConnect(); qDebug() << image.size(); QByteArray inByteArray; image.save(&buffer, "jpg"); bool sqlBool = query.prepare("INSERT INTO picTable (id, picName, pic) VALUES (?, ?, ?)"); query.addBindValue(5); query.addBindValue("flower"); query.addBindValue(inByteArray); if(sqlBool){ if(query.exec()){ qDebug() << "PictureModel::insertPic() sql insert executed fine!"; } } else{ qDebug() << "PictureModel::isertPic() sql insert did not execute!"; } } //---Displays pic stored in BLOB database---// void PictureModel::displayPic(){ dbConnect(); QByteArray outByteArray; bool sqlBool; sqlBool = query.prepare("SELECT pic FROM picTable"); if (sqlBool){ qDebug() << "prepare sql display pic executed fine!"; if(query.exec()){ qDebug() << "execute sql display pic executed fine!"; } else{ qDebug() << "execute sql display pic did not execute"; } } else{ qDebug() << "prepare sql display pic did not execute"; } PictureModelStruct picList; beginResetModel(); m_picList.clear(); while (query.next()){ picList.id = query.value(0).toString(); picList.picname = query.value(1).toString(); outByteArray = query.value(2).toByteArray(); addPicture(picList); //requestImage(picList.id, QSize(20, 20), QSize(20, 20)); } endResetModel(); emit showBusy(false); m_selectPictureDB.close(); } //---Function is called in xmui.cpp---// void PictureModel::setContext(QQmlContext* root){ //---Sets rootContext for model to be used in userListModel QML---// root->setContextProperty("PictureModel", this); } Q_UNUSED(parent); return m_picList.count(); } QHash<int, QByteArray> PictureModel::roleNames() const{ QHash<int, QByteArray> roleNames; roleNames.insert(nameRole, "picName"); return roleNames; } if (index.row() < 0 || index.row() >= m_picList.count()){ } QVariant text; if(role == nameRole){ PictureModelStruct pList = m_picList.at(index.row()); text = pList.picname; } return text; } void PictureModel::addPicture(const PictureModelStruct &picList){ m_picList.insert(0, picList); endInsertRows(); } //---Selects name of pictures from DB for display---// bool PictureModel::selectPictureName(){ dbConnect(); emit showBusy(true); bool sqlBool; sqlBool = selectQuery.prepare("SELECT DISTINCT picName FROM picTable ORDER BY picName ASC"); if(sqlBool){ if(selectQuery.exec()){ qDebug()<<"PictureModel::selectPictureName() select picName sql statement executed fine"; } } else{ emit xmui->alertMsg(QMessageBox::Warning, "Database selectPicture Error Message 1", "Error: sql select script..."+selectQuery.lastError().text()); qDebug()<<"PictureModel::selectPictureName() Error with sql statement execution " << selectQuery.lastError(); return selectQuery.exec(); } PictureModelStruct picList; beginResetModel(); m_picList.clear(); while (selectQuery.next()){ picList.picname = selectQuery.value(1).toString(); addPicture(picList); } endResetModel(); emit showBusy(false); m_selectPictureDB.close(); return selectQuery.exec(); }