Containers

A Container is a control used for grouping other controls and containers. Child objects in a container are arranged according to the specified layout. The default layout of a container is StackLayout, which stacks child objects in a column from top to bottom.


Diagram showing a root container with two child containers.

The image above shows a root container with two child containers. The root container uses the default StackLayout to stack the child containers vertically. The first child container (top) holds three button controls and uses an AbsoluteLayout to explicitly specify the locations for the buttons. The second child container (bottom) holds three buttons and uses a DockLayout to align the buttons to the edges of the container. For more information on layouts, see Layouts.

When you add a control to a container, it is added as the last child object in the container. If a container is removed from a screen, all of its children are removed as well.

A Container has a background property, which allows you to specify a fill. The default fill is transparent.

Sizing

Applying layouts

Layouts provide the basic design for a container in your app. Cascades supports a variety of different layouts, and each has its own set of properties that determine how child controls are arranged.

The following example creates the screen shown in the image above in QML:

// The root container
Container {
    layout: StackLayout {}
    // Create the first child container, applying a
    // spaceQuota of 1.0
    Container {
        layoutProperties: StackLayoutProperties {
            spaceQuota: 1.0
        }
        layout: AbsoluteLayout {}
        // Create three buttons, and set the absolute
        // position for each
        Button {
            layoutProperties: AbsoluteLayoutProperties {
                positionX: 25
                positionY: 25
            }
        }
        Button {
            layoutProperties: AbsoluteLayoutProperties {
                positionX: 200
                positionY: 125
            }  
        }
        Button {
            layoutProperties: AbsoluteLayoutProperties {
                positionX: 350
                positionY: 225
            }
        }
    }
    // Create the second child container, applying a
    // spaceQuota of 1.0
    Container {
        layoutProperties: StackLayoutProperties {
            spaceQuota: 1.0
        }
        layout: DockLayout {}
        horizontalAlignment: HorizontalAlignment.Fill
        // Create three buttons, and use the verticalAlignment
        // and horizontalAlignment properties to set the position
        // for each
        Button {
            verticalAlignment: VerticalAlignment.Top
            horizontalAlignment: HorizontalAlignment.Left
        }
        Button {
            verticalAlignment: VerticalAlignment.Center
            horizontalAlignment: HorizontalAlignment.Right
        }
        Button {
            verticalAlignment: VerticalAlignment.Bottom
            horizontalAlignment: HorizontalAlignment.Center
        }
    }
}

Here's how to do the same thing in C++:

#include <bb/cascades/Container>
#include <bb/cascades/StackLayout>
#include <bb/cascades/StackLayoutProperties>
#include <bb/cascades/AbsoluteLayout>
#include <bb/cascades/AbsoluteLayoutProperties>
#include <bb/cascades/DockLayout>
#include <bb/cascades/Button>
//...

// Create the root container and apply a StackLayout
Container *rootContainer = new Container();
StackLayout *myStackLayout = new StackLayout();
rootContainer->setLayout(myStackLayout);

StackLayoutProperties *sLayoutProperties = 
        StackLayoutProperties::create().spaceQuota(1.0);

// Create the first child container and apply a spaceQuota of 1.0
Container *absoluteContainer = Container::create()
        .layoutProperties(sLayoutProperties);

AbsoluteLayoutProperties *aLPropertiesTop = 
        AbsoluteLayoutProperties::create().x(25).y(25);

AbsoluteLayoutProperties *aLPropertiesCenter = 
        AbsoluteLayoutProperties::create().x(200).y(125);
        
AbsoluteLayoutProperties *aLPropertiesBottom = 
        AbsoluteLayoutProperties::create().x(350).y(225);

// Create three buttons, and set the absolute position for each        
absoluteContainer->add(Button::create()
                       .layoutProperties(aLPropertiesTop));
absoluteContainer->add(Button::create()
                       .layoutProperties(aLPropertiesCenter));
absoluteContainer->add(Button::create()
                       .layoutProperties(aLPropertiesBottom));

// Create the second child container and apply a spaceQuota of 1.0
Container *dockContainer = Container::create()
        .layoutProperties(sLayoutProperties);
        
DockLayout *myDockLayout = new DockLayout();
dockContainer->setLayout(myDockLayout);
dockContainer->setHorizontalAlignment(HorizontalAlignment::Fill);

// Create three buttons and set the horizontal and vertical
// position for each
dockContainer->add(Button::create()
                   .horizontal(HorizontalAlignment::Left)
                   .vertical(VerticalAlignment::Top));
dockContainer->add(Button::create()
                   .horizontal(HorizontalAlignment::Right)
                   .vertical(VerticalAlignment::Center));
dockContainer->add(Button::create()
                   .horizontal(HorizontalAlignment::Center)
                   .vertical(VerticalAlignment::Bottom));
//...

Scroll view

A ScrollView is a variant of a container that allows scrolling and zooming of its content. A ScrollView displays its content using a viewport. A viewport displays a portion of the total content of the scroll view (in a size you specify), and clips the rest. You can scroll the viewport across the entirety of the content, and zoom in and out as well. If the content is smaller than the size of the ScrollView, the entire content is displayed.

The scrollMode property controls the scrolling behavior for the control. The following modes are supported:

  • ScrollMode::None: Scrolling is disabled.
  • ScrollMode::Vertical: Vertical scrolling is enabled.
  • ScrollMode::Horizontal: Horizontal scrolling is enabled.
  • ScrollMode::Both: Both veritcal and horizontal scrolling is enabled.

Zooming and scrolling in the control can be controlled either by the user or programmatically by the app.

Sizing

Container example

The following example demonstrates adding and removing controls in a parent container.

When the Add button is clicked, a new Button is created and added as the last child object to a container. The button text is set from a counter that keeps track of the number of controls that are added to the container. A DropDown allows you to select the index position of the container, and the Insert at and Remove at buttons allow you to insert or remove buttons at the selected index. The background color of the container changes to cyan when a button is added, and red when a button is removed.

Animation showing Button controls being added to a parent container when a button is pressed.

main.qml

import bb.cascades 1.0

Page {
    property int buttonIndex: 0
    
    titleBar: TitleBar {
        title: "Container"
        scrollBehavior: TitleBarScrollBehavior.Sticky
    }
    Container {
        
        Container {
            layout: DockLayout {}
            // Create a ScrollView and set it to fill the
            // horizontal space available
            ScrollView {
                horizontalAlignment: HorizontalAlignment.Fill
                // Create a container to hold the added controls
                Container {
                    id: contentContainer
                    horizontalAlignment: HorizontalAlignment.Fill
                    // Change the backgound color of the container
                    // when a control is added
                    onControlAdded: {
                        contentContainer.background = Color.DarkCyan;
                    }
                    // Change the background color of the container
                    // when a control is removed
                    onControlRemoved: {
                        contentContainer.background = Color.DarkRed;
                    }
                }
            }
            Container {
                verticalAlignment: VerticalAlignment.Bottom
                background: Color.Black
                // Create the "Add" button
                Button {
                    horizontalAlignment: HorizontalAlignment.Fill
                    text: "Add"
                    // When the button is clicked, create a new button,
                    // set the button text using the buttonIndex counter,
                    // and update the value of the buttonIndex counter
                    onClicked: {
                        var item = dynamicButton.createObject();
                        item.setText(buttonIndex)
                        contentContainer.add(item);
                        buttonIndex++;
                    }
                }
                Container {
                    layout: StackLayout {
                        orientation: LayoutOrientation.LeftToRight
                    }
                    // Create the "Remove at" button
                    Button {
                        layoutProperties: StackLayoutProperties {
                            spaceQuota: 1.0
                        }
                        text: "Remove at"
                        // When the button is clicked, remove the button
                        // at the selected value of the drop-down menu
                        onClicked: {
                            contentContainer.remove
                                (contentContainer.at(dropdown.selectedValue))
                        }
                    }
                    // Create the "Insert at" button
                    Button {
                        layoutProperties: StackLayoutProperties {
                            spaceQuota: 1.0
                        }
                        text: "Insert at"
                        // When the button is clicked, add a button at
                        // the selected value of the drop-down menu and
                        // update the buttonIndex counter
                        onClicked: {
                            var item = dynamicButton.createObject();
                            item.setText(buttonIndex)
                            contentContainer.insert
                                (dropdown.selectedValue, item)
                            buttonIndex++;
                        }
                    }
                }
                DropDown {
                    id: dropdown
                    horizontalAlignment: HorizontalAlignment.Center
                    preferredWidth: 400
                    title: "Index"
                    
                    Option { text: "0"; value: 0; selected: true }
                    Option { text: "1"; value: 1}
                    Option { text: "5"; value: 5}
                    Option { text: "10"; value: 10}
                    Option { text: "20"; value: 20}
                }
            }
        }
        attachedObjects: [
            ComponentDefinition {
                id: dynamicButton
                
                Button {
                    horizontalAlignment: HorizontalAlignment.Center
                }
            }
        ]
    }
}

ContainerRecipe.h

#ifndef CONTAINERRECIPE_H_
#define CONTAINERRECIPE_H_

#include <bb/cascades/Page>
#include <bb/cascades/Container>
#include <QObject>
#include <bb/cascades/ScrollView>
#include <bb/cascades/DropDown>
#include <bb/cascades/Button>
#include <bb/cascades/StackLayoutProperties>


namespace bb { namespace cascades { class Application; }}

using namespace bb::cascades;

class ContainerRecipe : public QObject
{
    Q_OBJECT

public:

    ContainerRecipe(bb::cascades::Application *app);
        virtual ~ContainerRecipe() {}

public slots:
    void handleControlAdded();
    void handleControlRemoved();
    void handleAddButtonClicked();
    void handleRemoveButtonClicked();
    void handleInsertButtonClicked();

private:

    int buttonIndex;
    QVariant text1;
    QVariant index;

    Container *contentContainer;
    Container *workingContainer;
    Container *bodyContainer;
    Container *root;

    DropDown *dropdown;

    Button *dynamicButton;
    Button *item;

    ScrollView *myScrollView;

    StackLayoutProperties *mySpaceQuota;

};

#endif /* CONTAINERRECIPE_H_ */

ContainerRecipe.cpp

#include "ContainerRecipe.h"
 
#include <bb/cascades/Application>
#include <bb/cascades/Container>
#include <bb/cascades/DockLayout>
#include <bb/cascades/Page>
#include <bb/cascades/TitleBar>
#include <bb/cascades/TitleBarScrollBehavior>
#include <bb/cascades/Option>
#include <bb/cascades/Color>
#include <bb/cascades/Button>
#include <bb/cascades/StackLayout>
#include <bb/cascades/StackLayoutProperties>
#include <bb/cascades/DropDown>
#include <bb/cascades/ScrollView>
#include <bb/cascades/LayoutOrientation>
#include <bb/cascades/BaseObject>
#include <QVariant>
 
using namespace bb::cascades;
 
ContainerRecipe::ContainerRecipe(bb::cascades::Application *app)
: QObject(app)
{
    // Create a Container and set the layout
    Page *page = new Page();
 
    root = Container::create();
 
    TitleBar *tbar = TitleBar::create
        (TitleBarScrollBehavior::Sticky).title("Container");
    page->setTitleBar(tbar);
 
    workingContainer = Container::create()
            .layout(new DockLayout);
    // Create a scroll view and set it to fill the
    // horizontal space available
    myScrollView = ScrollView::create()
            .horizontal(HorizontalAlignment::Fill)
            .scrollMode(ScrollMode::Vertical);
             
    // Create a container to hold the added controls
    contentContainer = Container::create()
            .horizontal(HorizontalAlignment::Fill);
 
 
    // If any Q_ASSERT statement(s) indicate that the slot failed to
    // connect to the signal, make sure you know exactly why this 
    // has happened. This is not normal, and will cause your app to
    // stop working
    bool connectResult;
     
    // Since the variable is not used in the app, this is added to
    // avoid a compiler warning
    Q_UNUSED(connectResult);
     
    // Connect the controlAdded() signal to the
    // handleControlAdded() slot
    connectResult = connect(contentContainer, SIGNAL
                        (controlAdded(bb::cascades::Control*)), 
                        this,
                        SLOT(handleControlAdded()));
                         
    // This is only available in Debug builds.
    Q_ASSERT(connectResult);
     
    // Connect the controlRemoved() signal to the
    // handleControlRemoved() slot
    connectResult = connect(contentContainer, SIGNAL
                        (controlRemoved(bb::cascades::Control*)), 
                        this,
                        SLOT(handleControlRemoved()));
     
    // This is only available in Debug builds
    Q_ASSERT(connectResult);
     
    bodyContainer = Container::create()
            .vertical(VerticalAlignment::Bottom)
            .background(Color::Black);
     
    // Create the "Add" button
    Button *addButton = Button::create()
            .horizontal(HorizontalAlignment::Fill)
            .text("Add");
 
    // Connect the clicked() signal to the
    // handleAddButtonClicked() slot
    connectResult = connect(addButton, SIGNAL(clicked()), 
                    this,
                    SLOT(handleAddButtonClicked()));
                     
    // This is only available in Debug builds
    Q_ASSERT(connectResult);
     
    Container *stackContainer = Container::create();
 
    StackLayout *sLayout = StackLayout::create()
            .orientation(LayoutOrientation::LeftToRight);
 
    stackContainer->setLayout(sLayout);
 
    mySpaceQuota = StackLayoutProperties::create()
            .spaceQuota(1.0);
 
    // Create the "Remove at" button
    Button *removeButton = Button::create()
            .layoutProperties(mySpaceQuota)
            .text("Remove at");
 
    // Connect the clicked() signal to the
    // handleRemoveButtonClicked() slot
    connectResult = connect(removeButton, SIGNAL(clicked()), 
                    this,
                    SLOT(handleRemoveButtonClicked()));
                         
    // This is only available in Debug builds
    Q_ASSERT(connectResult);
 
    // Create the "Insert at" button
    Button *insertButton = Button::create()
            .layoutProperties(mySpaceQuota)
            .text("Insert at");
 
    // Connect the clicked() signal to the
    // handleInsertButtonClicked() slot
    connectResult = connect(insertButton, SIGNAL(clicked()), 
                    this,
                    SLOT(handleInsertButtonClicked()));
                             
    // This is only available in Debug builds
    Q_ASSERT(connectResult);
     
    dropdown = DropDown::create()
            .horizontal(HorizontalAlignment::Center)
            .preferredWidth(400)
            .title("Index")
            .add(Option::create().text("0").value(0).selected(true))
            .add(Option::create().text("1").value(1))
            .add(Option::create().text("5").value(5))
            .add(Option::create().text("10").value(10))
            .add(Option::create().text("20").value(20));
 
    buttonIndex = 0;
 
    stackContainer->add(removeButton);
    stackContainer->add(insertButton);
    bodyContainer->add(addButton);
    bodyContainer->add(stackContainer);
    bodyContainer->add(dropdown);
    myScrollView->setContent(contentContainer);
    workingContainer->add(myScrollView);
    workingContainer->add(bodyContainer);
    root->add(workingContainer);
    page->setContent(root);
    app->setScene(page);
 
}
 
// Create the handleControlAdded() slot to
// capture the controlAdded() signal
void ContainerRecipe::handleControlAdded()
{
    // Change the background color when a control
    // is added
    contentContainer->setBackground(Color::DarkCyan);
};
 
// Create the handleControlRemoved() slot to
// capture the controlRemoved() signal
void ContainerRecipe::handleControlRemoved()
{
    // Change the background color when a control
    // is removed
    contentContainer->setBackground(Color::DarkRed);
};
 
// Create the handleAddButtonClicked() slot
// to capture the clicked() signal emitted by
// the "Add" button
void ContainerRecipe::handleAddButtonClicked()
{
    // Create a new Button
    dynamicButton = Button::create()
            .horizontal(HorizontalAlignment::Center);
    // Set the button text based on the current
    // index value
    text1 = buttonIndex;
 
    dynamicButton->setText(text1.toString());
 
    // Add the button to the container, as
    // the last child object
    contentContainer->add(dynamicButton);
 
    // Increase the index counter
    buttonIndex++;
 
}
 
// Create the handleRemoveButtonClicked() slot
// to capture the clicked() signal emitted by the
// "Remove at" button
void ContainerRecipe::handleRemoveButtonClicked()
{
    // Set the value of the index variable
    // based on the current value of the drop-down selection
    index = dropdown->selectedValue();
 
    // Remove the button at the specified index
    contentContainer->remove
        (contentContainer->at(index.toInt()));
}
 
// Create the handleInsertButtonClicked() slot
// to capture the clicked() signal emitted by
// the "Insert at" button
void ContainerRecipe::handleInsertButtonClicked()
{
    // Create a new Button
    dynamicButton = Button::create()
            .horizontal(HorizontalAlignment::Center);
 
    // Set the button text based on the current
    // index value
    text1 = buttonIndex;
 
    dynamicButton->setText(text1.toString());
 
    index = dropdown->selectedValue();
 
    // Add the button to the container at the specified
    // index
    contentContainer->insert(index.toInt(), dynamicButton);
 
    // Increase the index counter
    buttonIndex++; 
}

main.cpp

#include "ContainerRecipe.h"

#include <bb/cascades/Application>
#include <Qt/qdeclarativedebug.h>

using namespace bb::cascades;

Q_DECL_EXPORT int main(int argc, char **argv)
{
    Application app(argc, argv);

    new ContainerRecipe(&app);

    return Application::exec();
}

Last modified: 2013-12-21

comments powered by Disqus