PDA

View Full Version : Can a QCompleter emit a signal of index of position of its inside list, by clicking?



Alex22
21st January 2016, 20:45
Hi,
Assume there is a lineEdit With a completer that a stringList is added to the completer. While typing in the lineEdite, some words appear that by clicking on one of them, I need the index of that word in the stringList be returned. is there any signal for this?

for example:



QWidget wdg;

QStringList wordList;
wordList << "yawalpha" << "omeyawga" << "omicyaron" << "zetaYAW";

QLineEdit *lineEdit = new QLineEdit(&wdg);
QCompleter *completer = new QCompleter(wordList,&wdg);

completer->setCaseSensitivity(Qt::CaseInsensitive);
completer->setFilterMode(Qt::MatchContains);
lineEdit->setCompleter(completer);//for example when i type "omicyaron" in the lineEdit and click on that in the completer, it emits a signal with value of 2 (index of position of "omicyaron" in the wordList )

wdg.show();



thanks for any help

d_stranz
21st January 2016, 23:27
Do you ever read the Qt docs? (http://doc.qt.io/qt-5/qcompleter.html#activated) Or do you just ask every question here?

I hope that you could teach yourself find the index of a QString in a QStringList if you are given the string itself instead of posting yet another question. Besides, you already asked that question in a previous post.

Alex22
22nd January 2016, 07:49
Do you ever read the Qt docs? (http://doc.qt.io/qt-5/qcompleter.html#activated) Or do you just ask every question here?
I have read that. this signal "void QCompleter::activated(const QString & text)" with a for-loop for searching could be used. But I think an optimal way being to use "void QCompleter::activated(const QModelIndex & index)" signal. After that I read this: http://doc.qt.io/qt-5/qmodelindex.html about QModelIndex. there is no example in this doc.

ChrisW67
22nd January 2016, 20:36
QCompleter works on an option list provided by a model. The convenience constructor taking a QStringList builds that model for you, but it still exists. The row numbers in the model, probably a QStringListModel, correspond to the indices of the original list. So, when the completer tells you the QModelIndex of the activated item you know which QStringList entry that was: index.row()

Alex22
23rd January 2016, 16:14
Thanks ChrisW67,
I tried this but it returns 0 always:


connect(completer, SIGNAL(activated(QModelIndex)), this, SLOT(myslot(QModelIndex)));

void MyClass::slot_searched(QModelIndex index)
{
qDebug() << index.column(); // always returns 0
qDebug() << index.row(); // always returns 0
}

ChrisW67
23rd January 2016, 21:55
always returns 0
No it doesn't, but it also does not quite do what I thought either. Run the code below, type 'B', press down-arrow twice to highlight "bison", press Enter and you get something other than row == 0.


#include <QApplication>
#include <QLineEdit>
#include <QStringList>
#include <QCompleter>
#include <QDebug>

class Test: public QLineEdit {
Q_OBJECT
public:
Test(QWidget *p = 0): QLineEdit(p) {
QStringList const entries = QStringList()
<< "aardvark" << "bear" << "beaver" << "bison" << "civet";
QCompleter *completer = new QCompleter(entries, this);
connect(completer, SIGNAL(activated(QModelIndex)), SLOT(activated(QModelIndex)));
setCompleter(completer);
}

private slots:
void activated(const QModelIndex& index) {
qDebug() << "Activated:" << index;
}
};

int main(int argc, char **argv) {
QApplication app(argc, argv);
Test t;
t.show();
return app.exec();
}
#include "main.moc"


Unfortunately the row number is in the filtered list not the full model. The completer is using a proxy model internally. Unfortunately that model is undocumented/private or we might be able to use QAbstractProxyModel::mapToSource().

Here is an option:


class MyCompleter: public QCompleter {
Q_OBJECT
public:
MyCompleter(QObject *p = 0): QCompleter(p) {
connect(this, SIGNAL(activated(QModelIndex)), SLOT(generateIndexSignal(QModelIndex)));
}

MyCompleter(QAbstractItemModel *model, QObject *p = 0): QCompleter(model, p) {
connect(this, SIGNAL(activated(QModelIndex)), SLOT(generateIndexSignal(QModelIndex)));
}

MyCompleter(const QStringList& strings, QObject *p = 0): QCompleter(strings, p) {
connect(this, SIGNAL(activated(QModelIndex)), SLOT(generateIndexSignal(QModelIndex)));
}

signals:
void selectedSourceRow(int index);

private slots:
void generateIndexSignal(const QModelIndex& index)
{
QAbstractItemModel * const baseModel = model();
QModelIndexList indexList = baseModel->match(
baseModel->index(0, completionColumn(), QModelIndex()),
completionRole(),
index.data(),
1,
Qt::MatchExactly);
if (!indexList.isEmpty()) {
emit selectedSourceRow(indexList.at(0).row());
}
}
};

d_stranz
24th January 2016, 00:01
And all that is easier than QStringList::indexOf() when you are passing a QStringList to the completer in the first place?

11659

ChrisW67
24th January 2016, 04:43
No, but the modified QCompleter is more general than that (need not be a string list, any table model will do) and does not require the receiver to have access to the original data.

An editable QComboBox may be a better option than either.

anda_skoa
24th January 2016, 09:24
Unfortunately the row number is in the filtered list not the full model. The completer is using a proxy model internally. Unfortunately that model is undocumented/private or we might be able to use QAbstractProxyModel::mapToSource().

Interesting, didn't know that.

So alternatively one could do something like



QModelIndex baseIndex = index;
while (QAbstractProxyModel *proxy = qobject_cast<QAbstractProxyModel*>(baseIndex.model()) {
baseIndex = proxy->mapToSource(baseIndex);
}
int row = baseIndex.row();


But using a completer subclass is definitely cleaner.

Cheers,
_

d_stranz
24th January 2016, 18:19
No, but the modified QCompleter is more general than that

Point taken.

In a bit of circular logic, I suppose you could give a table model-based completer to a line-edit based delegate in a QTableView that uses the same model as the view to emulate what happens when editing a real spreadsheet - as you type a new entry, it shows completed entries based on what has already been entered into the column.