Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QCompleter popup does not immediately reflect model changes



  • In Qt 5.12 on Windows, making changes to the model of a QCompleter isn't immediately reflected in the model used by the QCompleter's popup. Here's a minimal reproduction:

    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        QWidget window;
        window.show();
    
        QVBoxLayout layout;
        window.setLayout(&layout);
    
        QLineEdit lineEdit(&window);
        layout.addWidget(&lineEdit);
    
        QCompleter completer(&lineEdit);
        lineEdit.setCompleter(&completer);
    
        QStringList firstStringList = { "red", "yellow" };
        QStringList secondStringList = { "green", "blue" };
    
        QStringListModel completerModel(firstStringList, &completer);
        completer.setModel(&completerModel);
        completer.popup()->setFixedWidth(completer.popup()->sizeHintForColumn(0));
    
        QPushButton button("Swap Completer String List", &window);
        QObject::connect(&button, &QPushButton::clicked, [&completerModel, secondStringList, &completer]() {
            completerModel.setStringList(secondStringList);
            completer.popup()->setFixedWidth(completer.popup()->sizeHintForColumn(0));
        });
        layout.addWidget(&button);
    
        return a.exec();
    }
    

    Steps to reproduce:

    • Begin typing "yellow" in the text entry field. Notice that the completer popup appears and is set to be just wide enough to accommodate the text.
    • Click the button to modify the string list in the completer's model and update the popup width accordingly.
    • Re-focus the text entry field and begin typing "green". Notice that the completer popup does not appear.
    • Click the button again.
    • Re-focus the text entry field and begin typing "green" again. Notice how the completer popup has returned.

    The first time the button is clicked, the size hint from the popup returns 0, apparently due to the model containing zero rows. When the button is clicked a second time, the popup's model appears to have caught up and returns the correct size hint.

    Is this a bug or expected behaviour? And is possible to manually force the popup's model to re-sync with the completer's model and return the correct size hint?



  • For anyone also having this problem, I've discovered the cause of the issue I observed, as well as a workaround. The completion prefix can have a stale value even if the text entry field is cleared, and this prefix can prevent any completion matches from being found, causing the size hint to return 0.

    To get around this, manually clear the completion prefix before querying for the size hint. If the text entry field isn't being cleared as well at the same time, the prefix can be stored before it is cleared and restored after the size hint is retrieved, keeping the prefix and entered text synchonised.

    QObject::connect(&button, &QPushButton::clicked, [&completerModel, secondStringList, &completer]() {
        QString cachedPrefix = completer.completionPrefix();
        completer.setCompletionPrefix("");
        completerModel.setStringList(secondStringList);
        completer.popup()->setFixedWidth(completer.popup()->sizeHintForColumn(0));
        completer.setCompletionPrefix(cachedPrefix);
    });
    

Log in to reply