Creating QML Controls From Scratch

By Chris Cortopassi

Continuing our QML Controls from Scratch series, this time we'll implement a CheckBox. We'll also get RadioButton almost for free. CheckBox is similar to Button with the exception that it holds checked/unchecked state in the checked property. All QML properties have an associated *Changed signal, so the checkedChanged() signal (useful for C++) causes onCheckedChanged to run when the property checked changes.

CheckBox also serves as a radio button if a client sets radio: true, which is all RadioButton.qml does. To get multiple radio buttons to act together in a group, put a RadioButton in a ListView delegate with currentIndex indicating the currently selected radio button (see test.qml below).

Since we're not using Image, we used a unicode check ✓ (hexadecimal 2713) glyph to render the check mark as Text, but you might want to replace with an Image .png asset from your designer. The RadioButton dot is implemented with a Rectangle.

Take a look:


import QtQuick 2.0

Item { // size controlled by height
    id: root
// public    
    property string text:    'text'
    property bool   checked: false; // onCheckedChanged: print('onCheckedChanged', checked)
    signal clicked(bool checked);   // onClicked: print('onClicked', checked) // only runs via user interaction whereas checkedChanged runs via programmatic changes to checked as well

// private
    property real padding: 0.1    // around rectangle: percent of root.height
    property bool radio:   false  // false: check box, true: radio button
    width: 250;  height: 50  // default size
    //width: rectangle.width + 3 * padding * root.height + text.width;  height: 50 // width expands with text width
    opacity: enabled? 1: 0.3 // disabled state
    Rectangle { // check box (or circle for radio button)
        id: rectangle
        height: root.height * (1 - 2 * padding);  width: height // square
        x: padding * root.height
        anchors.verticalCenter: parent.verticalCenter
        border.width: 0.05 * root.height
        radius: (radio? 0.5: 0.2) * height
        Text { // check
            visible: checked  &&  !radio
            anchors.centerIn: parent
            text: '\u2713' // <a href=""></a>;            font.pixelSize: parent.height
        Rectangle { // radio dot
            visible: checked  &amp;&amp;  radio
            color: 'black'
            width: 0.5 * parent.width;  height: width // square
            anchors.centerIn: parent
            radius: 0.5 * width // circle

    Text {
        id: text
        text: root.text
        anchors {left: rectangle.right;  verticalCenter: rectangle.verticalCenter;  margins: padding * root.height}
        font.pixelSize: 0.5 * root.height
    MouseArea {
        anchors.fill: parent
        onPressed:  parent.opacity = 0.5 // down state
        onReleased: parent.opacity = 1
        onCanceled: parent.opacity = 1
        onClicked: {
            if(!radio)  checked = !checked // clients of radio button must set checked to keep them all in sync
            root.clicked(checked) // emit


import QtQuick 2.0

CheckBox {
    radio: true


CheckBox {            
    text:             'CheckBox'
    checked:          true
    onCheckedChanged: print('CheckBox onCheckedChanged', checked)
ListView { // RadioButton
    width: 250;  height: 50 * count
    model:[{text: 'RadioButton 0'}, {text: 'RadioButton 1'}]
    delegate: RadioButton {
        text:             modelData.text
        checked:          currentIndex == index // equality
        onClicked:        currentIndex =  index // assignment
        onCheckedChanged: print('RadioButton onCheckedChanged', index, checked)


In this post, we created CheckBox and RadioButton. Next time we'll create Switch. The source code can be downloaded here.

Have a question or want to add to the conversation?

You must be logged in to continue.

Log in Register