Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to force QCompleter to check second word in QLineEdit

Tags:

qt

I have a feature to implement a textbox with auto completion. I have found a code which uses QLineEdit and QCompleter.

Hence I have my string values, "one" , "two" , "three" ect.

Once I type "on" the completer suggests me every word in the list with prefix "on". But after I select "one" from the list and try to type the second word, completer does not work.

Is there a functionality in QCompleter or overall in Qt, which provides such functionality. I haven found it in documentation.

See my found code:

#include <QApplication>
#include<QStringList>
#include<QLineEdit>
#include<QCompleter>
#include<QHBoxLayout>
#include<QWidget>
#include<QLabel>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QWidget *win=new QWidget();
    QHBoxLayout *lay=new QHBoxLayout();
    QStringList wordList;
    wordList << "alpha" << "omega" << "omicron" << "zeta"<<"america"<<"orion"<<"amit"<<"Odssey";
    QLabel *lbl=new QLabel("Select");
    QLineEdit *lineEdit = new QLineEdit();
    lbl->setBuddy(lineEdit);
    QCompleter *completer = new QCompleter(wordList);
    completer->setCaseSensitivity(Qt::CaseInsensitive); //Make caseInsensitive selectio
    lineEdit->setCompleter(completer);
    lay->addWidget(lbl);
    lay->addWidget(lineEdit);
    win->setLayout(lay);
    win->showMaximized();
    return a.exec();
}
like image 511
Eduard Rostomyan Avatar asked Feb 14 '14 07:02

Eduard Rostomyan


2 Answers

I think you need override several methods in QLineEdit. My version of code:

mclineedit.h

#ifndef MCLINEEDIT_H
#define MCLINEEDIT_H

#include <QLineEdit>

class MCLineEdit : public QLineEdit
{
    Q_OBJECT
public:
    explicit MCLineEdit(QWidget *parent = 0);
    void setMultipleCompleter(QCompleter*);

protected:
    void keyPressEvent(QKeyEvent *e);

private:
    QString cursorWord(const QString& sentence) const;

private slots:
    void insertCompletion(QString);

private:
    QCompleter* c;
};

#endif // MCLINEEDIT_H

mclineedit.cpp

#include "mclineedit.h"
#include <QCompleter>
#include <QTextCursor>
#include <QAbstractItemView>
#include <QScrollBar>

MCLineEdit::MCLineEdit(QWidget *parent) :
    QLineEdit(parent)
{
}
void MCLineEdit::keyPressEvent(QKeyEvent *e)
{
    QLineEdit::keyPressEvent(e);
    if (!c)
        return;

    c->setCompletionPrefix(cursorWord(this->text()));
    if (c->completionPrefix().length() < 1)
    {
        c->popup()->hide();
        return;
    }
    QRect cr = cursorRect();
         cr.setWidth(c->popup()->sizeHintForColumn(0)
                     + c->popup()->verticalScrollBar()->sizeHint().width());
    c->complete(cr);

}
QString MCLineEdit::cursorWord(const QString &sentence) const
{
    return sentence.mid(sentence.left(cursorPosition()).lastIndexOf(" ") + 1,
                        cursorPosition() -
                        sentence.left(cursorPosition()).lastIndexOf(" ") - 1);
}

void MCLineEdit::insertCompletion(QString arg)
{
    setText(text().replace(text().left(cursorPosition()).lastIndexOf(" ") + 1,
                           cursorPosition() -
                           text().left(cursorPosition()).lastIndexOf(" ") - 1,
                           arg));
}

void MCLineEdit::setMultipleCompleter(QCompleter* completer)
{
    c = completer;
    c->setWidget(this);
    connect(c, SIGNAL(activated(QString)),
            this, SLOT(insertCompletion(QString)));
}

To learn more visit http://qt-project.org/doc/qt-4.8/tools-customcompleter.html (with QTextEdit).

like image 187
Filipp Klochko Avatar answered Nov 20 '22 19:11

Filipp Klochko


Here I have found a solution.

#ifndef COMPLETER_H
#define COMPLETER_H
#include <QCompleter>
#include <QString>
#include <QStringList>
#include <QLineEdit>

class Completer:public QCompleter
{
Q_OBJECT
public:
    explicit Completer(QStringList stringList, QObject *parent=0);
    virtual QString pathFromIndex(const QModelIndex &index)const;
    virtual QStringList splitPath(const QString&)const;

public slots:
    void onLineEditTextChanged();
private:
    mutable int cursorPos_;
};


class ExpressionLineEdit: public QLineEdit
{
    Q_OBJECT
    public:
        explicit ExpressionLineEdit(QWidget *parent=0);
private:
    QStringList stringList;
    Completer *completer_;
};
#endif // COMPLETER_H

#include <completer.h>
#include <QDebug>
Completer::Completer(QStringList stringList, QObject *parent)
    : QCompleter(stringList,parent)
    , cursorPos_(-1)
{

}

ExpressionLineEdit::ExpressionLineEdit(QWidget* parent)
    : QLineEdit(parent)
{
stringList << "minRoute" << "minPitch" << "minSpacing";
completer_ = new Completer(stringList, this);
setCompleter(completer_);

    QObject::connect(this, SIGNAL(textChanged(const QString&)),
             completer_, SLOT(onLineEditTextChanged()));

    QObject::connect(this, SIGNAL(cursorPositionChanged(int, int)),
            completer_, SLOT(onLineEditTextChanged()));
}

QString Completer::pathFromIndex(const QModelIndex &index) const
{
    QString newStr = index.data(Qt::EditRole).toString();
    ExpressionLineEdit *lineEdit = qobject_cast<ExpressionLineEdit*>(parent());
    QString str = lineEdit->text();
    int prevSpacePos = str.mid(0, lineEdit->cursorPosition()).lastIndexOf(' ');

    int curPos = lineEdit->cursorPosition();
    int nextSpacePos = str.indexOf(' ', curPos);
    if (nextSpacePos == -1) {
        nextSpacePos = str.size();
}

QString part1 = str.mid(0, prevSpacePos + 1);
QString pre = str.mid(prevSpacePos + 1, curPos - prevSpacePos - 1);
QString post = str.mid(curPos, nextSpacePos - curPos);
QString part2 = str.mid(nextSpacePos);

    cursorPos_ = curPos + newStr.size() - pre.size();
    return part1 + newStr + part2;
}

void Completer::onLineEditTextChanged()
{
    qDebug() << "Completer::onLineEditTextChanged()" << cursorPos_;
    if (cursorPos_ != -1) {
        ExpressionLineEdit *lineEdit = qobject_cast<ExpressionLineEdit*>(parent());
        lineEdit->setCursorPosition(cursorPos_);
        cursorPos_ = -1;
    }
}

QStringList Completer::splitPath(const QString &path) const
{
     cursorPos_ = -1;
     ExpressionLineEdit *lineEdit = qobject_cast<ExpressionLineEdit*>(parent());
     QString text = lineEdit->text();
     QStringList stringList;
     QString str;
     int index = text.mid(0,lineEdit->cursorPosition()).lastIndexOf(' ');
     str = text.mid(index, lineEdit->cursorPosition()-index);
     str.trimmed();
     str.replace(" ", "");
     stringList << str;
     return stringList;
}
like image 3
Eduard Rostomyan Avatar answered Nov 20 '22 19:11

Eduard Rostomyan