Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Native Development Knowledge Base

How to create/remove any number of dynamic controls

by Developer on ‎07-04-2014 02:18 PM (977 Views)

A short example of how to avoid messy QML code such as arrays, maps, switch statements on Ids, etc. when creating and removing multiple dynamic controls.

 

This example adds a countdown timer every time a button is pressed. To indicate how to pass information and control the multiple instances of the custom control (in this case a countdown timer) there is a button for pausing/unpausing all running timers.

 

Dynamic timers

Note: In the screenshots, the term 'infinite' is used to refer to an indeterminate number of controllers.

 

Right, how is it done?

 

The first QML file is just the container for the dynamic controls with a button to add the countdown timer and a button to pause the currently running timers as mentioned earlier.

 

The custom control gets passed in the custom control's object reference on creation and saved in a property to pass back on the timer hitting zero. In this example, a signal is connected to a slot in the custom control after it is added to the Scene Graph so that a single signal tells all the controls to pause their timers.

 

   InfiniteControls.qml

Page {
    Container {
        Container {
            layout: StackLayout {
                orientation: LayoutOrientation.LeftToRight
            }

            Button {
                text: qsTr("Add timer")
                
                onClicked: {
                    var newTimer = countDownTimer.createObject()
                    
                    if (newTimer) {
                        timers.add(newTimer)
                        newTimer.ctrl = newTimer

                        // Connect the pause signal
                        bPause.pauseAll.connect(newTimer.pauseTimer)
                    }
                }
            }
   
            Button {
                id: bPause

                signal pauseAll(bool pause)       // Signal we are going to connect to all dynamic control slots
                property bool paused: false

                text: qsTr("Pause running timers")

                onClicked: {
                    paused = !paused
                    bPause.text = paused ? qsTr("Unpause running timers") : qsTr("Pause running timers")
                    pauseAll(paused)
                }
            }            
        }

        Divider { }

        ScrollView {
            Container {
                id: timers
                
                // Dynamic control area
            }            
        }
    }

    attachedObjects: [
        ComponentDefinition {
            id: countDownTimer
            CountDownTimer {
                onTimedOut: {
                    timers.remove(control)    // Dynamic control has signalled it;s finished, remove from list
                }
            }
        }
    ]
}

 

The next QML file is the count down timer itself (the custom control), on reaching 0 it will send a signal which is picked up by the previous file as a signal to remove the control. The QML file exposes several properties so that it can be easily modified (e.g. different start time, the from property).  The ctrl property is used to hold the custom control's object reference, there are other ways to achieve the same result here but for simplicity and to demonstrate passing in a property and using it in a signal I have chosen this method. The started property is there so that we don't accidentally start timers that haven't already been started before.

 

   CountDownTimer.qml

import bb.cascades 1.2
import custom.lib 1.0

Container {
    signal timedOut(variant control)   // Signal indicating the timer has hit zero

    property variant ctrl: null      // Remember the control for passing back out in the signal
    property int from: 10           // from set as a property so that it can be set to any number from creator 
    property bool started: false  // flag to indicate if this timer has been started for use in 'pause all' function

    function pauseTimer(pause) {
        // Only restart the timers that have been started before
        if (started && !pause)
            timer.start()
        else
            timer.stop()
    }

    layout: StackLayout {
        orientation: LayoutOrientation.LeftToRight
    }

    Button {
        text: qsTr("Start/Stop")
        onClicked: {
            timer.start()
            started = true
        }    
    }

    Label {
        text: from 
    }

    attachedObjects: [
        QTimer {
            id: timer
            interval: 1000

            onTimeout: {
                from -= 1
                if (from <= 0) {
                    timer.stop()
                    timedOut(ctrl)       // Tell any control interested the timer has ended
                }
            }

        }
    ]
}

 

In order to use the QTimer in a QML file it needs to be registered first, so in applicationui.cpp add the following line to the constructor...

 

   applicationui.cpp

qmlRegisterType<QTimer>("custom.lib", 1, 0, "QTimer");

Don't forget to include the header...

 

   applicationui.cpp 

#include <QTimer>

 

As simple as that.

 

BBSJdev

 

Note: Make sure to disconnect the signals properly when adapting this to your own code.

Users Online
Currently online: 22 members 651 guests
Please welcome our newest community members: