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


  • Moderators

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


  • Moderators

    @TheFlyingMooseMan
    you need to call beginResetModel() and endResetModel() 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


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.