2014-02-14 17 views
5

我有一個功能來實現具有自動完成功能的文本框。 我找到了一個使用QLineEdit和QCompleter的代碼。如何強制QCompleter檢查QLineEdit中的第二個字

因此,我有我的字符串值,「一」,「兩」,「三」等。

一旦我輸入「on」,完成者就會在列表中以「on」的形式向我建議每一個單詞。 但是,從列表中選擇「one」並嘗試輸入第二個單詞後,完成程序不起作用。

QCompleter中是否有功能,或者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

用於QLineEdit的QCompleter不檢查每個單詞,而是檢查整個內容。如果你的字符串是「alpha歐米茄」,完成者會給你一個這個字符串的命中。您最終應該繼承QLineEdit並設置實現,以在每個單詞上使用QCompleter而不是整個內容。 –

+0

以及如何設置QLineEdit的實現,QCompleter會檢查除整個內容以外的每個單詞? –

+0

我很抱歉,但我沒有時間給你一個QLineEdit-Subclass的完整實現。除此之外,你可以學習更多的形式,它自己做。最終,您可以設置QLineEdits完成程序,以識別用QCompleter :: setCompletionPrefix(const QString&前綴)編寫的最後一個單詞;其中前綴只是您要完成的最後一個單詞 –

回答

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; 
} 
1

我需要這樣的東西!但是在我的測試中,我注意到了一些東西,有些東西可以被刪除(例如,QString文章未被實際使用,它可以被刪除)。另外,如果你輸入一個單詞列表,那麼在你的實現中似乎存在一個錯誤(至少從我的測試中),如果你使用箭頭鍵上/下,回去在中間的某個地方輸入一個單詞在自動完成列表中,第一個突出顯示的單詞將被放置在正確的位置,但在此之後,光標跳轉到結尾(不管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; 
} 
+0

自從我最初發布以來,我做了一些更改,我認爲我的實現基本上沒有bug,現在相當實用,如果有人嘗試我的代碼並發現錯誤,請告訴我! – Tory

相關問題