[implemented] Gui::QuantitySpinBox ignores keyboardTracking property

Here's the place for discussion related to coding in FreeCAD, C++ or Python. Design, interfaces and structures.
User avatar
wandererfan
Posts: 4078
Joined: Tue Nov 06, 2012 5:42 pm

Re: Gui::QuantitySpinBox ignores keyboardTracking property

Postby wandererfan » Mon Jun 01, 2020 12:24 pm

uwestoehr wrote:
Mon Jun 01, 2020 12:05 pm
I don't understand why keyboardTracking is not inherited.

Look at the slots which handle the TextChanged signal.

Code: Select all

void QAbstractSpinBoxPrivate::_q_editorTextChanged(const QString &t)
void QuantitySpinBox::userInput(const QString & text)
QSB::userInput does not look at the keyboardTracking setting.
openBrain
Posts: 4613
Joined: Fri Nov 09, 2018 5:38 pm

Re: Gui::QuantitySpinBox ignores keyboardTracking property

Postby openBrain » Mon Jun 01, 2020 1:04 pm

uwestoehr wrote:
Mon Jun 01, 2020 12:24 pm
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.
keyboardTracking variable is inherited along with the get 'keyboardTracking()' and the set 'setKeyboardTracking()' methods. This is how C++ (and globally OOP) works. This means that you can change the value of any instance of QuantitySpinBox. But it appears that QuantitySpinBox makes absolutely no usage of this variable, i.e. its behavior is always the same whatever is the value.
The signals are emitted here in the userInput() function.
If you want to implement keyboardTracking, you have to set a check here, but also to hack the keyPressEvent() function, and implement the focusOutEvent() function.
Another solution would be to rely on QAbstractSpinBox methods, but I think some are already overwritten in QuantitySpinBox. You can have a look at the Qt code (search 'keyboardTracking'). ;)

Notice that problem is exactly the same for UIntSpinBox, IntSpinBox & DoubleSpinBox classes defined in this file. So probably if you want a consistent behavior, changes shall also be ported there.
wmayer
Site Admin
Posts: 16452
Joined: Thu Feb 19, 2009 10:32 am

Re: Gui::QuantitySpinBox ignores keyboardTracking property

Postby wmayer » Mon Jun 01, 2020 4:48 pm

uwestoehr wrote:
Mon Jun 01, 2020 12:05 pm
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.
Try: git commit 15c964400
wmayer
Site Admin
Posts: 16452
Joined: Thu Feb 19, 2009 10:32 am

Re: Gui::QuantitySpinBox ignores keyboardTracking property

Postby wmayer » Mon Jun 01, 2020 5:09 pm

openBrain wrote:
Mon Jun 01, 2020 1:04 pm
Notice that problem is exactly the same for UIntSpinBox, IntSpinBox & DoubleSpinBox classes defined in this file. So probably if you want a consistent behavior, changes shall also be ported there.
They shouldn't suffer from this problem because they inherit from QSpinBox and QDoubleSpinBox, respectively. These two Qt classes implement the needed functionality in their private classes.

With QuantitySpinBox the story is different because it inherits directly from QAbstractSpinBox and due to some design flaws sub-classes must duplicate a lot of functionality. The main issue is that the virtual methods:

Code: Select all

QString QAbstractSpinBoxPrivate::textFromValue(const QVariant &) const
QVariant QAbstractSpinBoxPrivate::valueFromText(const QString &) const
are part of QAbstractSpinBoxPrivate instead of QAbstractSpinBox.
A possibility would be to use some of Qt's private headers but this is considered bad practice because there is no guarantee that it still works with the next Qt version.
User avatar
uwestoehr
Posts: 1777
Joined: Sun Jan 27, 2019 3:21 am

Re: Gui::QuantitySpinBox ignores keyboardTracking property

Postby uwestoehr » Mon Jun 01, 2020 9:12 pm

wmayer wrote:
Mon Jun 01, 2020 4:48 pm
Try: git commit 15c964400
Many thanks!

However, It doesn't work. I tested by using in TaskDetail.cpp this:

Code: Select all

 ui->qsbX->setKeyboardTracking(false);
    connect(ui->qsbX, SIGNAL(valueChanged()),
            this, SLOT(onXEdit()));
But I don't get the expected result. Pressing the spin box buttons doesn't emit the signal. The signal is only emitted on leaving the box.

I see that you connected editingFinished() QuantitySpinBox.cpp and not valueChanged(), however using this signal doesn't work either.
wmayer
Site Admin
Posts: 16452
Joined: Thu Feb 19, 2009 10:32 am

Re: Gui::QuantitySpinBox ignores keyboardTracking property

Postby wmayer » Mon Jun 01, 2020 9:36 pm

Then use valueChanged() with the correct signature. Its argument can be a double or a Quantity.
User avatar
uwestoehr
Posts: 1777
Joined: Sun Jan 27, 2019 3:21 am

Re: Gui::QuantitySpinBox ignores keyboardTracking property

Postby uwestoehr » Mon Jun 01, 2020 10:56 pm

wmayer wrote:
Mon Jun 01, 2020 9:36 pm
Then use valueChanged() with the correct signature. Its argument can be a double or a Quantity.
I don't understand. Here is my patch I use to test:
KeyboardTracking.txt
diff file
(1.45 KiB) Downloaded 23 times
With this patch applied FC crashes when the TD detail dialog is opened.
wmayer
Site Admin
Posts: 16452
Joined: Thu Feb 19, 2009 10:32 am

Re: Gui::QuantitySpinBox ignores keyboardTracking property

Postby wmayer » Tue Jun 02, 2020 6:14 am

Why do you change QunatitySpinBox and connect valueChanged with handlePendingEmit? This makes no sense at all.

What happens is that if handlePendingEmit is directly called it invokes valueChanged. Now valueChanged triggers handlePendingEmit which calls valueChanged which calls handlePendingEmit which calls valueChanged ....

What you get is a stack overflow and with it a segmentation fault.
User avatar
uwestoehr
Posts: 1777
Joined: Sun Jan 27, 2019 3:21 am

Re: Gui::QuantitySpinBox ignores keyboardTracking property

Postby uwestoehr » Sun Jun 07, 2020 2:27 am

wmayer wrote:
Tue Jun 02, 2020 6:14 am
Why do you change QunatitySpinBox and connect valueChanged with handlePendingEmit? This makes no sense at all.
OK, my mistake.
But how do I get KeyBoardTracking to work?
Neither this:

Code: Select all

ui->qsbX->setKeyboardTracking(false);
connect(ui->qsbX, SIGNAL(editingFinished()),
        this, SLOT(onXEdit()));
nor this:

Code: Select all

ui->qsbX->setKeyboardTracking(false);
connect(ui->qsbX, SIGNAL(valueChanged(bool)),
        this, SLOT(onXEdit()));
works. But at least the latter should emit the signal when the user uses a spin button.
wmayer
Site Admin
Posts: 16452
Joined: Thu Feb 19, 2009 10:32 am

Re: Gui::QuantitySpinBox ignores keyboardTracking property

Postby wmayer » Sun Jun 07, 2020 9:16 am

Try this example:

Code: Select all

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

sp.valueChanged.connect(lambda: print(sp.text()))
sp.show()
Click inside the spin box and select the text. Type in some numbers and observe the output window. Nothing is printed. Now click into e.g. the Python console so that the spin box loses the focus. Now the content is written to the output window.

When testing things you should test correctly.
ui->qsbX->setKeyboardTracking(false);
connect(ui->qsbX, SIGNAL(editingFinished()),
this, SLOT(onXEdit()));
The editingFinished() signal is only emitted when Enter/Return is pressed. Look at the implementation and documentation of QAbstractSpinBox.
ui->qsbX->setKeyboardTracking(false);
connect(ui->qsbX, SIGNAL(valueChanged(bool)),
this, SLOT(onXEdit()));
A signal valueChanged(bool) doesn't even exist. Here you should see a warning in the output window that trying to connect this signal with the slot failed.
The class QuantitySpinBox offers two valueChanged signals: valueChanged(double) and valueChanged(Base::Quantity)