Using a custom model with QCompleter and QLineEdit
-
Within my app I have been using a QSqlQueryModel. I want to replace this with my own model (inherited from QAbstractTableModel), as I want to add additional items to the model that drives QCompleter. I could do this in SQL, it'll be much slower. I also want to be able to remove/replace/add items to this model.
I started with the following definition of my own model class. However, the completer does not show a dropdown box when text is entered in my QLineEdit:class SearchItemModel : public QAbstractTableModel { Q_OBJECT public: SearchItemModel(); int rowCount(const QModelIndex &parent) const; Qt::ItemFlags flags(const QModelIndex &index) const { Q_UNUSED(index); return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemNeverHasChildren; } int columnCount(const QModelIndex &parent) const; QVariant data(const QModelIndex &index, int role) const; public slots: void populate(); private: typedef struct Tuple { SBIDBase::sb_type itemType; int songID; QString songTitle; int performerID; QString performerName; int albumID; QString albumTitle; QString display; } Tuple; QList<Tuple> _searchItems; void _init(); };
The completer is constructed as follows:
QCompleter* c=new QCompleter(); c->setModel(qtm); c->setCaseSensitivity(Qt::CaseInsensitive); c->setModelSorting(QCompleter::CaseSensitivelySortedModel); c->setFilterMode(Qt::MatchStartsWith); c->setCompletionMode(QCompleter::PopupCompletion); c->setCompletionColumn(0);
This works perfectly with the QSqlQueryModel, but not as well with my own model class. Do I need any other method implemented in my model?
Any hint or reply is greatly appreciated!
Thanks,
Roy -
@TheFlyingMooseMan
you should rather show the implementation of your SearchItemModel class than the definition. -
Here it is:
#include "SearchItemModel.h" #include "Context.h" #include "DataAccessLayer.h" SearchItemModel::SearchItemModel() { } int SearchItemModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return _searchItems.count(); } int SearchItemModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 3; } QVariant SearchItemModel::data(const QModelIndex &index, int role) const { Q_UNUSED(role); if(_searchItems.count()==0 || !index.isValid()) { return QVariant(); } if(index.row()<_searchItems.count()) { Tuple t=_searchItems.at(index.row()); switch(index.column()) { case 0: return t.display; break; case 1: // itemid int itemID; switch(t.itemType) { case SBIDBase::sb_type_song: itemID=t.songID; break; case SBIDBase::sb_type_performer: itemID=t.performerID; break; case SBIDBase::sb_type_album: itemID=t.albumID; break; default: itemID=-1; } return itemID; break; case 2: // itemtype return t.itemType; break; } } return QVariant(); } /// Slots void SearchItemModel::populate() { QString query=QString ( "SELECT " "t.type, " "t.song_id, " "t.title, " "t.artist_id, " "t.name, " "t.record_id, " "t.title " "FROM " "table t " ) .arg(SBIDBase::sb_type_song) .arg(SBIDBase::sb_type_album) .arg(SBIDBase::sb_type_performer) ; DataAccessLayer* dal=Context::instance()->getDataAccessLayer(); QSqlDatabase db=QSqlDatabase::database(dal->getConnectionName()); dal->customize(query); QSqlQuery queryList(query,db); while(queryList.next()) { QString key; QSqlRecord r=queryList.record(); struct Tuple t; int i=0; t.itemType=(SBIDBase::sb_type)queryList.value(i++).toInt(); t.songID=Common::parseIntFieldDB(&r,queryList.value(i++).toInt()); t.songTitle=queryList.value(i++).toString(); t.performerID=Common::parseIntFieldDB(&r,queryList.value(i++).toInt()); t.performerName=queryList.value(i++).toString(); t.albumID=Common::parseIntFieldDB(&r,queryList.value(i++).toInt()); t.albumTitle=queryList.value(i++).toString(); switch(t.itemType) { case SBIDBase::sb_type_song: t.display=QString("%1 - song by %2").arg(t.songTitle).arg(t.performerName); key=SBIDSong::createKey(t.songID); break; case SBIDBase::sb_type_album: t.display=QString("%1 - album by %2").arg(t.albumTitle).arg(t.performerName); key=SBIDAlbum::createKey(t.albumID); break; case SBIDBase::sb_type_performer: t.display=QString("%1 - performer").arg(t.performerName); key=SBIDPerformer::createKey(t.performerID); break; default: qDebug() << SB_DEBUG_ERROR << "Should not come here"; } _searchItems.append(t); } QModelIndex s=this->index(0,0); QModelIndex e=this->index(3,_searchItems.count()); emit dataChanged(s,e); }
As soon as a database connection has been established, an
emit populate
is issued to retrieve and populate the data structure. Please let me know if anything else is needed. -
@TheFlyingMooseMan
you need to callbeginResetModel()
andendResetModel()
at the beginning/end of your populate() method to inform the view about new data. -
Thanks for replying!
I added the beginResetModel() and endResetModel() -- no go.
The dropdown box still does not appear -- what does appear is a white bar, probably a fourth the size of the lineEdit widget. If a press a couple of characters and then the cursor down/up keys, I see some choices. But no dropdown box.
On top of that, quitting the app results in a crash.
I appreciate any additional hints or replies!Thanks,
Roy