[Development] Qt Quick Controls Dialogs -- enabled state of the standard buttons (API choices)

Vladimir Moolle vmoolle at ics.com
Mon Aug 24 14:36:45 CEST 2015


Hi, and many thanks for a detailed response :)
I think with that, and the other ones, we road to a better StandardButtons
API is almost clear now (to be touched in a separate e-mail).

Let me address some of your points  / questions:

> Below are some approaches coming to mind (after a discussion we had with
colleagues):
>
> 1. A getter method on Dialog, more or less duplicating that of the
QDialog. Pros are the API (and the patch implementing it) being trivial.
Cons are necessity to call the getter only after the button is created (by
otherwise declarative code) and complexities of button lifetime tracking.

>>>
I strongly dislike this. I think imperative methods should be a last
resort in QML, instead of the first thing we turn to.

(Note also that QDialog has no getters/setters for button states)
<<<

What was meant is something like:

Component.onCompleted: {
    var okBtn = standardButton(StandardButton.Ok)
    <logic setting up a binding on the returned button instance's enabled
property>
}

i.e. a setter would return the button item itself, not a property of it
 (still, this does not look handy).
Sorry, about not providing a sketched usage example initially.

> Pros of this approach would be “proper” declarativity, and ability to
easily extend the exposed property set (adding possibility to override
other properties other than “enabled”), cons would be limiting further API
changes in this area to being based on this one-way “reflect my properties”
approach (and making some bindings track the state of the button by default
would complicate things beyond reasonable).

>>>
I don't quite understand the cons you've mentioned. Could you please
explain why would it be one-way? Couldn't we do something like this?:

Dialog {
    ButtonState {
        id: okButtonState
        standardTarget: StandardButton.Ok // I think "role" isn't the
best name, as we're not assigning a role to this object
    }
    onSomething: okButtonState.enabled = true;
}

Also, why would bindings be complicated?
<<<

Above would perfectly work, yes, what could be complicated though is making
some ButtonState object's properties have bindings (to something offered by
Dialog's internal machinery / models) by default (the "text" property, for
example), which would not be easy to get back (except via recreating the
ButtonState object) once the user sets some of his own -- which would not
be the case if only user-supplied bindings would be used, and the logic
inside Dialog would always bind to whatever the current state of the
properties is (hence, one-way -- in this sense).

Best regards, Vladimir


On Sat, Aug 22, 2015 at 5:43 AM, Sze Howe Koh <szehowe.koh at gmail.com> wrote:

> Hi,
>
> In general, I think we should give higher priority to API simplicity
> and flexibility, and lower priority to implementation simplicity.
>
> Note that the QML Dialog is different from the C++ QDialog. QDialog
> has no standard buttons of its own. Rather, it's up to the user to
> manually add buttons, or to add a QDialogButtonBox (which might be a
> better place to attach the "button proxy/delegate" described in
> several of the approaches below). I think the C++ way provides better
> separation of concerns, where QDialog manages the popup window itself
> and reports the user's choice(s), while QDialogButtonBox manages the
> buttons (something to consider for Qt Quick 3?)
>
>
> On 22 August 2015 at 07:22, Vladimir Moolle <vmoolle at ics.com> wrote:
> >
> > Hi, I’d like to discuss approaches to API design in the context of
> https://bugreports.qt.io/browse/QTBUG-47850 (making Quick Controls
> dialogs’ standard buttons’ enabled properly state accessible).
> >
> > It seems, that the desired properties of an API implementing the above
> would be:
> > possibility to declaratively manipulate enabled-ness of the buttons
> > lack of risks brought by “signal races” (usually happens when imperative
> and declarative code is mixed)
> > optionally, possibility to tweak more than just the “enabled” property
> of the buttons (at least the API could allow for such extension in the
> future).
>
> +1
>
>
> > Below are some approaches coming to mind (after a discussion we had with
> colleagues):
> >
> > 1. A getter method on Dialog, more or less duplicating that of the
> QDialog. Pros are the API (and the patch implementing it) being trivial.
> Cons are necessity to call the getter only after the button is created (by
> otherwise declarative code) and complexities of button lifetime tracking.
>
> I strongly dislike this. I think imperative methods should be a last
> resort in QML, instead of the first thing we turn to.
>
> (Note also that QDialog has no getters/setters for button states)
>
>
> > 2. A set of applyEnabled, helpEnabled, … properties on the Dialog. Pros
> is being declarative and API simplicity, cons is the obvious verbosity
> (especially, if more properties are exposed this way later).
>
> This seems a bit unsustainable.
>
>
> > 3. An enabledButtons (disabledButtons? disabledStandardButtons?
> enabledStandardButtons??) property containing an ORed set of button roles
> (just like the standardButtons property). Pros are things being
> declarative, and uniform, cons -- that crafting a binding expression for
> more than a couple buttons may get ugly (and listening  / responding to
> changes through the single QML signal handler may require having a signal
> parameter matching the old / previous state of the ORed enum combo -- which
> is strange; note: something close is discussed by
> https://bugreports.qt.io/browse/QTBUG-40868?focusedCommentId=253265)
>
> This could work. We have something similar in Window.flags
> (http://doc.qt.io/qt-5/qml-qtquick-window-window.html#flags-prop)
>
> Is it necessary to have a signal parameter that reports the old state?
> AFAIK, most stateChanged()/valueChanged() signals in Qt only report
> the new state/value.
>
>
> > 4. An auxiliary object can be used to make the buttons accessible
> declaratively:
> > Dialog {
> >     StandardButtonProxy {
> >         id: okProxy
> >         role: StandardButton.Ok
> >         Binding {
> >              target: okProxy.button // here it is
> >              property: “enabled”
> >              value: <some binding expression>
> >         }
> >     }
> > }
> > Pros of this approach would be its simplicity (on both API and
> implementation sides), and relative safety (the “button” property would be
> null when the button is not there, incl. temporarily -- i.e. during button
> model reorganizations, etc.), cons -- that it would be merely a means to
> expose standard buttons “the QML way”, not addressing the fact that
> exposing control instances from underneath may not be the best practice by
> itself (and especially in QML, where a smart user may try to save the
> reference, thus confusing the GC).
>
> This is the QML way of achieving how dialog buttons are currently
> managed in C++.
>
> I currently haven't worked out if I'm for or against this.
>
>
> > 5. A special ButtonState object type serving as “declarative proxy” for
> the button’s properties, i.e.:
> > Dialog {
> >     <...>
> >     ButtonState {
> >         role: StandardButton.Ok
> >         enabled: <some binding expression>
> >     }
> > }
> > Pros of this approach would be “proper” declarativity, and ability to
> easily extend the exposed property set (adding possibility to override
> other properties other than “enabled”), cons would be limiting further API
> changes in this area to being based on this one-way “reflect my properties”
> approach (and making some bindings track the state of the button by default
> would complicate things beyond reasonable).
>
> I don't quite understand the cons you've mentioned. Could you please
> explain why would it be one-way? Couldn't we do something like this?:
>
> Dialog {
>     ButtonState {
>         id: okButtonState
>         standardTarget: StandardButton.Ok // I think "role" isn't the
> best name, as we're not assigning a role to this object
>     }
>     onSomething: okButtonState.enabled = true;
> }
>
> Also, why would bindings be complicated?
>
>
> > 6. Finally, Dialog could accept (optional) delegates for the buttons
> created, allowing for arbitrary customizations, i.e.:
> > Dialog {
> >     <...>
> >     StandardButtonDelegate {       //name arguably could be better
> >         role: StandardButton.Apply // could be “roles” here even
> >         StandardButton {           // a Button, but with default
> bindings for “text”, etc.
> >             enabled: <some binding expression>
> >         }
> >     }
> >     StandardButtonDelegate {       //name arguably could be better
> >         role: StandardButton.Apply // could be “roles” here even
> >         Rectangle {                // a very custom “button”
> >        <...>
> >             signal clicked         // or a warning emitted by Dialog if
> absent
> >             enabled: <some binding expression>
> >         }
> >     }
> > }
> > The pros of this approach would be the possibility to customize the
> buttons (standard or not) freely, including styling, overriding text (when
> / if necessary) etc., while being fully declarative.
> >
> > This way, the Dialog only does button management (i.e. platform-specific
> layout, creation and destruction), but the aspect of button’s behavior is
> completely separated (providing for a nice separation of concerns), and
> there’re no API bottlenecks like proxy property bags (#5 above) and so on.
> An obvious con would be ease of breaking layouts with geometry bindings  /
> anchors specified for the button (unless specifically addressed (and unset)
> by Dialog’s logic).
>
> This one's obviously the most powerful, but also takes the most effort
> to set up (especially if the user simply wants to disable one button).
>
> Is it viable to combine 2 or more of the options above? e.g. a simple
> API for common use cases, plus option #6 for maximum flexibility.
>
>
> > Overall, approaches #5 and #6 seem to attract more sympathy among those
> who discussed the API decisions in question here internally. What would you
> guys say (most importantly, Qt Quick Controls patch reviewers, but everyone
> else interested as well)?
>
>
> Regards,
> Sze-Howe
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/development/attachments/20150824/8e2c4cd4/attachment.html>


More information about the Development mailing list