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 .js

    The 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

    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
    <?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
     <widget class="QWidget" name="TameDial">
      <property name="geometry">
      <property name="minimumSize">
      <property name="maximumSize">
      <property name="windowTitle">
      <property name="sizeGripEnabled" stdset="0">
      <layout class="QVBoxLayout" name="verticalLayout">
       <property name="spacing">
       <property name="leftMargin">
       <property name="topMargin">
       <property name="rightMargin">
       <property name="bottomMargin">
        <widget class="QDial" name="dial">
         <property name="maximum">
         <property name="singleStep">

  • Qt Champions 2016

    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 !

Log in to reply

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.