QLineEdit实现自动补全

由于项目所需,自定义了一个继承自QLineEdit的实现输入自动过滤补全控件,在此贴出记录一下,以备后用。
代码比较简单易懂,并且有跟多人实现过所以就不做说明了。
.h
#ifndef COMPLETELINEEDIT_H
#define COMPLETELINEEDIT_H

#include <QLineEdit>
#include <QStringList>

class QListView;
class QStringListModel;
class QModelIndex;

class CompleteLineEdit : public QLineEdit {

    Q_OBJECT
public:
    CompleteLineEdit(QStringList words, QWidget *parent = 0);

    void bindDataSource(QStringList source);
    void popshow();
    void gettext();
    ~CompleteLineEdit();

public slots:
    void setCompleter(const QString &text); // 动态的显示完成列表
    void completeText(const QModelIndex &index); // 点击完成列表中的项,使用此项自动完成输入的单词

protected:
    virtual void keyPressEvent(QKeyEvent *e);
    virtual void focusOutEvent(QFocusEvent *e);
    virtual void focusInEvent(QFocusEvent *e);

private:
    QStringList words; // 整个完成列表的单词
    QListView *listView; // 完成列表
    QStringListModel *model; // 完成列表的model
    QWidget *parentwidget;
    QString currstr;

};

#endif // COMPLETELINEEDIT_H
.cpp
#include "completelineedit.h"
#include <QKeyEvent>
#include <QListView>
#include <QStringListModel>
#include <QDebug>

CompleteLineEdit::CompleteLineEdit(QStringList words, QWidget *parent)
    : QLineEdit(parent), words(words) {
    parentwidget=parent;
    listView = new QListView(this);
    model = new QStringListModel(this);
    listView->setWindowFlags(Qt::ToolTip);
    listView->setFocusPolicy(Qt::NoFocus);
    listView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
    connect(this, SIGNAL(textChanged(const QString &)), this, SLOT(setCompleter(const QString &)));
    connect(listView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(completeText(const QModelIndex &)));
}

void CompleteLineEdit::bindDataSource(QStringList source)
{
    this->words = source;
}

void CompleteLineEdit::popshow()
{
    setCompleter("");
}

void CompleteLineEdit::gettext()
{
    if(!words.contains(this->text())){
        this->setText(listView->currentIndex().data().toString());
    }
}


CompleteLineEdit::~CompleteLineEdit()
{
    parentwidget->clearFocus();
    this->clearFocus();
    delete listView;
}

void CompleteLineEdit::focusOutEvent(QFocusEvent *e) {
    this->clearFocus();
    if(!words.contains(this->text()))
    {
        this->setText(currstr);
    }
    listView->hide();
    QLineEdit::focusOutEvent(e);
}

void CompleteLineEdit::focusInEvent(QFocusEvent *e)
{
    setCompleter("");
    currstr=this->text();
    QLineEdit::focusInEvent(e);
}

void CompleteLineEdit::keyPressEvent(QKeyEvent *e) {
    if (!listView->isHidden()) {
        int key = e->key();
        int count = listView->model()->rowCount();
        QModelIndex currentIndex = listView->currentIndex();
        if (Qt::Key_Down == key) {
            int row = currentIndex.row() + 1;
            if (row >= count) {
                row = 0;
            }
            QModelIndex index = listView->model()->index(row, 0);
            listView->setCurrentIndex(index);
        } else if (Qt::Key_Up == key) {
            int row = currentIndex.row() - 1;
            if (row < 0) {
                row = count - 1;
            }
            QModelIndex index = listView->model()->index(row, 0);
            listView->setCurrentIndex(index);
        } else if (Qt::Key_Escape == key) {
            listView->hide();
        } else if (Qt::Key_Enter == key || Qt::Key_Return == key) {
            if (currentIndex.isValid()) {
                QString text = listView->currentIndex().data().toString();
                setText(text);
            }
            listView->hide();
        } else {
            QLineEdit::keyPressEvent(e);
        }
    } else {
        QLineEdit::keyPressEvent(e);
    }
}

void CompleteLineEdit::setCompleter(const QString &text) {
    /*if (text.isEmpty()) {
        listView->hide();
        return;
    }*/
    if(!this->hasFocus())
        return;
    if ((text.isEmpty()) && (!listView->isHidden())) {
        return;
    }
    QString newtext=text;
    if(listView->isHidden())
        newtext="";
    QStringList sl;
    foreach(QString word, words) {
        if(newtext.isEmpty()) {
            sl << word;
        } else {
            if (word.contains(newtext)) {
                sl << word;
            }
        }
    }
    if(sl.count() == 0) {
        foreach(QString word, words) {
            sl << word;
        }
    }
    model->setStringList(sl);
    listView->setModel(model);
    if (model->rowCount() == 0) {
        return;
    }
    // Position the text edit
    listView->setMinimumWidth(width());
    listView->setMaximumWidth(width());
    QPoint p(parentwidget->parentWidget()->x(), height());
    int x = this->mapToGlobal(p).x();
    int y = this->mapToGlobal(p).y() + 1;
    int h=y;
    //选择展开方向,由于我的开发板是600×800的,所以以下代码不具有通用性。
    if(y>=350)
    {
        h=qMin((600-y),model->rowCount()*26);
    }
    else if((350-y)<(y-height()))
    {
        h=qMin((y-height()),model->rowCount()*26);
        y=y-h-height();
    }
    else {
        h=qMin((350-y),model->rowCount()*26);
    }
    listView->move(x,y);
    listView->resize(width(),h-1);
    listView->setStyleSheet("QListView::item{\
                            height:25px;\
                            }\
                            QListView {\
                            background-color: #00FF7F;\
                            }");
    listView->show();
    QModelIndex index=model->index(0,0);
    listView->setCurrentIndex(index);

}

void CompleteLineEdit::completeText(const QModelIndex &index) {
    QString text = index.data().toString();
    setText(text);
    listView->hide();
    this->clearFocus();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值