Richard Moe Gustavsen

Native look and feel

Published Monday February 6th, 2017
27 Comments on Native look and feel
Posted in Dev Loop, Qt Quick Controls, Styles

We know that many Qt users want controls styled with a native look-and-feel. But offering that on platforms with no public styling API, is hard. A classic approach is to take snapshots of the native controls, tweak them, and use them as foreground or background in our own controls. Which is somewhat OK for static appearances. But when animations and transitions are involved, static pixmaps will only take you half the way. And since an OS can change style from one update to the next, taking snapshots runtime is risky. Using pre-grabbed snapshots is also something we don’t do because of legal considerations.

Since December last year, the controls team has been researching a bit small scale on a new project to offer controls with true native look-and-feel. The aim is to do the alternative to the above standing, and explore how feasible it would be to wrap actual native controls into a cross platform Qt API. Such ideas is nothing new of course, and have been discussed many times, at least internally. One of the problems is that different platforms can vary quite much API-wise, especially for more complex controls like tab-, and split views, with some having a rich API, while others are more limited. And unifying that into a common useable Qt API is a challenge.

Currently we have prototyped a set of controls, together with a plugin-based framework and a few backends for testing (uikit, appkit, android). The API is small and strict so that it can be realized on all supported (and future) platforms. As such, the controls become rather black box, since we cannot make assumptions on how they are implemented by the backends. Still, there will be times when you need to detail how your application should work on a specific platform. For that reason we plan to open up, and factor out, the various backends into separate libraries that can be accessed directly. Those libraries will wrap parts of the native APIs more closely, and offer building blocks specific to the platform, or controls with a broader set of functions and properties. They will be more open than the common controls, giving access to the native controls they wrap, to let you dig into to native development whenever you need to fill gaps that falls outside our own scope. In the end, it should be easy and straightforward to mix cross-platform controls, platform-specific controls, and native code in your application.

I’ve mentioned “APIs” a couple of times. This of course includes QML. But we also plan to offer direct access to the underlying C++ libraries, making it easy to extend the API, and write applications using C++ only. That way you can choose whether you want to use QML, C++, or a combination.

Here is a snippet showing how things look so far. The app mixes a couple of cross-platform controls (common controls) together with a control directly from the AppKit backend.

import QtQml 2.0
import Qt.CommonControls 1.0 as Common
import Qt.AppKitControls 1.0 as AppKit

Window {
    id: window
    visible: true

    Common.Button {
        id: button
        x: 20
        y: 20
        text: "Click me"
        onClicked: text ="You clicked me!"
    }

    Common.TextField {
        id: textField
        placeholderText: "TextField"
        x: 20
        y: button.bottom + 8
    }

    AppKit.SearchField {
        placeholderText: "Search"
        x: 20
        y: textField.bottom + 8
    }
}

The next snippet shows the same app, but this time in C++

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QCommonWindow window;

    QCommonButton commonButton(QStringLiteral("Click me"), &window);
    commonButton.move(20, 20);
    QObject::connect(&commonButton, &QCommonButton::clicked, [&commonButton](){
        commonButton.setText(QStringLiteral("Clicked!"));
    });

    QCommonTextField textField(&window);
    textField.setPlaceholderText(QStringLiteral("TextField"));
    textField.move(20, commonButton.bottom() + 8);

#if defined(Q_OS_MACOS)
    QAppKitSearchField searchField;
    searchField.setParent(&window);
    searchField.move(20, textField.bottom() + 8);
    NSSearchField *nsSearchField = searchField.nsSearchFieldHandle();
    nsSearchField.placeholderString = @"Search...";
#endif

    window.showFullScreen();
    return app.exec();
}

As mentioned, we plan to keep the API rather strict. The common controls will only contain the basics, with few, or no possibilities for tweaking the style, catching internal events, or overriding default behaviour. You basically get native controls with native look, feel and behaviour. If you, on the other hand, need custom styling, or your own custom controls, Qt offer solutions like QtQuickControls2, or Widgets, for that already. Our current thinking is that this module will be something for Qt6.

Do you like this? Share it
Share on LinkedInGoogle+Share on FacebookTweet about this on Twitter

Posted in Dev Loop, Qt Quick Controls, Styles

27 comments

Pierre-Yves Siret says:

Does that mean we will be able to have a window where native controls and quick controls can cohabitate ?
Will they have the same limitation than the current WebView (can’t overlay quick items on top) ?

Frederik Gladhorn Frederik Gladhorn says:

This is early research, I don’t think we fully know the limitations yet. My current feeling is that in general developers would want to create “native” applications but re-use custom Qt Quick in the same UI. Thus the base would be a native layer and we allow to mix in Qt Quick content.

Nikita Krupenko says:

Sounds great. Ability to add some native controls to a QtQuick app could be quite useful.

J-P Nurmi J-P Nurmi says:

Hi Nikita. It would be probably the other way around. That is, adding Qt Quick content to a native app ie. using Qt Quick as a canvas.

PeterBocan says:

Finally some advancements in Look’n’feel… but maybe I’ll be first. 😀

makochan says:

Don’t forget for about table view on qtquickcontrols2 please..

J-P Nurmi J-P Nurmi says:

We haven’t forgotten TableView. 🙂 I have been working on it since October. In the beginning prototyping different approaches in a personal playground, and recently moved to a public WIP branch: http://lists.qt-project.org/pipermail/development/2017-January/028344.html

avb says:

That is great to hear!

Will it support changing orientation (columns to become rows) -> https://bugreports.qt.io/browse/QTBUG-50532

J-P Nurmi J-P Nurmi says:

I’m not sure whether it will be called ‘orientation’, ‘flow’ (like in GridView), or something else, but yes, the plan is to support that concept too. 😉

Jake Petroules Jake Petroules says:

I also have UWP support in a branch somewhere, meaning that we are testing on at least Universal Windows Platform (WinRT), macOS, iOS, tvOS, and Android to start with. Win32 and GTK backends will also be needed, and QtWidgets should probably also be one of the possible backends (for proper KDE look-and-feel). For embedded devices, a Qt Quick Controls 2 backend is an interesting idea as well.

exim says:

Any plans for Qt Quick Controls for pure C++? (without QML/js crap)

J-P Nurmi J-P Nurmi says:

We have plans to open up some of the C++ APIs later when we are ready to commit for binary compatibility. However, these C++ APIs are likely to be for the Qt Quick Templates that are pure C++ classes, not for Qt Quick Controls that are visual styles implemented using QML. There is simply no C++ class for a styled Button, for instance. It is a QML composite type. Even if you don’t like QML, it was solely thanks to QML that we even created the Material and Universal styles. If we had had to do all that in C++, we would be still working on the first version… 🙂

Diego says:

Now that you are developing a new set of api.. How about making them in a new namespace, to make it more modern, and making code smaller and readable:

using namespace QtCommonControls;

var button = Button();
button.move(200, 200);

Birdy says:

QWidgets, QtQuick.Controls, QtQuick.Controls2 and now even one more UI set. It get’s more and more confusing. Or is there a chance that this new “native controls” will replace the 2 existing controls with Qt6?

Frederik Gladhorn Frederik Gladhorn says:

Indeed. Be aware that this is an experiment. We’d like to reduce the amount of options for doing UI in Qt 6. Widgets will be around for sure. Qt Quick Controls 2 for devices and ideally this new project to cover the rest.

BaCaRoZzo says:

The outlined scenario does make sense to me. That’s probably the best way to go. However Qt 6 seems to be not so near and the native controls are still an experiment. In the meanwhile, what’s the planning for quick controls 2? I’ve read somewhere that there’s a planning to had other styles but iOS one could be problematic due to legal issues. Thus the biggest question of all is: will an iOS style be added in the near future? A clear answer to this topic would be really appreciated. Thanks.

Benoit says:

Awesome! That’s definitely the way to go. Create a native UI and embed common, cross-platform elements. I can easily image the common case:
– Android app with action bar and drawer
– iOS app with navigation bar and tab bar
– Common “pages” with embedded Quick views (with or without Quick Controls 2 elements)
– Settings page with native UI elements (buttons, sliders, …)

I cannot imagine a better way to develop cross-platform apps with a good user acceptance (which requires a native look’n feel). React native has such an approach but is quite limited in terms of functionalities (and does not have the power of Qt).

It additionally gives more confidence to companies deciding to use Qt for developing apps because they can still use native OS functionalities, even for the user interface and thus save time and money with a convenient, powerful, convenient cross-platform technology while keeping a high confidence level because and enjoying the best of both worlds.

That’s definitely the project which will help Qt being the best choice for cross-platform development.

micu says:

Wow, thanks for the update. That sounds like pretty hot stuff.

Does that mean we also get sth. #ifdef for QML? (Runtime or “compile time”, i.e. like a preprocessor) 🙂
That would be really helpful to do things like

“`
import Qt.CommonControls 1.0 as Common
#ifdef iOS
import Qt.AppKitControls 1.0 as AppKit
#elif SailfishOS
import Sailfish.Silica 1.0
#endif

Window {
id: window
visible: true


Common.TextField {
id: textField
placeholderText: “TextField”
x: 20
y: button.bottom + 8
}

#ifdef iOS
AppKit.SearchField {

}
#elif SailfishOS
Silica.SearchField …

“`

}

Richard Moe Gustavsen Richard Moe Gustavsen says:

We have been thinking in the same direction, but its currently too early to say. What you can do already is to place the platform specific parts into separate QML files, and use the file selector system to load the correct files at runtime (e.g wrap ‘AppKit.SearchField’ in a ‘MySearchField.qml’ file, and place it in a ‘+macos’ folder)

Emiliano Beronich says:

An approach that I use for specific platform code is by using Qt.os.platform on qml files.
Example:
onClicked(): {
if (Qt.platform.os == “android”) {
// android specific stuff
} else if (Qt.platform.os == “ios”) {
// ios specific stuff
}
}

Thorbjørn says:

Since these controls are native, I think it would be better to call it Qt.NativeControls and QNativeButton. I think it’s more intuitive and it will make it more clear when reading code.

Richard Moe Gustavsen Richard Moe Gustavsen says:

That’s what we currently use internally as well. But we found it far too easy to get confused when e.g talking about a “native button” – do we then mean the Qt button or the platform native button? So the naming will change. But not to “common”, that was just a name chosen for the blog until it’s decided.

Flavio says:

This is incredible news! I’ve been silently watching Qt evolve in a direction that is not relevant for desktop applications and people that would rather stick to C++ than having a codebase split in two languages.

Btw, NSSearchField is the perfect example of why Qt should have native controls.

Will Stokes says:

Agreed 100%. I’d love to start using QAppKitSearchField now. Any chance that class, which I presume is a QWidget and can be inserted into a QLayout, will be made available before qt6?

Richard Moe Gustavsen Richard Moe Gustavsen says:

It’s not a QWidget. The common controls are independent of any specific control sets (even tough QWidgets will be a possible backend). So the answer is “no”.

Benoit says:

By the way, I am just wondering if you plan something to achieve lay outing of native control in a cross-platform way. While I can image using platform-specific layout definition (constraints on iOS, layouts on Android, …), the challenge seems to be much higher to use the same definition for both.

That’s why I am wondering if the easiest solution would not be to use platform-specific UI and embed common ones when appropriate (e.g. charts or Quick views)?

Richard Moe Gustavsen Richard Moe Gustavsen says:

It’s a bit early to say. But some common layout scheme needs to be available. In the end, I guess the amount of platform specific code vs common controls needed will vary individually per app.

Commenting closed.

Get started today with Qt Download now