1,序
通常我们使用QLineEdit的时候,可以使用自动补全提示,如pic-1所示,通过键入关键字,QLineEdit可以为我们提示相关内容。但是Qt 4.x没有为QTextEdit提供设置QCompleter的接口。网络上已经给出大量范例代码,基本上出自qt官方文档。
本文章将做对以下几个方面进行剖析:
1. 在获取QTextEdit中,光标所在位置对应的单词时,不使用QTextCursor::WordUnderCursor。因为该模式会忽略”$、%”等特殊符号。
2. 裁剪官方代码,祭出关键框架代码和主要逻辑关系介绍。
3. 讲解相关知识细节。
// 如下所示,为QLineEdit添加自动提示功能
#include <QApplication>
#include <QCompleter>
#include <QLineEdit>
#include <QStringList>
int main(int ac, char **av) {
QApplication app(ac, av);
QLineEdit *lineEdit = new QLineEdit;
QStringList indicator;
for (int index = 0; index < 3; ++index) {
indicator << QString("%1").arg(index);
}
QCompleter *completer = new QCompleter(indicator, lineEdit);
lineEdit->setCompleter(completer);
lineEdit->show();
return app.exec();
}
pic-1 : 自动提示
2,文件组织和代码详解
为了更加清晰的说明设计的总框架和内在的勾连,工程只涉及3个文件,如图pic-2所示。其中,main.cpp为入口函数main()文件,其他两个为类CompleterTextEdit对应的header文件和source文件。
pic-2
下面将分别按照(1)原理解释;(2)构思框架;(3)代码解读。三个步骤,整体设计进行剖析。
1, 原理解释
在Qt中,我们每次敲击键盘,都会引起QTextEdit中的事件接收函数keyPressEvent(QKeyEvent *e)的调用。因此,该函数作为着手点,可以对每次敲击键盘进行响应的操作。
从QTextEdit中,我们看到有光标在闪动,这个闪动的光标在Qt中称作cursor。这个cursor对应到QTextEdit中,就是QTextCursor类对象,我们可以通过QTextEdit来获取QTextCursor类型的对象。我们可以操纵cursor(也就是光标)来进行各种动作,比如移动光标,在光标处插入文本,选中文本。其中,本文内容与Qt官方示例最大的不同,在于,当获得cursor所在位置对应的单词时,不采用WordUnderCursor进行控制。下面代码将显示出这点。
QCompleter类只有在调用complete()函数后,才会弹出提示下拉列表,提示下拉列表如上面图pic-1所示。为了让QCompleter能够根据关键字进行搜索,我们还需要在调用complete()之前,调用setCompletionPrefix()函数设置关键字前缀。当我们选中下拉列表中的某个选项后,按enter键,QCompleter会发出activated()信号,通过接收并处理该信号,就可以插入文本并对QTextEdit中的cursor进行移动操作。
2, 构思框架
本设计有三个关键点:
(1)获取当前光标所在位置处,对应的单词。因为WordUnderCursor会忽略掉单次内的特殊符号,如$等,因此我们不能使用该方法。
(2)涉及到一个事件(QKeyEvent)和一个信号(activated())的处理。
(3)如何将QCompleter选中的字符串在QTextEdit中补全。
3, 代码解读
下面将祭出代码。其中,外部main()函数将自定义的QCompleter放入自定义的CompleterTextEdit中。CompleterTextEdit类内部处理自动提示功能。
// completertextedit.h
#ifndef COMPLETERTEXTEDIT_H
#define COMPLETERTEXTEDIT_H
#include <QTextEdit>
#include <QString>
QT_BEGIN_NAMESPACE
class QCompleter;
QT_END_NAMESPACE
class CompleterTextEdit : public QTextEdit
{
Q_OBJECT
public:
explicit CompleterTextEdit(QWidget *parent = 0);
void setCompleter(QCompleter *completer);
protected:
void keyPressEvent(QKeyEvent *e); // 响应按键盘事件
private slots:
void onCompleterActivated(const QString &completion); // 响应选中QCompleter中的选项后,QCompleter发出的activated()信号
private:
QString wordUnderCursor(); // 获取当前光标所在的单词
private:
QCompleter *m_completer;
};
#endif // COMPLETERTEXTEDIT_H
// completertextedit.cpp
#include "completertextedit.h"
#include <QAbstractItemView>
#include <QCompleter>
#include <QKeyEvent>
#include <QString>
#include <QTextCursor>
CompleterTextEdit::CompleterTextEdit(QWidget *parent) :
QTextEdit(parent), m_completer(NULL) {
}
void CompleterTextEdit::setCompleter(QCompleter *completer) {
m_completer = completer;
if (m_completer) {
m_completer->setWidget(this);
connect(m_completer, SIGNAL(activated(QString)),
this, SLOT(onCompleterActivated(QString)));
}
}
void CompleterTextEdit::keyPressEvent(QKeyEvent *e) {
if (m_completer) {
if (m_completer->popup()->isVisible()) {
switch(e->key()) {
case Qt::Key_Escape:
case Qt::Key_Enter:
case Qt::Key_Return:
case Qt::Key_Tab:
e->ignore();
return;
default:
break;
}
}
QTextEdit::keyPressEvent(e);
QString completerPrefix = this->wordUnderCursor();
m_completer->setCompletionPrefix(completerPrefix); // 通过设置QCompleter的前缀,来让Completer寻找关键词
m_completer->complete();
}
}
void CompleterTextEdit::onCompleterActivated(const QString &completion) {
QString completionPrefix = wordUnderCursor(),
shouldInertText = completion;
QTextCursor cursor = this->textCursor();
if (!completion.contains(completionPrefix)) {// delete the previously typed.
cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, completionPrefix.size());
cursor.clearSelection();
} else { // 补全相应的字符
shouldInertText = shouldInertText.replace(
shouldInertText.indexOf(completionPrefix), completionPrefix.size(), "");
}
cursor.insertText(shouldInertText);
}
QString CompleterTextEdit::wordUnderCursor() { //不断向左移动cursor,并选中字符,并查看选中的单词中是否含有空格——空格作为单词的分隔符
QTextCursor cursor = this->textCursor();
while (cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor)) {
if (cursor.selectedText().contains(" ")) {
break;
}
}
return cursor.selectedText().remove(" ");
}
// main.cpp
#include <QApplication>
#include <QCompleter>
#include <QLineEdit>
#include <QStringList>
#include "completertextedit.h"
int main(int ac, char **av) {
QApplication app(ac, av);
CompleterTextEdit *textEdit = new CompleterTextEdit;
QStringList stringList;
for (int index = 0; index < 4; ++index) {
stringList << QString("%1%1%1%1").arg(index);
}
QCompleter *completer = new QCompleter(stringList, textEdit);
textEdit->setCompleter(completer);
textEdit->show();
return app.exec();
}
以上为所有代码。转载请注明出自本博客,代码遵循GPLv3版权许可。