我有一个功能来实现一个自动完成的文本框。 我找到了一个使用QLineEdit和QCompleter的代码。
因此我有我的字符串值,“一个”,“两个”,“三个”等。
一旦我输入“on”,完成者就会在列表中为每个单词添加前缀“on”。 但是,在我从列表中选择“one”并尝试键入第二个单词后,完成程序不起作用。
Qtmpleter中是否存在功能或Qt中的功能,它提供了这样的功能。我在文档中找到了它。
查看我找到的代码:
#include <QApplication>
#include<QStringList>
#include<QLineEdit>
#include<QCompleter>
#include<QHBoxLayout>
#include<QWidget>
#include<QLabel>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget *win=new QWidget();
QHBoxLayout *lay=new QHBoxLayout();
QStringList wordList;
wordList << "alpha" << "omega" << "omicron" << "zeta"<<"america"<<"orion"<<"amit"<<"Odssey";
QLabel *lbl=new QLabel("Select");
QLineEdit *lineEdit = new QLineEdit();
lbl->setBuddy(lineEdit);
QCompleter *completer = new QCompleter(wordList);
completer->setCaseSensitivity(Qt::CaseInsensitive); //Make caseInsensitive selectio
lineEdit->setCompleter(completer);
lay->addWidget(lbl);
lay->addWidget(lineEdit);
win->setLayout(lay);
win->showMaximized();
return a.exec();
}
答案 0 :(得分:7)
我认为你需要在QLineEdit中覆盖几个方法。我的代码版本:
mclineedit.h
#ifndef MCLINEEDIT_H
#define MCLINEEDIT_H
#include <QLineEdit>
class MCLineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit MCLineEdit(QWidget *parent = 0);
void setMultipleCompleter(QCompleter*);
protected:
void keyPressEvent(QKeyEvent *e);
private:
QString cursorWord(const QString& sentence) const;
private slots:
void insertCompletion(QString);
private:
QCompleter* c;
};
#endif // MCLINEEDIT_H
mclineedit.cpp
#include "mclineedit.h"
#include <QCompleter>
#include <QTextCursor>
#include <QAbstractItemView>
#include <QScrollBar>
MCLineEdit::MCLineEdit(QWidget *parent) :
QLineEdit(parent)
{
}
void MCLineEdit::keyPressEvent(QKeyEvent *e)
{
QLineEdit::keyPressEvent(e);
if (!c)
return;
c->setCompletionPrefix(cursorWord(this->text()));
if (c->completionPrefix().length() < 1)
{
c->popup()->hide();
return;
}
QRect cr = cursorRect();
cr.setWidth(c->popup()->sizeHintForColumn(0)
+ c->popup()->verticalScrollBar()->sizeHint().width());
c->complete(cr);
}
QString MCLineEdit::cursorWord(const QString &sentence) const
{
return sentence.mid(sentence.left(cursorPosition()).lastIndexOf(" ") + 1,
cursorPosition() -
sentence.left(cursorPosition()).lastIndexOf(" ") - 1);
}
void MCLineEdit::insertCompletion(QString arg)
{
setText(text().replace(text().left(cursorPosition()).lastIndexOf(" ") + 1,
cursorPosition() -
text().left(cursorPosition()).lastIndexOf(" ") - 1,
arg));
}
void MCLineEdit::setMultipleCompleter(QCompleter* completer)
{
c = completer;
c->setWidget(this);
connect(c, SIGNAL(activated(QString)),
this, SLOT(insertCompletion(QString)));
}
要了解详情,请访问http://qt-project.org/doc/qt-4.8/tools-customcompleter.html(使用QTextEdit)。
答案 1 :(得分:1)
我找到了解决方案。
#ifndef COMPLETER_H
#define COMPLETER_H
#include <QCompleter>
#include <QString>
#include <QStringList>
#include <QLineEdit>
class Completer:public QCompleter
{
Q_OBJECT
public:
explicit Completer(QStringList stringList, QObject *parent=0);
virtual QString pathFromIndex(const QModelIndex &index)const;
virtual QStringList splitPath(const QString&)const;
public slots:
void onLineEditTextChanged();
private:
mutable int cursorPos_;
};
class ExpressionLineEdit: public QLineEdit
{
Q_OBJECT
public:
explicit ExpressionLineEdit(QWidget *parent=0);
private:
QStringList stringList;
Completer *completer_;
};
#endif // COMPLETER_H
#include <completer.h>
#include <QDebug>
Completer::Completer(QStringList stringList, QObject *parent)
: QCompleter(stringList,parent)
, cursorPos_(-1)
{
}
ExpressionLineEdit::ExpressionLineEdit(QWidget* parent)
: QLineEdit(parent)
{
stringList << "minRoute" << "minPitch" << "minSpacing";
completer_ = new Completer(stringList, this);
setCompleter(completer_);
QObject::connect(this, SIGNAL(textChanged(const QString&)),
completer_, SLOT(onLineEditTextChanged()));
QObject::connect(this, SIGNAL(cursorPositionChanged(int, int)),
completer_, SLOT(onLineEditTextChanged()));
}
QString Completer::pathFromIndex(const QModelIndex &index) const
{
QString newStr = index.data(Qt::EditRole).toString();
ExpressionLineEdit *lineEdit = qobject_cast<ExpressionLineEdit*>(parent());
QString str = lineEdit->text();
int prevSpacePos = str.mid(0, lineEdit->cursorPosition()).lastIndexOf(' ');
int curPos = lineEdit->cursorPosition();
int nextSpacePos = str.indexOf(' ', curPos);
if (nextSpacePos == -1) {
nextSpacePos = str.size();
}
QString part1 = str.mid(0, prevSpacePos + 1);
QString pre = str.mid(prevSpacePos + 1, curPos - prevSpacePos - 1);
QString post = str.mid(curPos, nextSpacePos - curPos);
QString part2 = str.mid(nextSpacePos);
cursorPos_ = curPos + newStr.size() - pre.size();
return part1 + newStr + part2;
}
void Completer::onLineEditTextChanged()
{
qDebug() << "Completer::onLineEditTextChanged()" << cursorPos_;
if (cursorPos_ != -1) {
ExpressionLineEdit *lineEdit = qobject_cast<ExpressionLineEdit*>(parent());
lineEdit->setCursorPosition(cursorPos_);
cursorPos_ = -1;
}
}
QStringList Completer::splitPath(const QString &path) const
{
cursorPos_ = -1;
ExpressionLineEdit *lineEdit = qobject_cast<ExpressionLineEdit*>(parent());
QString text = lineEdit->text();
QStringList stringList;
QString str;
int index = text.mid(0,lineEdit->cursorPosition()).lastIndexOf(' ');
str = text.mid(index, lineEdit->cursorPosition()-index);
str.trimmed();
str.replace(" ", "");
stringList << str;
return stringList;
}
答案 2 :(得分:1)
我需要这样的东西!但是在我的测试中我确实注意到了一些事情,有一些你可以摆脱的东西(例如, QString post 实际上并没有使用它,它可以被删除)。此外,您的实现中似乎存在一个错误(至少从我的测试中),如果您输入单词列表,然后返回在中间某处输入单词,如果您使用箭头键上/下在自动完成列表中,第一个突出显示的单词将被放置在正确的位置,但在此之后光标跳转到结尾(无论onLineEditTextChanged()槽),然后它开始用自动更正列表中的那些单词替换最后一个单词。
我创建了自己的实现,其中一个主要区别是我的实现需要一个分隔符字符,并且使用该字符而不是总是使用空格,我修复了我描述的错误以上。您会注意到我的实现非常简单:
<强> DelimitedCompleter.hpp 强>
#ifndef DELIMITEDCOMPLETER_HPP
#define DELIMITEDCOMPLETER_HPP
#include <QCompleter>
class QString;
class QStringList;
/**
* class DelimitedCompleter
*
* QCompleter that supports completing multiple words in a QLineEdit, completed words are separated
* by delimiter.
*/
class DelimitedCompleter : public QCompleter {
Q_OBJECT
public:
DelimitedCompleter(QLineEdit *parent, char delimiter);
DelimitedCompleter(QLineEdit *parent, char delimiter, QAbstractItemModel *model);
DelimitedCompleter(QLineEdit *parent, char delimiter, const QStringList &list);
QString pathFromIndex(const QModelIndex &index) const;
QStringList splitPath(const QString &path) const;
private:
char delimiter;
mutable int cursor_pos = -1;
void connectSignals();
private slots:
void onActivated(const QString &text);
void onCursorPositionChanged(int old_pos, int new_pos);
};
#endif
<强> DelimitedCompleter.cpp 强>
#include "DelimitedCompleter.hpp"
#include <QDebug>
#include <QLineEdit>
#include <QStringList>
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* DELIMITEDCOMPLETER PUBLIC METHODS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
DelimitedCompleter::DelimitedCompleter(QLineEdit *parent, char delimiter)
: QCompleter(parent), delimiter(delimiter) {
parent->setCompleter(this);
connectSignals();
}
DelimitedCompleter::DelimitedCompleter(QLineEdit *parent, char delimiter, QAbstractItemModel *model)
: QCompleter(model, parent), delimiter(delimiter) {
parent->setCompleter(this);
connectSignals();
}
DelimitedCompleter::DelimitedCompleter(QLineEdit *parent, char delimiter, const QStringList &list)
: QCompleter(list, parent), delimiter(delimiter) {
parent->setCompleter(this);
connectSignals();
}
QString DelimitedCompleter::pathFromIndex(const QModelIndex &index) const {
QString auto_string = index.data(Qt::EditRole).toString();
QLineEdit *line_edit = qobject_cast<QLineEdit*>(parent());
QString str = line_edit->text();
// If cursor position was saved, restore it, else save it
if(cursor_pos != -1) line_edit->setCursorPosition(cursor_pos);
else cursor_pos = line_edit->cursorPosition();
// Get current prosition
int cur_index = line_edit->cursorPosition();
/**
* NOTE
*
* prev_delimiter_index should actually point at final white space AFTER the delimiter.
*/
// Get index of last delimiter before current position
int prev_delimiter_index = str.mid(0, cur_index).lastIndexOf(delimiter);
while(str.at(prev_delimiter_index + 1).isSpace()) prev_delimiter_index++;
// Get index of first delimiter after current position (or EOL if no delimiter after cursor)
int next_delimiter_index = str.indexOf(delimiter, cur_index);
if(next_delimiter_index == -1) {
next_delimiter_index = str.size();
}
// Get part of string that occurs before cursor
QString part1 = str.mid(0, prev_delimiter_index + 1);
// Get string value from before auto finished string is selected
QString pre = str.mid(prev_delimiter_index + 1, cur_index - prev_delimiter_index - 1);
// Get part of string that occurs AFTER cursor
QString part2 = str.mid(next_delimiter_index);
return part1 + auto_string + part2;
}
QStringList DelimitedCompleter::splitPath(const QString &path) const {
QLineEdit *line_edit = qobject_cast<QLineEdit*>(parent());
QStringList string_list;
int index = path.mid(0,line_edit->cursorPosition()).lastIndexOf(delimiter) + 1;
QString str = path.mid(index, line_edit->cursorPosition()-index).trimmed();
string_list << str;
return string_list;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* DELIMITEDCOMPLETER PRIVATE METHODS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DelimitedCompleter::connectSignals() {
connect(this, SIGNAL(activated(const QString &)), this, SLOT(onActivated(const QString &)));
connect(qobject_cast<QLineEdit*>(parent()), SIGNAL(cursorPositionChanged(int, int)),
this, SLOT(onCursorPositionChanged(int, int)));
}
void DelimitedCompleter::onActivated(const QString &text) {
cursor_pos = -1;
}
void DelimitedCompleter::onCursorPositionChanged(int old_pos, int new_pos) {
// If old_pos == cursor_pos then we are cycling through autocomplete list
// If not cycling through autocomplete list, then make sure cursor_pos is reset to -1
if(old_pos != cursor_pos) cursor_pos = -1;
}