Styling QML without manually marking each property to be styled

13,769

Solution 1

The preferred way isn't applying a style on default components, but deriving from these components to create pre-styled custom components.

What I do for my projects :

First, I create one centralized 'theme' file, as a JavaScript shared module :

// MyTheme.js
.pragma library;
var bgColor   = "steelblue";
var fgColor   = "darkred";
var lineSize  = 2;
var roundness = 6;

Next, I create custom components that rely on it :

// MyRoundedRect.qml
import QtQuick 2.0;
import "MyTheme.js" as Theme;
Rectangle {
    color: Theme.bgColor;
    border {
        width: Theme.lineSize;
        color: Theme.fgColor;
    }
    radius: Theme.roundness;
}

Then, I can use my pre-styled component everywhere with a single line of code :

MyRoundedRect { }

And this method has a huge advantage : it's really object-oriented, not simple skinning.

If you want you can even add nested objects in your custom component, like text, image, shadow, etc... or even some UI logic, like color-change on mouse hover.

PS : yeah one can use QML singleton instead of JS module, but it requires extra qmldir file and is supported only from Qt 5.2, which can be limiting. And obviously, a C++ QObject inside a context property would also work (e.g. if you want to load skin properties from a file on the disk...).

Solution 2

It could also be helpful to look at Qt Quick Controls Styles

When using Controls Styles it is not necessary to explicitly assign each property in the target control. All properties can be defined in a separate [ControlName]Style component (e.g. ButtonStyle).
Then in target component (e.g. Button) you can just reference to style component in one line of code.

The only one downside here is that Style components are available for Qt Quick Controls only. Not for any Qt Component.

Share:
13,769

Related videos on Youtube

jesperhh
Author by

jesperhh

Updated on June 11, 2022

Comments

  • jesperhh
    jesperhh about 2 years

    I know that QML does not support CSS styling like widgets do, and I have read up on alternative approaches to styling/theming:

    Common for these approaches is that they require the developer to specify the parts of the QML that can be styled, either by binding to a property in a “styling QML file/singleton”, or by using a Loader to load a different QML component based on style name. What I would like is something that works like the "id" selector in CSS instead of the "class" selector, so that the individual QML files do not have to know whether they will be styled later on or not.

    My current approach make all the QML files look similar to this (using approach in link 2):

    Main.qml

    Rectangle {
        Id: background
        color: g_theme.background.color 
        //g_theme is defined in root context and loaded dynamically
    }
    

    What I would like to do is:

    Main.qml

    Rectangle {
        Id: background
        color: “green” // default color
    }
    

    And then have a styling file that defines (or similar)

    Main.qml #background.color: red
    

    Is this possible at the moment, or something that is in the pipeline for a future Qt version, or will the preferred way of styling continue to be something similar to the approach described in the links above?

  • jesperhh
    jesperhh over 9 years
    Thank you for the answer - I guess your approach is similar to what we currently do except we use qml files to define the "themes" instead of .js files. My issue with this is that we have to decide what we want to style early to avoid having to go through a lot of themes and controls and modify the properties we want to apply styling to. But for now it works alright, so we will keep using this approach until something better shows up.
  • Grégoire Borel
    Grégoire Borel over 8 years
    Would it be possible to get rid of the import "MyTheme.js" as Theme; statement? I would like to do exactly like @jesperhh but with external binary resources. I am wondering if I can change themes in runtime without having to state imports.