Bonjour.
Je suis en train d’améliorer mon moteur de jeu (http://www.haiecapique.fr/marble.html)
Pour l’éditeur de script j'utilise QScintilla, mais la complétion de la forme "toto." affiche "tata" n'est pas géré.

On m'a conseillé de passer par QCompleter.
J'arrive à refaire la même chose qu'avec QScintilla, mais mon système d’auto-complétion ne fonctionne que sur un QLineEdit, pas sur un QTextEdit.

Je vous met mon code :
treemodelcompleter.h
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
 
#ifndef TREEMODELCOMPLETER_H
#define TREEMODELCOMPLETER_H
 
#include <QCompleter>
 
class TreeModelCompleter : public QCompleter {
    Q_OBJECT
    Q_PROPERTY(QString separator READ separator WRITE setSeparator)
 
public:
    TreeModelCompleter(QObject *parent = 0);
    TreeModelCompleter(QAbstractItemModel *model, QObject *parent = 0);
 
    QString separator() const;
public slots:
    void setSeparator(const QString &separator);
 
protected:
    QStringList splitPath(const QString &path) const;
    QString pathFromIndex(const QModelIndex &index) const;
 
private:
    QString sep;
};
 
#endif // TREEMODELCOMPLETER_H

treemodelcompleter.cpp
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
 
#include "treemodelcompleter.h"
#include <QStringList>
 
TreeModelCompleter::TreeModelCompleter(QObject *parent) :
    QCompleter(parent) {
}
 
TreeModelCompleter::TreeModelCompleter(QAbstractItemModel *model, QObject *parent) :
    QCompleter(model, parent) {
}
 
void TreeModelCompleter::setSeparator(const QString &separator) {
    sep = separator;
}
 
QString TreeModelCompleter::separator() const {
    return sep;
}
 
QStringList TreeModelCompleter::splitPath(const QString &path) const {
    if (sep.isNull()) {
        return QCompleter::splitPath(path);
    }
 
    return path.split(sep);
}
 
QString TreeModelCompleter::pathFromIndex(const QModelIndex &index) const {
    if (sep.isNull()) {
        return QCompleter::pathFromIndex(index);
    }
 
    // navigate up and accumulate data
    QStringList dataList;
    for (QModelIndex i = index; i.isValid(); i = i.parent()) {
        dataList.prepend(model()->data(i, completionRole()).toString());
    }
 
    QString t = dataList.join(sep);
    return dataList.join(sep);
}

mainwindow.h
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
 
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
 
#include <QTextEdit>
 
class TreeModelCompleter;
class QAbstractItemModel;
class QLineEdit;
 
class MainWindow : public QTextEdit {
    Q_OBJECT
 
public:
    MainWindow(QWidget *parent = 0);
 
protected:
     void keyPressEvent(QKeyEvent *e);
     void focusInEvent(QFocusEvent *e);
 
 private slots:
     void insertCompletion(const QString &completion);
 
 private:
     QString textUnderCursor() const;
 
private:
    QAbstractItemModel *modelFromFile(const QString& fileName);
 
    TreeModelCompleter *completer;
};
 
#endif // MAINWINDOW_H

mainwindow.cpp
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
129
130
131
132
133
134
135
136
137
138
139
 
#include <QtGui>
#include <QModelIndex>
 
#include "treemodelcompleter.h"
#include "mainwindow.h"
 
MainWindow::MainWindow(QWidget *parent) :
    QTextEdit(parent) {
 
    completer = new TreeModelCompleter(this);
    completer->setWidget(this);
    completer->setModel(modelFromFile(":/resources/treemodel.txt"));
    completer->setSeparator(QLatin1String("."));
    completer->setCaseSensitivity(Qt::CaseInsensitive);
    completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
    completer->setCompletionMode(QCompleter::PopupCompletion);
    completer->setWrapAround(true);
 
    QObject::connect(completer, SIGNAL(activated(QString)), this, SLOT(insertCompletion(QString)));
 
    setWindowTitle(tr("Tree Model Completer"));
}
 
void MainWindow::insertCompletion(const QString& completion) {
    if (completer->widget() != this)
        return;
    QTextCursor tc = textCursor();
    int extra = completion.length() - completer->completionPrefix().length();
    tc.movePosition(QTextCursor::Left);
    tc.movePosition(QTextCursor::EndOfWord);
    tc.insertText(completion.right(extra));
    setTextCursor(tc);
}
 
QString MainWindow::textUnderCursor() const {
    QTextCursor tc = textCursor();
    tc.select(QTextCursor::WordUnderCursor);
    QString t = tc.selectedText();
    return tc.selectedText();
}
 
void MainWindow::focusInEvent(QFocusEvent *e) {
    if (completer)
        completer->setWidget(this);
    QTextEdit::focusInEvent(e);
}
 
void MainWindow::keyPressEvent(QKeyEvent *e) {
    if (completer && completer->popup()->isVisible()) {
        // The following keys are forwarded by the completer to the widget
        switch (e->key()) {
        case Qt::Key_Enter:
        case Qt::Key_Return:
        case Qt::Key_Escape:
        case Qt::Key_Tab:
        case Qt::Key_Backtab:
            e->ignore();
            return; // let the completer do default behavior
        default:
            break;
        }
    }
 
    bool isShortcut = ((e->modifiers() & Qt::ControlModifier) && e->key() == Qt::Key_E); // CTRL+E
    if (!completer || !isShortcut) // do not process the shortcut when we have a completer
        QTextEdit::keyPressEvent(e);
 
    const bool ctrlOrShift = e->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier);
    if (!completer || (ctrlOrShift && e->text().isEmpty()))
        return;
 
    static QString eow("~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-="); // end of word
    bool hasModifier = (e->modifiers() != Qt::NoModifier) && !ctrlOrShift;
    QString completionPrefix = textUnderCursor();
 
    if (!isShortcut && (hasModifier || e->text().isEmpty() || eow.contains(e->text().right(1)))) {
        completer->popup()->hide();
        return;
    }
 
    if (completionPrefix != completer->completionPrefix()) {
        completer->setCompletionPrefix(completionPrefix);
        completer->popup()->setCurrentIndex(completer->completionModel()->index(0, 0));
    }
 
    QRect cr = cursorRect();
    cr.setWidth(completer->popup()->sizeHintForColumn(0) + completer->popup()->verticalScrollBar()->sizeHint().width());
    completer->complete(cr); // popup it up!
}
 
QAbstractItemModel *MainWindow::modelFromFile(const QString& fileName) {
    QFile file(fileName);
    if (!file.open(QFile::ReadOnly))
        return new QStringListModel(completer);
 
#ifndef QT_NO_CURSOR
    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
#endif
    QStringList words;
 
    QStandardItemModel *model = new QStandardItemModel(completer);
    QVector<QStandardItem *> parents(10);
    parents[0] = model->invisibleRootItem();
 
    while (!file.atEnd()) {
        QString line = file.readLine();
        QString trimmedLine = line.trimmed();
        if (line.isEmpty() || trimmedLine.isEmpty())
            continue;
 
        QRegExp re("^\\s+");
        int nonws = re.indexIn(line);
        int level = 0;
        if (nonws == -1) {
            level = 0;
        } else {
            if (line.startsWith("\t")) {
                level = re.cap(0).length();
            } else {
                level = re.cap(0).length()/4;
            }
        }
 
        if (level+1 >= parents.size())
            parents.resize(parents.size()*2);
 
        QStandardItem *item = new QStandardItem;
        item->setText(trimmedLine);
        parents[level]->appendRow(item);
        parents[level+1] = item;
    }
 
#ifndef QT_NO_CURSOR
    QApplication::restoreOverrideCursor();
#endif
 
    return model;
}

treemodel.txt
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 
Parent1
    Child1
        GrandChild1
        GrandChild2
        GrandChild3
            GrandGrandChild1
    Child2
        GrandChild1
            GrandGrandChild1
        GrandChild2
    Child3
 
Parent2
    Child1
        GrandChild1
    Child2
    Child3
        GrandChild1
        GrandChild2
Si vous trouvez comment je doit faire, je serais très heureux de mettre une note sur l'auteur dans mon éditeur...