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

Potential Bug (Qt 5.15): QLineEdit emits "editingFinished()" signal twice when the text is changed and enter is pressed



  • I don't think this is related to: https://bugreports.qt.io/browse/QTBUG-40

    QLineEdit should emit "editingFinished()" when either it loses focus OR the enter key is pressed while it is in focus. In 5.15 each of these individual cases work as intended; however, given the description of this slot and the intuitive use cases for it, it is my understanding that should both of these triggers occur simultaneously, in which case still only one "edit" was actually made, the signal should still only fire once in order to communicate the singular edit. As far as I can tell though the signal is emitted twice due to a potential oversight.

    The QLineEdit implementation has a simple QoL feature that makes it so the "editingFinished()" signal is emitted in the first case (losing focus) only if its contents were actually modified, which allows for a simple test:

    1. Click into the QLineEdit and just press enter -> "editingFinished()" is emitted once as expected
    2. Click into the QLineEdit and change it's contents, then click on another focusable widget so that it loses focus -> "editingFinished()" is emitted once as expected
    3. Click into the QLineEdit and change it's contents, and then also press enter -> "editingFinished()" is emitted twice

    It seems to be there was some oversight made in that if the check for seeing if QLineEdit's contents were modified returns true after the enter key is pressed within it the "editingFinished()" signal is emitted once for the enter key press, and then a second time for the contents being different as they would need to be for the signal to fire when the widget loses focus, even though focus isn't actually lost here; even if pressing the enter key did cause the widget to briefly lose focus I'd still say this behavior is undesirable and most likely not intentional. Regardless of what happens while the text is being edited, pressing the enter key at the end signifies the completion of a single edit and therefore should result in just one emission of the above signal.

    If for some reason this is intentional behavior I'd love an explanation for it as to me this completely defeats the purpose of this signal (a catchall for "the user is for now finished touching this widget") and would instead require separate use of "textChanged" and "returnPressed".

    If anyone can't reproduce this I can create a generic/minimal example the next time I can use this computer.

    Otherwise, I just wanted to check in here before making a formal report.



  • My behavior correction patch for this one has also gone through to be available in 6.0/the current dev build

    https://codereview.qt-project.org/c/qt/qtbase/+/312083

    Cheers.


  • Lifetime Qt Champion

    Hi
    Qt 5.15.0, win 10. VS.
    I could not reproduce this.
    For case 3. it only emits one time for the enter.
    I tried 3 times to be sure to test like you described



  • @mrjj said in Potential Bug (Qt 5.15): QLineEdit emits "editingFinished()" signal twice when the text is changed and enter is pressed:

    Hi
    Qt 5.15.0, win 10. VS.
    I could not reproduce this.
    For case 3. it only emits one time for the enter.
    I tried 3 times to be sure to test like you described

    Ok I'll play with it some more and see if there's another part to the problem, and otherwise come up with a simple demonstration.

    This is a self compiled MSVC2019 Static package but I'd be surprised if such a specific issue was produced because of that.



  • Ok I made a new project with the minimum requirements to recreate the issue and tested it on the pre-compiled release of Qt 5.15.0 MSVC2019 64-bit that you can get through the Qt website/maintenance tool and unfortunately the issue does still occur. Really curious as to what's up with this one since you weren't able to recreate it.

    See the following quick example:
    https://www.youtube.com/watch?v=hRgSA_0lm9k&feature=youtu.be

    This happens regardless of the build configuration (i.e. same issue on Release config and using just "Run" instead of "Start debugging").

    Also, since I've seen some older mentions of this issue happening when a QMessageBox is used in the corresponding slot, I also tried just putting dummy code (creating an int and then incrementing it once) and using the debugger to break within the slot and it is still fired twice in the 3rd case when no message box is used.


  • Lifetime Qt Champion

    Hi
    Could you try my small test project
    https://www.dropbox.com/s/o9p7hbhb0nr3054/TestLineEdit.zip?dl=0

    Also if possible i want to try your small test project and see.



  • @mrjj

    Ok, I've figured out exactly what is happening due to your test project and should have thought to use qDebug earlier, as there happened to be a coincidence between my two testing methods that caused a false positive for "detecting" this would-be bug (this coincidence is why I thought the QMessageBox usage was not related when in fact it was).

    You are correct, the editingFinsihed() signal does work "correctly", though my realization has led me to discover another quirk of the signal that I feel is still an oversight, albeit a lesser one.

    Here is what was happening:

    editingFinsihed() is supposed to trigger when the Return key is pressed, or when the QLineEdit loses focus, with the exception that it will not trigger upon only (key for later) focus loss if no changes were actually made to the QLineEdit's contents as I mentioned previously (undocumented in the Qt docs). Note that the key detail here is that pressing the Return key does trigger the signal, but does not cause the QLineEdit to drop focus as well.

    With my example as shown in the video whenever I would press enter in the QLineEdit the editingFinsihed() signal would fire once, but then when the QMessageBox would pop and draw focus that would count as the QLineEdit losing focus and so editingFinsihed() would trigger a second time. The catch/coincidence is that when I then tested the project without the QMessageBox and simply had the slot do a dummy operation, I was testing for the number of times the signal was called by using a breakpoint on the dummy operation and checking how many times the breakpoint was hit. As in the first example editingFinsihed() would fire once when pressing enter; however, I was completely caught off guard by the fact that the debugger being brought into the foreground when the breakpoint is hit also counts as the QLineEdit losing focus and so in this case editingFinished() would also fire a second time (again, assuming changes were made to the contents).

    Because in both cases the signal fires twice for different reasons I incorrectly assumed that there was a bug and that QMessageBox was not to blame when in fact it and my usage of the debugger were both secondary causes of the issue for separate reasons.

    I say secondary because there is ultimately another quirk/oversight of this signal that if different would have prevented this entire series of events (and you may have been able to pickup on it even from just this explanation). Here is what I mean:

    Officially, editingFinsihed() triggers as described here, which if that is exactly how it worked would be fine and the end of this issue; however, by including the undocumented feature I mentioned above, the Qt developers clearly were aiming to enhance this signals functionality by preventing redundant/undesirable triggers. This makes sense. If the user simply clicks into the QLineEdit and then clicks off of it without a single content changing keystroke occurring, there is no reason to fire this signal as the QLineEdit hasn't truly been edited at all.

    This is where my argument for there being an oversight comes in. The above explanation makes the intentions of the Qt developers and this signal clear: Fire this signal when the QLineEdit has actually been edited and then loses focus, or the return key is pressed. There is no need to fire the signal when no state changes have occurred whatsoever. However, there are two sides to the coin of this ideology and while they covered one side with this undocumented QoL feature I've described, they missed the other one. If you click into the QLineEdit and actually edit it (i.e. add a character) and then press enter, editingFinsihed() triggers as expected, which means that it's current contents have now been handled by the programmer and this internal flag Qt uses to note that no changes to the widget have actually occurred should be reset to "true" until further changes are made, but it is not. If you then drop the QLineEdit's focus immediately after pressing the enter key the editingFinsihed() signal will fire again even though no edit's of any kind have occurred since the last time the signal was fired. To me it is clear that in this situation the signal should not fire, as otherwise there is a direct inconsistency with this undocumented feature.

    If the idea is that losing QLineEdit's focus after no editing actually occurs since doesn't fire the signal then this should also remain true even if the last thing to "finish the edits" was the return key. Or in other words, if clicking into the widget, making a change and then clicking out fires the signal, but then clicking back in and out while making no changes doesn't fire the signal, then the signal should also not fire a second time if the user click's in, makes a change and presses enter, and then clicks out.

    I could probably explain this better in a short video verbally and with an on-screen example, but I think it should be clear what I'm getting at. If not let me know. If so do you agree with my reasoning?

    Do you happen to know the preferred channel to make a request for this behavior to be changed? I know Qt is opensource but with how huge it is a pull request and change from some random person isn't likely to be accepted/merged I'd imagine.



  • If this step-by-step that covers all cases for your test program makes it more clear:

    1. Click into the line edit and type "a" into it, then click the "Take Focus" box -> editingFinished() fires as expected
    2. Click back into the line edit, then press enter -> editingFinished() fires as expected
    3. Click out of the line edit -> editingFinished() doesn't fire due to the undocumented QoL feature
    4. Click into the line edit, and then back into the "Take Focus" box -> editingFinished() doesn't fire due to the undocumented QoL feature
    5. Click into the line edit, type "b" into it and the press enter -> editingFinished() fires as expected
    6. Click out of the line edit -> based on the QoL feature paradigm clearly established at this point we would expect editingFinished() not to fire here since the last edits were already accounted for by the previous return key press, but it fires again anyway

  • Lifetime Qt Champion

    Hi
    Good, write up. It's 100% clear to me.
    I agree that it's not optimal handled as it would also happen in a very common use case where enter will move to the next input line and in that case also fire 2 editingFinished as
    far as i can see from your test case. User type text and press enter, then next edit is entered and old loose focus.

    • Do you happen to know the preferred channel to make a request for this behavior to be changed? I know Qt is opensource but with how huge it is a pull request and change from some random person isn't likely to be accepted/merged I'd imagine.

    They do accept incoming patches but they care a lot of breaking code/ABI so
    might not agree.

    However, I would ask on the mailing list where the devs hang out.
    https://lists.qt-project.org/


  • Lifetime Qt Champion

    Hi,

    To add to @mrjj the size of the patch does not matter. If really too big for some reason, you will be asked to split it.

    If breaking some ABI, now is the good time since you will have to first provide it for Qt 6 anyway.

    Since we are in a period of Holidays, you might have to wait a bit for the reviews but in any case, do not hesitate to provide a patch. It will be welcome.



  • @mrjj said in Potential Bug (Qt 5.15): QLineEdit emits "editingFinished()" signal twice when the text is changed and enter is pressed:

    Hi
    Good, write up. It's 100% clear to me.
    I agree that it's not optimal handled as it would also happen in a very common use case where enter will move to the next input line and in that case also fire 2 editingFinished as
    far as i can see from your test case. User type text and press enter, then next edit is entered and old loose focus.

    • Do you happen to know the preferred channel to make a request for this behavior to be changed? I know Qt is opensource but with how huge it is a pull request and change from some random person isn't likely to be accepted/merged I'd imagine.

    They do accept incoming patches but they care a lot of breaking code/ABI so
    might not agree.

    However, I would ask on the mailing list where the devs hang out.
    https://lists.qt-project.org/

    @SGaist said in Potential Bug (Qt 5.15): QLineEdit emits "editingFinished()" signal twice when the text is changed and enter is pressed:

    Hi,

    To add to @mrjj the size of the patch does not matter. If really too big for some reason, you will be asked to split it.

    If breaking some ABI, now is the good time since you will have to first provide it for Qt 6 anyway.

    Since we are in a period of Holidays, you might have to wait a bit for the reviews but in any case, do not hesitate to provide a patch. It will be welcome.

    Thanks for the information.

    I looked into it a bit and did see there was a wiki page describing the official procedure for contributing for the project and while I've never used Gerrit before or staged a commit for something other than much smaller projects, there seeems to be enough guidelines that it makes the process somewhat clear.

    The changes required should be quite minimal, so I'll re-download the sources and look at qlinewidget.cpp to see where the signal is emitted and what would need to be done. If I get stuck trying to submit a patch I'm sure someone could give me a nudge through the IRC or email mentioned on the page that @mrjj mentioned.


  • Lifetime Qt Champion

    While the documentation might look a bit daunting, it's just pretty thorough so you know what you are doing. The procedure is not as hard as it looks like.

    You'll also find people here :-)



  • @SGaist

    Sorry got busy for a while (mainly working on the project I'm making use of QLineEdit in, lol).

    Really appreciate the support as it ensures I'll be able to get this implemented one way or another without having to be too anxious over the process; though, its initial intimidation is certainly just a side effect of its reasonable formality given the size of Qt and how many people can be impacted by changes to it.

    I will start looking this over in the next few days.



  • My behavior correction patch for this one has also gone through to be available in 6.0/the current dev build

    https://codereview.qt-project.org/c/qt/qtbase/+/312083

    Cheers.