Taming QDial
-
Hi,
Do you have the following requirements ?
1 Preventing QDial jump-to-position on click ?
2 Preventing QDial jump-to-maximum on End key, and jump-to-minimum on Home key ?
3 Smooth control of an on-screen visual, or off-screen motor ?Then read on :-)
I've seen each of the above requested on the forum. Example code provided below.
The basic idea, is to constrain the size of user-requested position change.
Specifically, to constrain the change to an accelerating limit, up to a coast maximum.
As such, the constaint acts to prevent 1 and 2, and provide for 3:The effect of this relatively simple mod, is that now if you drag, starting
from a position away from the nub, it smoothly accelerates to meet you; whether
moving away from or toward the nub. Keys likewise smoothly accelerate up to the
configured singleStep rate for arrow keys, pageStep rate for Page Up/Down,
and coast maximum for Home/End, in place of the former behaviour.The accelerating limit is reset at mouse/touch move end. QDial or its inheritee
QAbstractSlider, omit a signal for key-initiated move end. So end is the simple expedient
of a timeout, period 0.5s to accommodate the default key repeat threshold.If you want to see a working demo, proceed as follows. Should take 10 mins tops,
to get up and running:As mentioned in other posts, we're using Qt Script only, not fullblown Qt. This due to
restriction placed by our vendor tool, that launches our .js. Which then in turn,
via vendor-specific command, launches our .ui.Qt Script, or the vendor environment at least, limits code access to properties, signals,
public slots, and the vendor-specific commands. Public functions are inaccessible.I would attach my example code, TameDial.js/us. But the forum errors, saying I lack
the privileges as yet. Instead, I have copy-pasted the .js/ui file content below.
They are not too long. Just copy-paste back into an empty TameDial.js/ui file.
Now with better wrapping support :-)You will need our vendor tool, to open the .js, which launches the .ui. The demo version of the
tool can be freely downloaded from https://www.emtas.de/en/download/canopen-deviceexplorer-demo/.
It times out and exits after 1 hour of use, although can be restarted. Within the tool, to
launch the .js, select PlugIns > CAN/CANopen Scripting, then Load, and nav to the .jsThe QDial has default properties, except maximum increased from 99 to 999, for resolution
and smoothness. And singleStep increased from 1 to 5, to expose arrow key acceleration.Naturally the same approach and code could be used for the other QAbstractSliders,
namely QScrollBar and QSlider. Feel free to tame those :-)Best regards,
David King
TameDial.js ----------- util.loadUIFile( "TameDial.ui", "TameDial" ); // Vendor-specific UI file load command var Dial = TameDial.findChild( "dial" ); // Dial handle Dial.valueChanged.connect( Change ); // Value change Dial.sliderReleased.connect( End ); // Move end var Wrap = Dial.wrapping; // Wrapping if ( Wrap ) // Wrapping enabled { var Min = Dial.minimum; // Dial minimum var Max = Dial.maximum; // Dial maximum var Range = Max - Min; // Dial range var Half = Range / 2; // Half range }; var User = true; // User-requested change var Control = 0; // Controlled value var Limit = 0; // Speed limit var Coast = 20; // Speed coast (tune if desired) var Time = 0; // End timeout util.every( 0, "Cyclic()" ); // Cyclic task function Change( ) // Value change { if ( User ) // Prevent reentrancy { Time = Date.now( ) + 500; // End timeout (500ms after last movement) var Value = Dial.value; // User-requested value if ( Limit > 1 ) // Ignore first two requests, including mouse press, // and mouse release within timeout, so no click move { var Delta = Value - Control; // Value delta if ( Wrap ) // Wrapping enabled { if ( Delta > Half && Value != Max ) Delta -= Range; else if ( Delta < -Half && Value != Min ) Delta += Range; // Delta wrap } if ( Delta > Limit ) Delta = Limit; else if ( Delta < -Limit ) Delta = -Limit; // If delta exceeds limit, constrain Control += Delta; // Controlled value change if ( Wrap ) // Wrapping enabled { if ( Control > Max ) Control -= Range; else if ( Control < Min ) Control += Range; // Controlled value wrap } } if ( Control != Value ) User = false, Dial.value = Control, User = true; // If difference, update dial if ( Limit != Coast ) Limit++; // If not coast speed, increment limit TameDial.windowTitle = "TameDial Value " + Value + " Control " + Control + " Limit " + Limit // Metrics } } function End( ) // Move end { Limit = 0; // Speed limit reset TameDial.windowTitle = "TameDial" // Indicate end } function Cyclic( ) // Cyclic task { if ( Time && Date.now( ) > Time ) Time = 0, End( ); // If end timeout, remove, end move // Short-circuit evaluate efficiently bails expression if no timeout } TameDial.ui ----------- <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>TameDial</class> <widget class="QWidget" name="TameDial"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>400</width> <height>200</height> </rect> </property> <property name="minimumSize"> <size> <width>400</width> <height>200</height> </size> </property> <property name="maximumSize"> <size> <width>400</width> <height>200</height> </size> </property> <property name="windowTitle"> <string>TameDial</string> </property> <property name="sizeGripEnabled" stdset="0"> <bool>false</bool> </property> <layout class="QVBoxLayout" name="verticalLayout"> <property name="spacing"> <number>16</number> </property> <property name="leftMargin"> <number>16</number> </property> <property name="topMargin"> <number>16</number> </property> <property name="rightMargin"> <number>16</number> </property> <property name="bottomMargin"> <number>16</number> </property> <item> <widget class="QDial" name="dial"> <property name="maximum"> <number>999</number> </property> <property name="singleStep"> <number>5</number> </property> </widget> </item> </layout> </widget> <resources/> <connections/> </ui>
-
Hi
Cool.
I think you are the first i have seen here using Qt via QtScript + js :)
I didn't know you much you can actually do !