Solved Exposing QAbstractListModel to QML SegFault
-
Hello everyone!
I have strange behavior in Qt 5.2. I'm trying to expose QAbstractListModel to QML, but after adding items to it it shows SegFault.
main.cppqmlRegisterType<AttachmentsToSendModel>("VKModels",1,0,"AttachmentsToSendModel");
AttachmentsToSendModel.cpp
#include "attachmentstosendmodel.h" AttachmentsToSendModel::AttachmentsToSendModel(QObject *parent) { setParent(parent); roles=roleNames(); beginInsertRows(QModelIndex(),rowCount(),rowCount()); AttachmentToSendItem* itm = new AttachmentToSendItem(this); QQmlEngine::setObjectOwnership(itm, QQmlEngine::CppOwnership); itm->setSource("file:///home/nemo/Pictures/SK/NwC1iub1wog.jpg"); itm->setType(static_cast<AttachmentToSendItem::FileType>(0)); Items.append(itm); endInsertRows(); } AttachmentsToSendModel::~AttachmentsToSendModel() { qDebug()<<"Killed"; } void AttachmentsToSendModel::addAttachment(QString source, int Type) { qDebug()<<source; beginInsertRows(QModelIndex(),rowCount(),rowCount()); AttachmentToSendItem* itm = new AttachmentToSendItem(this); QQmlEngine::setObjectOwnership(itm, QQmlEngine::CppOwnership); itm->setSource(source); itm->setType(static_cast<AttachmentToSendItem::FileType>(Type)); Items.append(itm); endInsertRows(); } QModelIndex AttachmentsToSendModel::index(int row, int column, const QModelIndex &parent) const { } int AttachmentsToSendModel::rowCount(const QModelIndex &parent) const { return Items.count(); } QVariant AttachmentsToSendModel::data(const QModelIndex &index, int role) const { if(!index.isValid()) return QVariant(); if(index.row()>=Items.size()) return QVariant(); if(role==TYPE) return Items.at(index.row())->Type(); if(role==SOURCE) { qDebug()<<Items.at(index.row())->Source(); // return Items.at(index.row())->Source(); } if(role==URL) qDebug()<<Items.at(index.row())->Url(); if(role==STATUS) qDebug()<<Items.at(index.row())->Status(); if(role==PROGRESS) qDebug()<<Items.at(index.row())->progress(); if(role==TOTAL) qDebug()<<Items.at(index.row())->total(); // const RecursingWallItem* Wi = Items.at(index.row()); return QVariant(); } //bool AttachmentsToSendModel::insertRows(int row, int count, const QModelIndex &parent) //{ //} //bool AttachmentsToSendModel::removeRows(int row, int count, const QModelIndex &parent) //{ // beginRemoveRows(QModelIndex(),row,count); // for(int i=0;i<count;i++) // { // Items.at(row+i)->deleteLater(); // Items.removeAt(row+i); // } // qDebug()<<"deleting Attach"; // endRemoveRows(); //} QHash<int, QByteArray> AttachmentsToSendModel::roleNames() const { QHash<int, QByteArray> roles; roles[TYPE] = "type"; roles[SOURCE] = "c_source"; roles[STATUS]="c_status"; roles[URL] = "url"; roles[PROGRESS] = "progress"; roles[TOTAL] = "total"; return roles; }
AttachmentsToSendItem.h
#ifndef ATTACHMENTTOSENDITEM_H #define ATTACHMENTTOSENDITEM_H #include <QObject> #include <QDebug> class AttachmentToSendItem : public QObject { Q_OBJECT public: explicit AttachmentToSendItem(QObject* parent=0); AttachmentToSendItem(QString source, int type); ~AttachmentToSendItem(); Q_ENUMS(FileType) Q_PROPERTY(QString Url READ Url WRITE setUrl NOTIFY UrlChanged) Q_PROPERTY(int progress READ progress WRITE setProgress NOTIFY progressChanged) Q_PROPERTY(int total READ total WRITE setTotal NOTIFY totalChanged) Q_PROPERTY(QString Source READ Source WRITE setSource NOTIFY SourceChanged) Q_PROPERTY(FileType Type READ Type WRITE setType NOTIFY TypeChanged) Q_PROPERTY(int Status READ Status WRITE setStatus NOTIFY StatusChanged) enum FileType { PHOTO, VIDEO, AUDIO, DOC, WALL }; QString Url() const; int progress() const; int total() const; QString Source() const; FileType Type() const; int Status() const; signals: void UrlChanged(QString Url); void progressChanged(int progress); void totalChanged(int total); void SourceChanged(QString Source); void TypeChanged(FileType Type); void StatusChanged(int Status); public slots: void setUrl(QString Url); void setProgress(int progress); void setTotal(int total); void setSource(QString Source); void setType(FileType Type); void setStatus(int Status); private: QString m_Url=""; int m_progress=0; int m_total; QString m_Source; FileType m_Type; int m_Status=2; }; #endif // ATTACHMENTTOSENDITEM_H
AttachmentToSendItem.cpp
#include "attachmenttosenditem.h" AttachmentToSendItem::AttachmentToSendItem(QObject *parent) { setParent(parent); } AttachmentToSendItem::AttachmentToSendItem(QString source,int type) { setSource(source); setType(static_cast<FileType>(type)); } AttachmentToSendItem::~AttachmentToSendItem() { qDebug()<<"Killed"; } QString AttachmentToSendItem::Url() const { return m_Url; } int AttachmentToSendItem::progress() const { return m_progress; } int AttachmentToSendItem::total() const { return m_total; } QString AttachmentToSendItem::Source() const { return m_Source; } AttachmentToSendItem::FileType AttachmentToSendItem::Type() const { return m_Type; } int AttachmentToSendItem::Status() const { return m_Status; } void AttachmentToSendItem::setUrl(QString Url) { if (m_Url == Url) return; m_Url = Url; emit UrlChanged(Url); } void AttachmentToSendItem::setProgress(int progress) { if (m_progress == progress) return; m_progress = progress; emit progressChanged(progress); } void AttachmentToSendItem::setTotal(int total) { if (m_total == total) return; m_total = total; emit totalChanged(total); } void AttachmentToSendItem::setSource(QString Source) { if (m_Source == Source) return; m_Source = Source; emit SourceChanged(Source); } void AttachmentToSendItem::setType(AttachmentToSendItem::FileType Type) { if (m_Type == Type) return; m_Type = Type; emit TypeChanged(Type); } void AttachmentToSendItem::setStatus(int Status) { if (m_Status == Status) return; m_Status = Status; emit StatusChanged(Status); }
.qml
import QtQuick 2.0 import Sailfish.Silica 1.0 import QtMultimedia 5.0 import VKModels 1.0 import ".." import "../items" import QtDocGallery 5.0 import org.nemomobile.thumbnailer 1.0 Page{ id:page property string headertitle; property int chat_id; property bool isMulti:false property string sobesed_photo; onStatusChanged: { if(status == PageStatus.Active) historyModel.isActive = true; else if(status == PageStatus.Activating) historyModel.isActive = true; historyModel.isActive = false; } Component.onCompleted: { historyModel.clear_Messages(); globalSettings.companionId=chat_id; vkapi.messages_getHistory(chat_id,0,20,-1); } Component.onDestruction: { globalSettings.companionId=0; } Drawer{ id:attachDrawer open:false dock:Dock.Bottom anchors.fill: parent PageHeader{ id:name_info title:headertitle anchors { leftMargin: 10 } } SilicaListView { id: listView model: historyModel anchors.bottom: sendArea.top verticalLayoutDirection: ListView.BottomToTop PullDownMenu { id:pulley MenuItem { text: "добавить прошлые записи" onClicked: { vkapi.messages_getHistory(chat_id,listView.count,20,-1) } } } width: parent.width height: parent.height-name_info.height spacing: 30 anchors { top:name_info.bottom } clip:true delegate:MessageItem{ isOut:out author: isMulti?first_name+ " "+last_name:"" fwdMsg: historyModel.getFwdMessage(id) attachWallpost: historyModel.getFwdPost(id) } } Item{ id:sendArea anchors.bottom: parent.bottom // anchors.left:parent.left width: parent.width height: messageArea.height+attachmentstoSend.height+Theme.paddingSmall //! If model empty everything ok, but if it has items -> SegFault SilicaListView{ id:attachmentstoSend width:parent.width height: model.count>0?Theme.itemSizeMedium:0 anchors.bottom: messageArea.top model:c_attachmentsModelToSend orientation:Qt.Horizontal spacing:5 delegate: Image{ width:Theme.itemSizeMedium height:width sourceSize: Qt.size(width,height) source:"image://nemoThumbnail/"+c_source IconButton{ icon.source: "image://theme/icon-s-clear-opaque-cross?"+Theme.highlightColor anchors.centerIn: parent //onClicked: c_attachmentsModelToSend.(index) } Rectangle{ color:"black" visible: c_status>0 opacity: 0.5 } BusyIndicator{ size: BusyIndicatorSize.Medium anchors.centerIn: parent running: c_status>0 } } } IconButton { id:skrepkaWizard icon.source: "image://theme/icon-m-attach" highlighted: false anchors.bottom: messageArea.bottom anchors.right:messageArea.left anchors.bottomMargin: 25 onClicked: attachDrawer.open=true } TextArea { id:messageArea anchors.bottom: parent.bottom anchors.right: sendButton.left height: Math.min(Theme.itemSizeExtraLarge,implicitHeight)//Math.max(page.height/5, Math.min(page.height/3,implicitHeight)) width:parent.width-sendButton.width- skrepkaWizard.width } IconButton { id:sendButton icon.source: "image://theme/icon-m-message" highlighted: false anchors.bottom: messageArea.bottom // anchors.left:messageArea.right anchors.right:parent.right anchors.bottomMargin: 25 onClicked: { console.log(parent.width,sendButton.width,messageArea.width) vkapi.messages_send(chat_id,messageArea.text) messageArea.selectAll() messageArea.text="" highlighted=!highlighted // historyModel.clear_Messages() // vkapi.messages_getHistory(chat_id,false,20,0) } } } MouseArea { enabled: attachDrawer.open anchors.fill: listView onClicked: attachDrawer.open = false } background:Loader{ id:attachLoader anchors.fill: parent source:"../items/AttachComponent.qml" } } MessageModel{ id:historyModel Component.onCompleted: { historyModel.DataProvider=c_dataProvider historyModel.userId=chat_id } } DocumentGalleryModel { id: galleryModel rootType: DocumentGallery.Image properties: [ "url", "title", "dateTaken" ] autoUpdate: true sortProperties: ["-dateTaken"] } ListModel{ id:attachmentsModelToSend } Connections { target: attachLoader.item onS_items: { console.log(items) var types = ["photo","video","place","audio","doc","photoVK","videoVK"]; for(var i=0;i<items.length;i++) { console.log(items[i]); var file = galleryModel.get(items[i].id).url; console.log(file) attachmentsModelToSend.append({"url":"image://nemoThumbnail/"+galleryModel.get(items[i].id).url,"type":types[items[i].type],"status":2}) c_attachmentsModelToSend.addAttachment(file,types[items[i].type]) } } } }
I understand that issue somehow has problem near ownership of QObject. But I can't find it.
Please help. -
@blacky_i Since you have used
qmlRegisterType
you need to instantiate the type in QML.VKModels { id: vkModels }
Is it done already? I found it missing in your code.
http://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html#exposing-c-data-models-to-qml -
but VKModels is used as import in the beginning of QML...
AttachmentsToSendModel is creating in here
-
@blacky_i
import
doesnot create it. It just makes aware about the type to the engine.
See the example in the link posted earlier. -
Oh shoot! i posted wrong qml file! here I am creating AttachmentsToSendModel
import QtQuick 2.0 import Sailfish.Silica 1.0 import QtMultimedia 5.0 import VKModels 1.0 import ".." import "../items" import QtDocGallery 5.0 import org.nemomobile.thumbnailer 1.0 Page{ id:page signal addAttach(var src,var type); property string headertitle; property int chat_id; property bool isMulti:false property string sobesed_photo; onStatusChanged: { if(status == PageStatus.Active) historyModel.isActive = true; else if(status == PageStatus.Activating) historyModel.isActive = true; historyModel.isActive = false; } Component.onCompleted: { historyModel.clear_Messages(); globalSettings.companionId=chat_id; vkapi.messages_getHistory(chat_id,0,20,-1); } Component.onDestruction: { globalSettings.companionId=0; } Drawer{ id:attachDrawer open:false dock:Dock.Bottom anchors.fill: parent PageHeader{ id:name_info title:headertitle anchors { leftMargin: 10 } } SilicaListView { id: listView model: historyModel anchors.bottom: sendArea.top verticalLayoutDirection: ListView.BottomToTop PullDownMenu { id:pulley MenuItem { text: "добавить прошлые записи" onClicked: { vkapi.messages_getHistory(chat_id,listView.count,20,-1) } } } width: parent.width height: parent.height-name_info.height spacing: 30 anchors { top:name_info.bottom } clip:true delegate:MessageItem{ isOut:out author: isMulti?first_name+ " "+last_name:"" fwdMsg: historyModel.getFwdMessage(id) attachWallpost: historyModel.getFwdPost(id) } } Item{ id:sendArea anchors.bottom: parent.bottom // anchors.left:parent.left width: parent.width height: messageArea.height+attachmentstoSend.height+Theme.paddingSmall SilicaListView{ id:attachmentstoSend width:parent.width height: model.count>0?Theme.itemSizeMedium:0 anchors.bottom: messageArea.top model:c_attachmentsModelToSend orientation:Qt.Horizontal spacing:5 delegate: Image{ width:Theme.itemSizeMedium height:width sourceSize: Qt.size(width,height) source:"image://nemoThumbnail/"+c_source IconButton{ icon.source: "image://theme/icon-s-clear-opaque-cross?"+Theme.highlightColor anchors.centerIn: parent //onClicked: c_attachmentsModelToSend.(index) } Rectangle{ color:"black" visible: c_status>0 opacity: 0.5 } BusyIndicator{ size: BusyIndicatorSize.Medium anchors.centerIn: parent running: c_status>0 } } } IconButton { id:skrepkaWizard icon.source: "image://theme/icon-m-attach" highlighted: false anchors.bottom: messageArea.bottom anchors.right:messageArea.left anchors.bottomMargin: 25 onClicked: attachDrawer.open=true } TextArea { id:messageArea anchors.bottom: parent.bottom anchors.right: sendButton.left height: Math.min(Theme.itemSizeExtraLarge,implicitHeight)//Math.max(page.height/5, Math.min(page.height/3,implicitHeight)) width:parent.width-sendButton.width- skrepkaWizard.width } IconButton { id:sendButton icon.source: "image://theme/icon-m-message" highlighted: false anchors.bottom: messageArea.bottom // anchors.left:messageArea.right anchors.right:parent.right anchors.bottomMargin: 25 onClicked: { console.log(parent.width,sendButton.width,messageArea.width) vkapi.messages_send(chat_id,messageArea.text) messageArea.selectAll() messageArea.text="" highlighted=!highlighted // historyModel.clear_Messages() // vkapi.messages_getHistory(chat_id,false,20,0) } } } MouseArea { enabled: attachDrawer.open anchors.fill: listView onClicked: attachDrawer.open = false } background:Loader{ id:attachLoader anchors.fill: parent source:"../items/AttachComponent.qml" } } MessageModel{ id:historyModel Component.onCompleted: { historyModel.DataProvider=c_dataProvider historyModel.userId=chat_id } } DocumentGalleryModel { id: galleryModel rootType: DocumentGallery.Image properties: [ "url", "title", "dateTaken" ] autoUpdate: true sortProperties: ["-dateTaken"] } AttachmentsToSendModel{ id:c_attachmentsModelToSend } Connections { target: attachLoader.item onS_items: { console.log(items) var types = ["photo","video","place","audio","doc","photoVK","videoVK"]; for(var i=0;i<items.length;i++) { console.log(items[i]); var file = galleryModel.get(items[i].id).url; console.log(file) c_attachmentsModelToSend.addAttachment(file,types[items[i].type]) } } } }
error still the same. If Items in model >0, then SegFault
If inAttachmentToSendModel.cpp
useList<AttachmentToSendItem> Items
instead ofList<AttachmentToSendItem*> Items
as collection, After adding new item it deletes immediately and calling SegFault. -
Strange, but SegFault is gone.
I removed realization ofQModelIndex AttachmentsToSendModel::index(int row, int column, const QModelIndex &parent)
and SegFault is gone.
Any ideas why? -
this
QModelIndex AttachmentsToSendModel::index(int row, int column, const QModelIndex &parent) const { }
should not even compile, you need to return something...
-
I understand my stupid errror. Problem solved.