QCompleter for QLineEdit documentation and behaviour question
-
I have two questions about attaching a
QCompleter
to aQLineEdit
.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 aQLineEdit
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 theQLineEdit
, so maybe it never used theactivated
signal itself to do that in the first place? What is doing the text copy when? Am I supposed to call the baseQCompleter::activated
slot before/after my handler too to do anything more? -
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
andhighlighted
signals and to set the text accordingly.
Here is the source code ofQLineEdit: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 signalhighlighted
, 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 toQLineEdit::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.
- Calling QCompleter::setWidget() and pass pointer on the "edit" widget in argument (
-
@SGaist , @Gojir4
Thank you both.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 isSo 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? -
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
toeditFinished
. I was assuming thateditFinished
will be called "automatically" by QLineEdit's slot connected toactivated
, with a "validated" string as argument, except if validation failed. But I was wrong as it only emitstextChanged
indirectly by callingQLineEdit::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 emiteditFinished
, 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 someQLineEdit
s I already have. -
Those
QLineEdit
s 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 theQLineEdit
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 theQLineEdit
does or does not have aQCompleter
attached. -
When the user clicks to accept a suggestion, the
QCompleter
appears to first copy the text into theQLineEdit
(that emitstextChanged
) and then explicitly emit theactivated
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 connectedQCompleter::activated
signal to it. However, that is not the real world. The outside world will (or may) have connected a function toQLineEdit::editingFinished
for whatever behaviour it wants on editing completed. In theQCompleter
we know nothing about that, so we don't have an explicit function to call. All we know is we'd like theQLineEdit
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 theQLineEdit
to emit itseditingFinished
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 theeditFinished
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 theQCompleter
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 anyQLineEdit
it's attached to. Imagine this was functionality that Qt had decided to provide in their base, genericQCompleter
. How would they have coded it? They cannot possibly know what/whether theQLineEdit
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).