PDA

View Full Version : a smarter QCompleter



ber_44
7th May 2007, 20:31
Hello,
Is there another QCompleter-like class that does the same thing as the Index search in Qt Assistant? QCompleter will not match items where the search term is in the middle of the item.
E.g. Qt Assistant can complete "ActiveX" giving this result:
- A standard ActiveX and the "simple" ActiveQt widget
- testcon - An ActiveX Test Container (ActiveQt)
QCompleter cannot do this.

fullmetalcoder
7th May 2007, 20:43
You can always have a look at the Qt Assistant sources... However it is not that simple because Qt Assistant does not use anything like a QCompleter but instead builds a custom database and search it in its own way...

As QCompleter is not designed to be extended you'll have to reimplement it from scratch (or from Qt sources ;)) to achieve what you want. If you're interested in a simpler example of completion classes you might want to have a look at the QCompletionWidget class I've crafted to handle completion in Edyuk. It relies on custom model and nodes types but should not be too hard to adapt to fit your needs.

wysota
7th May 2007, 21:21
Isn't Assistant using a sort filter proxy and not a completer? At least I can't get any "completion" from it :) With a sort filter proxy matching in the middle of a string is trivial.

ber_44
19th May 2007, 00:22
I tried this, but setFilterRegExp() has no effect.



void FindDialog::filterRegExpChanged(const QString &s) {
proxyModel->setFilterRegExp(QRegExp(s, Qt::CaseInsensitive, QRegExp::RegExp));
}

FindDialog::FindDialog(QWidget *parent) : QDialog(parent) {
...
model = new QStringListModel(this);
model->setStringList(names);
proxyModel = new QSortFilterProxyModel(this);
proxyModel->setSourceModel(model);
proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
completer = new QCompleter(proxyModel, this);
completer->setCaseSensitivity(Qt::CaseInsensitive);
completer->setModelSorting(QCompleter::CaseInsensitivelySorte dModel);

label = new QLabel(tr("...:"), this);
lineEdit = new QLineEdit(this);
lineEdit->setCompleter(completer);
label->setBuddy(lineEdit);
findButton = new QPushButton(tr("&Find"),this);
findButton->setDefault(true);
connect(findButton, SIGNAL(clicked()), parent->parentWidget()->parentWidget(), SLOT(show_image()));
connect(lineEdit, SIGNAL(textEdited(const QString &)), this, SLOT(filterRegExpChanged(const QString &)));
...
}

wysota
19th May 2007, 00:54
Could you provide a minimal compilable example reproducing the problem?

ber_44
19th May 2007, 07:50
#include <QtGui>

bool caseInsensitiveLessThan(const QString &s1, const QString &s2) {
return s1.toLower() < s2.toLower();
}

class FindDialog : public QDialog
{
Q_OBJECT
public:
FindDialog(QWidget *parent = 0);
QString get_item() const { return lineEdit->text(); }
void clear() { lineEdit->setText(""); }
private slots:
void filterRegExpChanged(const QString &s) {
proxyModel->setFilterRegExp(QRegExp(s, Qt::CaseInsensitive, QRegExp::RegExp));
}
private:
QSortFilterProxyModel *proxyModel;
QStringListModel *model;
QList<QString> names;
QLabel *label;
QLineEdit *lineEdit;
QCompleter *completer;
QPushButton *findButton;
};

FindDialog::FindDialog(QWidget *parent) : QDialog(parent) {
for (int i = 0; i < 5; i++)
names << QString::number(i) + QString(" ") +
QString::number(i + 1) + QString(" ") +
QString::number(i + 2);
qSort(names.begin(), names.end(), caseInsensitiveLessThan);

model = new QStringListModel(this);
model->setStringList(names);
proxyModel = new QSortFilterProxyModel(this);
proxyModel->setSourceModel(model);
proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
completer = new QCompleter(proxyModel, this);
completer->setCaseSensitivity(Qt::CaseInsensitive);
completer->setModelSorting(QCompleter::CaseInsensitivelySorte dModel);

label = new QLabel(tr("...:"), this);
lineEdit = new QLineEdit(this);
lineEdit->setCompleter(completer);
label->setBuddy(lineEdit);
findButton = new QPushButton(tr("&Find"),this);
findButton->setDefault(true);
connect(lineEdit, SIGNAL(textEdited(const QString &)), this, SLOT(filterRegExpChanged(const QString &)));

QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->addWidget(label);
mainLayout->addWidget(lineEdit);
mainLayout->addWidget(findButton, 0, Qt::AlignRight);
setLayout(mainLayout);

setWindowTitle(tr("Find"));
}

#include "main.moc"

int main(int argc, char **argv){
QApplication app(argc, argv);
FindDialog *dialog = new FindDialog(0);
dialog->show();
return app.exec();
}

wysota
19th May 2007, 08:43
With this approach you shouldn't use a completer anymore, proxy does all the work for you. You just need to find a way to display the list of available items (either through a fake listview like QCompleter does or for example through an editable combobox).

wambagilles
30th March 2011, 07:10
where can i have the sources of Edyuk to look at that class?