[Development] QAction-like API for QML

Alan Alpert 416365416c at gmail.com
Mon Dec 17 00:38:12 CET 2012

On Sun, Dec 16, 2012 at 6:32 AM, Bache-Wiig Jens
<Jens.Bache-Wiig at digia.com> wrote:
>> Having a common base class was something I thought of last summer or
>> so.  I still think maybe it can work.  But we won't get the benefit of
>> it unless we change the QWidget menu system to take the base class
>> pointers, and deal with them polymorphically; or deprecate the old
>> QAction and have the widget menus also take the new class.  Then it
>> would be possible to create one kind of actions which can be used to
>> build both declarative-based and widget-based UIs.  If nobody thinks
>> that will ever be useful, then we might as well just have an
>> independent action class which is only for use in declarative UIs.
> I did not say the idea was not useful. My point was that it is not required since we already have access to everything the common base class would give you. Action is a QObject, so when we expose it to QML, we can already access text, toolTip, statusTip, triggered and all of those core properties even without sharing the implementation. The only issue we have is when we try to make direct use of unknown data types like QIcon, or QKeySequence. Since these are anyway not going to be part of CoreAction, there was really no added benefit. Of course we would need a shared implementation to support QML-declared actions directly in C++ widgets, but this would essentially be like writing a QML backend to a C++ application, which I don't see as a realistic use case.

With regards to QKeySequence, a string property for shortcuts was
suggested which would become a QKeySeqence internally. The QML Action
needs to integrate with global shortcuts too.

It's not really very elegant to use the Action API via properties on a
QObject* type, because of the QVariants in between and because it
means we'd have to wrap it in a way that you can't use C++ QActions
directly (the best would be QmlAction{ realAction: myApp.exposedAction
}. A shared implementation is also the best way to use C++-declared
actions directly in a QML scene.

>> I like the idea but I'm not sure it's possible.  QIcon would have to
>> come along for the ride, for one thing.  (But we will need some
>> mechanism like that in declarative anyway.)  Last time I tried to
>> trace the dependency chain, I think it turned out there were some
>> inescapable dependencies on QWidget stuff which we cannot break
>> without changing the API (not to mention binary compatibility).
>>> Problem: QAction is in QtWidgets. Either we have to somehow move it
>>> out, or this new Action class goes in a plugin which depends on
>>> QtWidgets (a dependency we generally like to avoid). This is the
>>> primary advantage of the QGuiAction approach - it can go in QtGui.
>>> It's not like a QtWidgetEnablers import in QML would be terrible, it's
>>> just that it increases the weight of other modules using it (very
>>> undesirable for embedded).
> What is so terrible about it? QtWidgetEnables would be private API, only used by components internally and we would not need to load the module on embedded, or am I missing something?

I don't see how you'd avoid loading the module on embedded. Because
the components are written in QML you'd need the QtWidgetEnablers
plugin available at runtime for any application using the components
(assuming they include an import QtWidgetEnablers 1.0 line). I also
don't know how you'd write the C++ module to avoid having a
libQt5Widgets runtime dependency.

The only dynamic inclusion approach I can think of is to have
QtWidgetEnablers contain another version of Menu {}, which can be used
like a Menu{} in components but shich can also accept QAction*s. Then
the extra module is loaded only by components users wanting to use

> Worst case scenario is anyway that we simply do not support QIcon and QKeySequence but we will still have all the benefits of coreAction.
>>> Actually I was under the impression we wanted to do something better
>>> (ergo, different) to widgets. The widget approach of grouping menus
>>> separately from actions means that the common case is to fill the menu
>>> with the actions in the exact same order you declared the actions.
> But QAction and collapsible groups is not the right abstraction for this. First of all it means nothing in QToolBar. (what is a collapsed group or sub-menu doing there?)

That's why collapsible is a hint. Then the groups are just logical
groupings. It means you can at least use the same hierarchy
everywhere, whereas in QtWidgets you need to flatly add every action
to every menu and every toolbar. It's so much more convenient to be
able to just have a hierarchy with a root node that you can assign to

As a hint it is also not menu specific, making it easier to reuse in
custom component sets.

> When you want to re-use a menu, I would argue the appropriate abstraction would be to make a QMenu subclass using a subset of actions. An action group should not be assumed to be a menu since it can be used in any context.
> Similarly in QML, I would create a Menu component and re-use that. When I use the same actions in a toolbar I would anyway have to re-order and handpick the ones that make sense in that context. An action by itsel should not care if it is used in a menu, toolbar or button.
>> But if you can end up with a very terse menu declaration in QML at the
>> end, I think that's very worthwhile.
>> MenuBar { MyMenuGroup { } }
> As I said I don't think ActionGroup is the correct abstraction. You are already treating it as if it was a menu. If it was, then you should be able to put it in a ToolBar as well. How meaningful is this:  ToolBar { MyMenuGroup{} }

Rename the element MyActionGroup{} and it suddenly makes perfect
sense. Although it's still abstracted to such a degree that it doesn't
cover the question of whether menu and toolbar action groups normally

> I would prefer: MenuBar { EditMenu { } } where EditMenu is a carefully crafted Menu, built using a subset of actions.

Alan Alpert

More information about the Development mailing list