[implemented] Gui::QuantitySpinBox ignores keyboardTracking property

Here's the place for discussion related to coding in FreeCAD, C++ or Python. Design, interfaces and structures.
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
User avatar
uwestoehr
Veteran
Posts: 4961
Joined: Sun Jan 27, 2019 3:21 am
Location: Germany
Contact:

[implemented] Gui::QuantitySpinBox ignores keyboardTracking property

Post by uwestoehr »

Qt has the cool and very valuable feature of "keyboardTracking":
https://doc.qt.io/archives/qt-4.8/qabst ... cking-prop

This is what we would need e.g. in the TD workbench.

I tested it and it works fine with a QDoubleSpinBox, but when using a Gui::QuantitySpinBox, the keyboardTracking setting is simply ignored.

I tried to find out what is causing this, since most other QAbstractSpinBox properties are correctly respected but failed. Could anybody with deeper Gui:: UI element knowledge hive me a hint please?

(While I am at it: the readOnly property of QAbstractSpinBox is also not respected by Gui::QuantitySpinBox)
wandererfan wrote: .
Last edited by uwestoehr on Sun Jun 07, 2020 11:07 pm, edited 1 time in total.
openBrain
Veteran
Posts: 9041
Joined: Fri Nov 09, 2018 5:38 pm
Contact:

Re: Gui::QuantitySpinBox ignores keyboardTracking property

Post by openBrain »

Will have a look. Could you give some details about how you tested to determine whether tracking is active or not depending on the widget type ?
openBrain
Veteran
Posts: 9041
Joined: Fri Nov 09, 2018 5:38 pm
Contact:

Re: Gui::QuantitySpinBox ignores keyboardTracking property

Post by openBrain »

Here are the results of analysis. :)
First, as it may be confusing from QAbstractSpinBox documentation, this class implements the meta 'keyboardTracking' flag, but neither its logic nor the mentioned 'textChanged' and 'valueChanged' signals. It's up to subclasses to implement it.

Remark : AFAIK TechDraw is a C++ WB, following statements focus on C++. Typically QuantitySpinBox specific API isn't available in Python.

Regarding QuantitySpinBox :

'textChanged' isn't implemented, nothing more about it.

'valueChanged' is implemented. Notice 'keyboardTracking' behavior isn't implemented so setting/clearing it won't change anything.
'valueChanged' signal is emitted as soon as the value is changed to a correct value.
It means that is you're writing "2 kg", it will be emitted after '2', after space, not after the 'k', and finally after the 'g'. Of course if you enter "2 mm", it will be emitted for all characters as the first 'm' will be valid as 'meter'.
As soon as the entered text can't be determined as being a correct quantity, signal is no more emitted.
I think it's quite close from what you want and should be acceptable. Notice 'valueChanged' exists in 2 flavors : 'valueChanged(double)' emits raw value (unitless) and 'valueChanged(Base::Quantity') emits the complete quantity. Both are always emitted at the same time.

If you want to really catch all changes, you can connect to the inner QLineEdit of the spinbox by connecting to 'spinbox_pointer->lineEdit()->textChanged()'. This will give you access to lower level entered text. You may then have to call QuantitySpinBox methods to check/clear the text, such as 'validate()' or 'valueFromText()'.
Notice 'lineEdit()' is a QAbstractSpinBox method, so this would work on any spinbox type inherited from it.

HTH
User avatar
wandererfan
Veteran
Posts: 6321
Joined: Tue Nov 06, 2012 5:42 pm
Contact:

Re: Gui::QuantitySpinBox ignores keyboardTracking property

Post by wandererfan »

uwestoehr wrote:
openBrain wrote: Sun May 31, 2020 9:54 am 'valueChanged' is implemented. Notice 'keyboardTracking' behavior isn't implemented so setting/clearing it won't change anything.
'valueChanged' signal is emitted as soon as the value is changed to a correct value.
It means that is you're writing "2 kg", it will be emitted after '2', after space, not after the 'k', and finally after the 'g'. Of course if you enter "2 mm", it will be emitted for all characters as the first 'm' will be valid as 'meter'.
Thanks for looking into this. It confirms my investigation.
As soon as the entered text can't be determined as being a correct quantity, signal is no more emitted.
I think it's quite close from what you want and should be acceptable.
The problem with using valueChanged in QuantitySpinBox is that in entering "1234.56 kg", the signal is emitted 9 times and there is nothing to distinguish #1 from #9. If we update a property every time the signal is emitted, onChanged(myProperty) gets called 9 times. So unless onChanged(myProperty) is super quick, keyboard input slows down.

In QDoubleSpinBox for example, with KeyboardTracking = false, the value changed signal is only emitted after all the numbers have been typed (enter or focus lost), or if the increment arrows are clicked, and onChanged only gets executed once.

To support KeyboardTracking in QuantitySpinBox would need changes to:
void QuantitySpinBox::userInput(const QString & text)
void QuantitySpinBox::focusOutEvent(QFocusEvent * event)
void Gui::QuantitySpinBox::keyPressEvent(QKeyEvent *event)


There is also the UI style question. Everybody's opinion will be different, but I prefer that when typing a value, nothing happens until I indicate that I'm finished typing.
openBrain
Veteran
Posts: 9041
Joined: Fri Nov 09, 2018 5:38 pm
Contact:

Re: Gui::QuantitySpinBox ignores keyboardTracking property

Post by openBrain »

OK, wasn't clear from @uwestoehr if you want only 1 signal at the end or signal for each character. ;)

If this is first case, as a variant to using keyboardTracking = false, you can connect to 'spinbox_pointer->lineEdit()->editingFinished()' signal.
If you want to make some tests, you can try the below snippet in the Python console. You need to open Part/Extrude dialog first, then it will react on 'Along:' field change :

Code: Select all

from PySide import QtGui
qsb = Gui.getMainWindow().findChild(QtGui.QDockWidget,'Combo View').findChild(QtGui.QAbstractSpinBox,'spinLenFwd')
qsb.lineEdit().editingFinished.connect(lambda :print(qsb.text()))
As a sidenote, it works the same for every class inherited from QAbstractSpinBox. ;)
wmayer
Founder
Posts: 20310
Joined: Thu Feb 19, 2009 10:32 am
Contact:

Re: Gui::QuantitySpinBox ignores keyboardTracking property

Post by wmayer »

Code: Select all

ui=Gui.UiLoader()
sp=ui.createWidget("Gui::QuantitySpinBox")
sp.setProperty("unit","mm")

sp.valueChanged.connect(lambda: print(sp.text()))
sp.show()

# set some text which is printed for each character you type => OK

sp.setKeyboardTracking(False)

# set some text which is printed for each character you type => not OK

sp.setReadOnly(True)

# it's not possible for the user to change the content => OK, so I can't confirm the second part of the bug description
NOTE: When a widget is set to read-only it only means that the user cannot change the value but it's still possible to do this programmatically.
User avatar
uwestoehr
Veteran
Posts: 4961
Joined: Sun Jan 27, 2019 3:21 am
Location: Germany
Contact:

Re: Gui::QuantitySpinBox ignores keyboardTracking property

Post by uwestoehr »

openBrain wrote: Sun May 31, 2020 2:25 pm OK, wasn't clear from @uwestoehr if you want only 1 signal at the end or signal for each character. ;)
You misunderstood me then. What I want is to have _exactly_ the behavior of Qt's keyboardTracking property. (When the user types in e.g. "600" a signal is only omitted on using the spin box buttons or the return key.)

So in my opinion Gui::QuantitySpinBox should just inherit the keyboardTracking from QAbstractSpinBox and we have the functionality we need.
User avatar
uwestoehr
Veteran
Posts: 4961
Joined: Sun Jan 27, 2019 3:21 am
Location: Germany
Contact:

Re: Gui::QuantitySpinBox ignores keyboardTracking property

Post by uwestoehr »

wmayer wrote: Sun May 31, 2020 5:33 pm sp.setKeyboardTracking(False)

# set some text which is printed for each character you type => not OK
Yes, but how can I fix this? At least a pointer would be helpful because by looking at the code I don't understand why keyboardTracking is not inherited.

sp.setReadOnly(True)

# it's not possible for the user to change the content => OK, so I can't confirm the second part of the bug description
[/code]
Hmm, I set the ReadOnly property via the .UI file and also in the code. E.g. I write

Code: Select all

ui->qsbY->setReadOnly(true);
in TaskDetail.cpp but as result, the "qsbY" QuantitySpinBox is still changeable by the user.
openBrain
Veteran
Posts: 9041
Joined: Fri Nov 09, 2018 5:38 pm
Contact:

Re: Gui::QuantitySpinBox ignores keyboardTracking property

Post by openBrain »

Both your sentences don't make much sense. ;)
uwestoehr wrote: Mon Jun 01, 2020 11:52 am You misunderstood me then. What I want is to have _exactly_ the behavior of Qt's keyboardTracking property. (When the user types in e.g. "600" a signal is only omitted on using the spin box buttons or the return key.)
'keyboardTracking' has no behavior by itself. 'keyboardTracking' changes the behavior of the spinbox (more precisely of when the textChanged/valueChanged is emitted) depending on its value. What you mention is the behavior when keyboardTracking=false. The default value is keyboardTracking=true, and in this case the signal is emitted at each keyboard entry.
So in my opinion Gui::QuantitySpinBox should just inherit the keyboardTracking from QAbstractSpinBox and we have the functionality we need.
It's not really about inheritance. keyboardTracking behavior change has to be implemented in QuantitySpinBox, which isn't the case currently.

Hope this help to make things clear.

This said, if you're only interested in the behavior you mentioned, I suggested a solution using editingFinished of the lineEdit() above, but I didn't tested if it is sent when changing the value with arrows.
User avatar
uwestoehr
Veteran
Posts: 4961
Joined: Sun Jan 27, 2019 3:21 am
Location: Germany
Contact:

Re: Gui::QuantitySpinBox ignores keyboardTracking property

Post by uwestoehr »

openBrain wrote: Mon Jun 01, 2020 12:10 pm It's not really about inheritance. keyboardTracking behavior change has to be implemented in QuantitySpinBox, which isn't the case currently.
I must admit, I am confused now. As it is, Gui::QuantitySpinBox behaves in any case as if keyboardTracking=TRUE. To do so, it must have inherited that there is such a property. Thus I thought, inheritance means also the methods to change the inherited properties are inherited too.
As this is not the case, so I will have to implement this to Gui::QuantitySpinBox manually. I'll have a look at the QAbstractButton sources hoping I'll understand what I have to do. I thought that a Qt expert here could give me pointer or already knows what to do.

This said, if you're only interested in the behavior you mentioned, I suggested a solution using editingFinished of the lineEdit() above, but I didn't tested if it is sent when changing the value with arrows.
That is in my opinion a work around the "clean" solution to use Qt's documented features. I mean I want a solution that also new programmers of FC can use Qt's documentation to implement features. For example I found keyboardTracking property by googling in developer forums.
I had a discussion with WandererFan and it crystallized out that what we would need is what keyboardTracking is already offering.
Post Reply