最近写了一个查单词的类似有道词典的软件,里面就有一个自动补全功能(即当你输入一个字母时,就会出现几个候选项)。这个自动补全功能十分常见,百度搜索关键词时就会出现。不过它们这些补全功能都是与你输入的进行首字匹配,有时也会不方便。例如,如果我输入一个“好”,如果是首字匹配的话会出现下图:
如果是句中匹配的话,则是这种情况:
你可以根据自己的要求进行选择哪一种模式。
Qt中自带QCompleter类来实现上面的自动补全功能,读者可以在Qt自带的demo中很容易的学会该类的使用。下面我要讲的是自己构造一个比QCompleter更强大的类。有人会说,为什么有现成的不用,要自己写一个类呢?因为,我用QCompleter类的时候发现,它只有句首匹配模式(可能是我没仔细看文档,不知道可以改变模式),其次,当我的词库非常大的时候,有的时候就不会出现下拉自动补全列表,具体原因也不清楚。所以自己写了一个类,来实现QCompleter类所没有功能。废话不多说,直接见代码(代码注解比较详细,就不仔细讲解了,widget.ui文件也不给出了,就是一个空的界面):
1、widget.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #ifndef WIDGET_H #define WIDGET_H
#include <QWidget> #include<QMouseEvent>
namespace Ui { class Widget; }
class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); void mousePressEvent(QMouseEvent *event); private: Ui::Widget *ui; signals: void movesignal(); };
#endif
|
2.completelineedit.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #ifndef COMPLETELINEEDIT_H #define COMPLETELINEEDIT_H #include <QLineEdit> #include <QStringList> #include<QFile> #include<QTextCodec> #include<QDebug> class QListView; class QStringListModel; class QModelIndex; class CompleteLineEdit : public QLineEdit { Q_OBJECT public: CompleteLineEdit(QStringList words, QWidget *parent = 0); public slots: void setCompleter(const QString &text); void completeText(const QModelIndex &index); protected: virtual void keyPressEvent(QKeyEvent *e); virtual void focusOutEvent(QFocusEvent *e); private slots: void replyMoveSignal(); private: QStringList words; QListView *listView; QStringListModel *model; }; #endif
|
3.widget.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include "widget.h" #include "ui_widget.h"
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); }
Widget::~Widget() { delete ui; }
void Widget::mousePressEvent(QMouseEvent *event) { emit movesignal(); }
|
4.completelineedit.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
| #include "CompleteLineEdit.h" #include <QKeyEvent> #include <QListView> #include <QStringListModel> #include <QDebug> CompleteLineEdit::CompleteLineEdit(QStringList words, QWidget *parent) : QLineEdit(parent), words(words) { listView = new QListView(this); model = new QStringListModel(this); listView->setWindowFlags(Qt::ToolTip); connect(this, SIGNAL(textChanged(const QString &)), this, SLOT(setCompleter(const QString &))); connect(listView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(completeText(const QModelIndex &))); }
void CompleteLineEdit::focusOutEvent(QFocusEvent *e) { }
void CompleteLineEdit::replyMoveSignal() { listView->hide(); }
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 { listView->hide(); QLineEdit::keyPressEvent(e); } } else { QLineEdit::keyPressEvent(e); } }
void CompleteLineEdit::setCompleter(const QString &text) { if (text.isEmpty()) { listView->hide(); return; } if ((text.length() > 1) && (!listView->isHidden())) { return; } QStringList sl; foreach(QString word, words) { if (word.contains(text)) { sl << word; }
} model->setStringList(sl); listView->setModel(model); if (model->rowCount() == 0) { return; } listView->setMinimumWidth(width()); listView->setMaximumWidth(width()); QPoint p(0, height()); int x = mapToGlobal(p).x(); int y = mapToGlobal(p).y() + 1; listView->move(x, y); listView->show(); }
void CompleteLineEdit::completeText(const QModelIndex &index) { QString text = index.data().toString(); setText(text); listView->hide(); }
|
5.main.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| #include <QApplication> #include "CompleteLineEdit.h" #include"widget.h" int main(int argc, char *argv[]) { QApplication a(argc, argv);
QStringList sl;
QFile *inFile=new QFile ("input.txt");
if(!inFile->open(QIODevice::ReadOnly|QIODevice::Text)) { qDebug()<<"cannot read!";
}
while(!inFile->atEnd()) { QByteArray line = inFile->readLine(); QTextCodec* gbk_codec = QTextCodec::codecForName("GBK"); QString gbk_string = gbk_codec->toUnicode(line); if (!line.isEmpty()) sl << gbk_string.trimmed(); }
inFile->close(); sl<< "你好" << "好的" << "好吗" << "你的" << "真好啊" << "天真" << "你好吗";
Widget *w= new Widget(); CompleteLineEdit * edit= new CompleteLineEdit(sl,w);
w->show();
return a.exec(); }
|
最后放两张查单词软件用到的自动补全功能的截图:
基于Qt的词典开发系列
- 词典框架设计及成品展示
- 本地词典的设计
- 开始菜单的设计
- 无边框窗口的缩放与拖动
- 无边框窗口的拖动
- 界面美化设计
- 调用网络API
- 用户登录及API调用的实现
- JSON数据解析
- 国际音标的显示
- 系统托盘的显示
- 调用讲述人
- 音频播放
- 自动补全功能
- HTML特殊字符及正则表达式
- 后序
作品下载地址(发布版):http://download.csdn.net/detail/tengweitw/8548767
作品下载地址(绿色版):http://download.csdn.net/detail/tengweitw/8830495
源码下载地址:http://download.csdn.net/detail/tengweitw/8830503