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

QCompleter for QLineEdit documentation and behaviour question



  • I have two questions about attaching a QCompleter to a QLineEdit.

    Documentation

    I have read documentation at http://doc.qt.io/qt-5/qcompleter.html and http://doc.qt.io/qt-5/qlineedit.html#setCompleter carefully. Taking an absolute default code:

    self.le = QtWidgets.QLineEdit()
    self.completer = QtWidgets.QCompleter(["111", "112", "121", "2222", "333"])
    self.le.setCompleter(self.completer)
    

    When the user clicks (or presses Enter) on an item in the popup, the text of the item is copied into the QLineEdit.

    Can anyone point me to anywhere in the documentation where this is actually stated??

    The only mention I can find of anything related is in http://doc.qt.io/qt-5/qcompleter.html#activated :

    This signal is sent when an item in the popup() is activated by the user (by clicking or pressing return).

    Well, I'm not connecting the activated signal. Is this what it does for a QLineEdit by default or something?

    Behaviour

    My actual objective is: after the selected item has been copied, I want the QLineEdit to treat it as the use has finished editing the text, so that it gets acted on immediately. (I would have thought this is a not-uncommon requirement. It's the kind of behaviour you'd expect if you were using an (editable) combobox.)

    I have come up with the following addition to the above code, which seems to work:

    self.le.completer().activated.connect(self.le.editingFinished.emit)
    

    Is this right/best? My connecting the activated signal does not seem to have stopped selecting an item from copying it to the QLineEdit, so maybe it never used the activated signal itself to do that in the first place? What is doing the text copy when? Am I supposed to call the base QCompleter::activated slot before/after my handler too to do anything more?


  • Lifetime Qt Champion

    Hi,

    You don't connect that signal yourself, it's handled internally.

    setText is used when you select an entry.



  • Hi ,
    @JonB said in QCompleter for QLineEdit documentation and behaviour question:

    When the user clicks (or presses Enter) on an item in the popup, the text of the item is copied into the QLineEdit.
    Can anyone point me to anywhere in the documentation where this is actually stated??

    I don't think you will find this in the documentation. This is implicit as this is the goal of the completer. QLineEdit is already designed to handle actived and highlighted signals and to set the text accordingly.
    Here is the source code of QLineEdit:setCompleter():

    void QLineEdit::setCompleter(QCompleter *c)
    {
        Q_D(QLineEdit);
        if (c == d->control->completer())
            return;
        if (d->control->completer()) {
            disconnect(d->control->completer(), 0, this, 0);
            d->control->completer()->setWidget(0);
            if (d->control->completer()->parent() == this)
                delete d->control->completer();
        }
        d->control->setCompleter(c);
        if (!c)
            return;
        if (c->widget() == 0)
            c->setWidget(this);
        if (hasFocus()) {
            QObject::connect(d->control->completer(), SIGNAL(activated(QString)),
                             this, SLOT(setText(QString)));
            QObject::connect(d->control->completer(), SIGNAL(highlighted(QString)),
                             this, SLOT(_q_completionHighlighted(QString)));
        }
    }
    

    There is two important things which are done here to make it working:

    • Calling QCompleter::setWidget() and pass pointer on the "edit" widget in argument (this).
    • Connecting to signal actived to handle insertion of completion item and signal highlighted, which may be used depending of the CompletionMode

    So except if you have some validator on your QLineEdit, I would suggest to use the signal activated directly without connecting it to QLineEdit::editFinished().
    I will try to make an example with my bad python level :)

    def handleNewText(text):
        print(text)
    self.le.completer().activated.connect(handleNewText)
    

    @JonB said in QCompleter for QLineEdit documentation and behaviour question:

    Is this right/best? My connecting the activated signal does not seem to have stopped selecting an item from copying it to the QLineEdit, so maybe it never used the activated signal itself to do that in the first place? What is doing the text copy when? Am I supposed to call the base QCompleter::activated slot before/after my handler too to do anything more?

    Connecting to asignal will not disconnect it from the QLineEdit, so it will not stop completion in your QLineEdit.



  • @SGaist , @Gojir4
    Thank you both.

    @SGaist

    You don't connect that signal yourself, it's handled internally.
    setText is used when you select an entry.

    Fair enough. I don't know if you are the person to mention it to, but that could do with being documented.

    @Gojir4
    Don't worry about the Python! C++ is fine.
    The bit I don't get is

    So except if you have some validator on your QLineEdit, I would suggest to use the signal activated directly without connecting it to QLineEdit::editFinished().

    Why wouldn't you connect to editFinished? Maybe there will indeed be a validator. All I know is I want selection to be treated as whatever editing finished would do. I don't know what that might be, so I emit the signal. What possible disadvantage are you suggesting there might be?


  • Lifetime Qt Champion

    You can request an improvement to the documentation on the bug report system or even better, you can submit an improvement to the documentation :)



  • @JonB said in QCompleter for QLineEdit documentation and behaviour question:

    Why wouldn't you connect to editFinished? Maybe there will indeed be a validator. All I know is I want selection to be treated as whatever editing finished would do. I don't know what that might be, so I emit the signal. What possible disadvantage are you suggesting there might be?

    You're right. What I meant is you don't need to connect activated to editFinished. I was assuming that editFinished will be called "automatically" by QLineEdit's slot connected to activated , with a "validated" string as argument, except if validation failed. But I was wrong as it only emits textChanged indirectly by calling QLineEdit::setText(). Also the doc says "The text is not validated when inserted with setText().". So it seems that using completer will bypass the validator anyway.

    So I think you can assume that the string argument from activated will be the same value than the one contained in the line edit.

    def onEditFinished(text): //text contains value selected from completer
        print(le.text()) //Get updated value from QLineEdit
    self.le.completer().activated.connect(onEditFinished)
    

    If the goal is to handle the new value, connecting to activated seems enough to me. If the goal is to explicitly emit editFinished, so ok you need to make the "extra" connection but I don't see the benefits.



  • @Gojir4
    I'll try one more time. I'm not sure whether you're trying to say something I don't understand or whether we are talking at cross-purposes :)

    • I wish to add a QCompleter to some QLineEdits I already have.

    • Those QLineEdits may already be set up so that when editing completed (e.g. press Enter or perhaps press Tab to move off) code wishes to act on that immediately. (In the current particular situation this is indeed the case: when the user has finished typing into the QLineEdit its content is a "filter" which immediately causes refresh of the whole page.)

    • The outside world will have hooked to a signal from the QLineEdit to accomplish this behaviour. The outside world will know nothing about whether the QLineEdit does or does not have a QCompleter attached.

    • When the user clicks to accept a suggestion, the QCompleter appears to first copy the text into the QLineEdit (that emits textChanged) and then explicitly emit the activated signal.

    • I can't use the textChanged signal as that is emitted as text is being typed in, that's too early to act on since we're waiting for the complete text before we can act on it.

    In your example, you have written your own onEditFinished() slot and connected QCompleter::activated signal to it. However, that is not the real world. The outside world will (or may) have connected a function to QLineEdit::editingFinished for whatever behaviour it wants on editing completed. In the QCompleter we know nothing about that, so we don't have an explicit function to call. All we know is we'd like the QLineEdit to behave however it would behave if the user had typed into it and finished typing, e.g. by pressing Enter or Tab or by clicking elsewhere. That's what my question stated:

    My actual objective is: after the selected item has been copied, I want the QLineEdit to treat it as [if] the use[r] has finished editing the text, so that it gets acted on immediately.

    So, I don't know about you but I cannot see how the QCompleter::activated would know what to call to achieve that, other than by causing the QLineEdit to emit its editingFinished signal?



  • @JonB said in QCompleter for QLineEdit documentation and behaviour question:

    I'll try one more time. I'm not sure whether you're trying to say something I don't understand or whether we are talking at cross-purposes :)

    hmmm... I'm not sure too :)

    What I'm trying to say is that connecting activated signal to the editFinished one or directly to your "outside world" slot (which refresh the page) will have the same result.

    But if you can't accessing the slot to make the connect , so in this case I agree that you need to connect to editFinished .



  • @Gojir4
    This is generic code for making the QCompleter work (i.e. accept picking a suggestion as meaning we have edited the line edit, finished editing it, and want it to be acted on immediately if appropriate) against any QLineEdit it's attached to. Imagine this was functionality that Qt had decided to provide in their base, generic QCompleter. How would they have coded it? They cannot possibly know what/whether the QLineEdit has a specific function attached to it, can they?

    The whole point of Qt's signal/slot mechanism is that objects/widgets emit signals and leave the outside world to connect those to slots as appropriate if desired, and that logic/behaviour (whether slots are attached and if so what they do), so that the signal emitter is isolated from what might be going on in the slot receiver(s).


Log in to reply