2014-02-14 3 views
5

Ich habe eine Funktion, um ein Textfeld mit automatischer Vervollständigung zu implementieren. Ich habe einen Code gefunden, der QLineEdit und QCompleter verwendet.Wie erzwinge QCompleter, um das zweite Wort in QLineEdit zu überprüfen

Daher habe ich meine Zeichenfolge Werte, "eins", "zwei", "drei" ect.

Sobald ich "on" tippe, schlägt der Completer mir jedes Wort in der Liste mit dem Präfix "on" vor. Aber nachdem ich "eins" aus der Liste ausgewählt habe und versuche, das zweite Wort einzugeben, funktioniert der Completer nicht.

Gibt es eine Funktionalität in QCompleter oder insgesamt in Qt, die solche Funktionalität bietet. Ich habe es in der Dokumentation gefunden.

meinen gefunden Code Siehe:

#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

Der QCompleter für QLineEdit prüft nicht jedes Wort, sondern den gesamten Inhalt. Wenn Ihre Strings "Alpha Omega" wären, würde der Completer Ihnen einen Treffer für diese Saite geben. Sie sollten schließlich QLineEdit ableiten und die Implementierung so einrichten, dass QCompleter für jedes Wort anstelle des gesamten Inhalts verwendet wird. –

+0

Und wie man die Implementierung für QLineEdit, für die QCompleter jedes Wort aber den gesamten Inhalt überprüft? –

+0

Es tut mir leid, aber ich habe nicht die Zeit, Ihnen eine vollständige Implementierung für eine QLineEdit-Subclass zu geben. Außerdem können Sie viel mehr lernen, indem Sie es selbst machen.Schließlich könnten Sie QLineEdits Completer einrichten, um das letzte Wort zu erkennen, das mit 'QCompleter :: setCompletionPrefix (const QString & Präfix) geschrieben wurde;' 'Präfix ist nur Ihr letztes einzelnes Wort, das Sie vervollständigen möchten. –

Antwort

7

Ich glaube, Sie verschiedene Methoden in QLineEdit außer Kraft setzen müssen: Sie werden meine Implementierung ist ganz einfacher merken. Meine Version von Code:

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

Weitere Informationen finden Sie http://qt-project.org/doc/qt-4.8/tools-customcompleter.html (mit QTextEdit) zu lernen.

+1

Es funktioniert nicht für Sprachen von rechts nach links! –

1

Hier habe ich eine Lösung gefunden.

#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

Ich brauchte etwas genau so! Bei meinen Tests bemerkte ich jedoch einige Dinge, es gibt einige Dinge, die Sie loswerden können (zum Beispiel QString post wird nicht wirklich verwendet, es kann gelöscht werden). Es scheint auch einen Bug in Ihrer Implementierung zu geben (zumindest aus meinen Tests), wenn Sie eine Liste von Wörtern eingeben, dann gehen Sie zurück, um irgendwo in der Mitte ein Wort einzugeben, wenn Sie mit den Pfeiltasten nach oben/unten gehen In der Autocomplete-Liste wird das erste hervorgehobene Wort an der richtigen Position platziert, danach springt der Cursor jedoch an das Ende (unabhängig vom Slot onLineEditTextChanged()) und ersetzt dann das letzte Wort durch das aus der Autokorrekturliste.

habe ich meine eigene Implementierung, einer der wichtigsten Unterschiede ist meine Implementierung eines Begrenzer Charakter nimmt, und das Zeichen verwendet wird, statt immer einen weißen Raum mit, und ich Es ist der Fehler, die ich oben beschrieben.

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

Ich habe einige Änderungen vorgenommen, seit ich ursprünglich gepostet habe, und ich denke, dass meine Implementierung im Grunde fehlerfrei ist und jetzt ziemlich brauchbar ist. Wenn jemand meinen Code ausprobiert und Fehler findet, lasst es mich wissen! – Tory

Verwandte Themen