Buttons

A Button is a clickable control that you can use to capture touch events in your app. Typically, this control is used to initiate some sort of predefined action. A Button has a fixed height and a variable width. You can also add an image or text to your button to customize its look.

Screen showing a Button with text, a Button with an image and text, a Button with an image, and a colorized Button.

You can add text to a Button by using the text property. Button text has a predefined font, font size, and color, and can't be changed.

Images are added using the image and imageSource properties. The image property uses an Image instance with image data loaded into it, and the imageSource property uses a path to an asset in your project. The aspect ratio of an image automatically scales to fit inside the Button.

A button with only text, or only an image, centers the contents of the button automatically. A button with both text and an image aligns the button contents to the left.

You can change the appearance of a Button using the ControlAppearance class and the Button::color property. The ControlAppearance class contains a set of enums used to control the appearance based on the current theme. For more information, see Themes.

The Button::color property allows you to specify a color for the button using color presets, or a color that you specify. For more information, see the Button API reference.

Sizing

  • The height is fixed and can't be changed.
  • The width is increased automatically to fit text and images.
  • The width is manually adjustable using preferredWidth, minWidth, and maxWidth.
  • The preferredWidth property is ignored if the specified width is smaller than is necessary to fit the content.
  • The maxWidth property can truncate text if the specified width is smaller than is necessary to fit the content. An image cannot be truncated.
  • The leftPadding, rightPadding, topPadding, and bottomPadding properties can't be used on this control.

Image buttons

In addition to the standard buttons listed above, Cascades also includes an ImageButton. Like a standard button, an ImageButton is a clickable control used to intercept touch events. The main difference is that an ImageButton doesn't have a text property. Instead, an ImageButton has different graphical representations that correspond to the possible states of the button.

The different states for an ImageButton are:

  • Default: The button is enabled, but not actively being pressed.
  • Pressed: The button is actively being pressed.
  • Disabled: The button is disabled. This state is controlled by the Control::enabled property.
An ImageToggleButton showing the three visual states of the control.

The behavior of each of the visual states is handled automatically by the OS, so you don't have to add any extra code. If an image source is provided for all three states, an ImageButton will display the image specified using the defaultImageSource property if the button is enabled, display the image specified using the pressedImageSource property while the button is being pressed, and display the image specified using the disabledImageSource property when the Control::enabled property is set to false. If you don't specify an image for a visual state, the ImageButton won't be visible during the respective state.

Even though the ImageButton has different visual states, it's not possible to programmatically set or check the current state of the button.

Sizing

Responding to button presses

When a Button (or an ImageButton) is pressed, it emits a clicked() signal that tells your app that a user has pressed the button. You define the way your app responds to the signal by connecting it to a slot.

In QML, you capture the signal using the onClicked signal handler. This example shows how to capture the signal and change the text that's displayed on the button.

// Create a Button and specify the button text
Button {
    id: myButton
    text: "Button"
    onClicked: {
        // Change the button text when pressed
        myButton.text = "New text";
    }
}

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

#include <bb/cascades/Button>
//...

// Create the Button and set the button text.
// The myButton object is declared in the header
// as follows:
// Button *myButton;
myButton = Button::create()
        .text((const QString) "Button");

// 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 clicked() signal to the handleClicked() slot
connectResult = QObject::connect(myButton, SIGNAL(clicked()), 
                                this, 
                                SLOT(handleClicked()));

// This is only available in Debug builds
Q_ASSERT(connectResult);

//...

// Create the handleClicked() slot
// to capture the clicked() signal
void ButtonRecipe::handleClicked()
{
    // Change the button text when clicked
    myButton->setText("New text");
}

For more information on responding to signals, see Signals and slots.

Button example

The following example creates a series of buttons that change their image source and state when pressed.

The Ripen button icon changes when the button is pressed once. When pressed a second time, the icon changes again and the Orange ImageButton is enabled. Pressing the Ripen button a third time disables the button.

The Eat button text changes when the button is pressed, and it hides the Ripen button.

Pressing the Orange ImageButton resets all the buttons to their original state.

You can download the images for the sample here: images.zip

Animation showing three Button controls that change their image source and state when pressed.

main.qml

import bb.cascades 1.0
 
Page {
    titleBar: TitleBar {
        title: "Button"
    }
     
    Container {
        layout: DockLayout {}
         
        Container {
            horizontalAlignment: HorizontalAlignment.Center
            verticalAlignment: VerticalAlignment.Center
            layout: StackLayout {}
 
            // Create a button with an icon. The icon for the 
            // button is set using the imageSource property. The 
            // id and state properties are used in the switch case to 
            // change the icon each time the button is pressed
            Button {
                id: fruitButton
                property int state: 0
                topMargin: 40
                text: "Ripen"
                imageSource: "asset:///images/button_icon_green.png"
 
                // Attach an onClicked signal handler.
                // A switch case is used to change the 
                // imageSource property for the button when it is 
                // pressed. When the button reaches case 2, the
                // button is disabled
                onClicked: {
                    switch (state) {
                        case 0: {
                            state = 1;
                            fruitButton.imageSource = 
                                "asset:///images/button_icon_ripe.png"
                            break;
                        }
                        case 1: {
                            state = 2;
                            fruitButton.imageSource = 
                                "asset:///images/button_icon_mouldy.png"
                            newButton.enabled = true;
                            break;
                        }
                        case 2:{
                            fruitButton.imageSource = 
                                "asset:///images/button_icon_dust.png"
                            fruitButton.enabled = false;
                            break;
                        }
                    }
                }
            }
 
            // Create a button with a text property of "Eat"
            Button {
                id: eatButton
                text: "Eat"
                topMargin: 40
 
                // Attach an onClicked signal handler to change 
                // the text, and disable the button when it is 
                // pressed. When this button is pressed, it also 
                // hides the first button we created, and 
                // enables the ImageButton below
                onClicked: {
                    if (eatButton.text == "Eat") {
                        eatButton.text = "Burp";
                        eatButton.enabled = false;
                        fruitButton.opacity = 0;
                        newButton.enabled = true;
                    }
                }
            }
 
            // Create an ImageButton, giving it an id, an
            // image source for each state of the 
            // button, and disable the ImageButton by default
            ImageButton {
                id: newButton
                defaultImageSource: 
                    "asset:///images/image_button_enabled.png"
                pressedImageSource: 
                    "asset:///images/image_button_selected.png"
                disabledImageSource: 
                    "asset:///images/image_button_disabled.png"
                topMargin: 40
                enabled: false
                horizontalAlignment: HorizontalAlignment.Center
 
                // Attach an onClicked signal handler that resets all
                // the buttons to their original state
                onClicked: {
                    fruitButton.imageSource = 
                        "asset:///images/button_icon_green.png"
                    fruitButton.enabled = true;
                    fruitButton.opacity = 1.0;
                    fruitButton.state = 0;
                    eatButton.text = "Eat";
                    eatButton.enabled = true;
                    enabled = false;
                }
            }
        }
    }
}

buttonrecipe.h

#ifndef _BUTTONRECIPE_H_
#define _BUTTONRECIPE_H_

#include <bb/cascades/Page>
#include <bb/cascades/Container>
#include <QObject>
#include <bb/cascades/Button>
#include <bb/cascades/ImageButton>


namespace bb { namespace cascades { class Application; }}

using namespace bb::cascades;

class ButtonRecipe : public QObject
{
    Q_OBJECT

public:

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

public slots:

    void onNewButtonClicked();

    void onEatButtonClicked();

    void onRipenButtonClicked();

private:

    Button *mFruitButton;
    Button *mEatButton;
    ImageButton *mNewButton;

    int mState;

    Page *root;
    Container *recipeContainer;

};

#endif // ifndef _BUTTONRECIPE_H_

buttonrecipe.cpp

#include "buttonrecipe.h"

#include <bb/cascades/Application>
#include <bb/cascades/Button>
#include <bb/cascades/Container>
#include <bb/cascades/DockLayout>
#include <bb/cascades/ImageButton>
#include <bb/cascades/StackLayout>
#include <bb/cascades/Page>

#include <bb/cascades/TitleBar>

using namespace bb::cascades;

ButtonRecipe::ButtonRecipe(bb::cascades::Application *app)
: QObject(app)
{

    Page *page = new Page();
    Container *root = Container::create().layout(new DockLayout());
    TitleBar *tbar = TitleBar::create().title("Button");
    page->setTitleBar(tbar);

    Container *recipeContainer = Container::create()
                .left(20.0).right(20.0)
                .horizontal(HorizontalAlignment::Center)
                .vertical(VerticalAlignment::Center);

    StackLayout *recipeLayout = new StackLayout();
    recipeContainer->setLayout(recipeLayout);

    // Create a Button and set the text as "Ripen"
    mFruitButton = Button::create()
    		.text((const char*) "Ripen")
    		.imageSource(QUrl("asset:///images/button_icon_green.png"))
    		.topMargin(40.0f)
    		.preferredWidth(350)
    		.horizontal(HorizontalAlignment::Center);

    // 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 clicked() signal to the onRipenButtonClicked() slot
    connectResult =  connect(mFruitButton, SIGNAL
        (clicked()), this, SLOT(onRipenButtonClicked()));

    // This is only available in Debug builds
    Q_ASSERT(connectResult);

    // Create a Button with the text "Eat"
    mEatButton = Button::create()
    		.text((const char*) "Eat")
    		.topMargin(40.0f)
    		.preferredWidth(350)
    		.horizontal(HorizontalAlignment::Center);

    // Connect the clicked() signal to the onEatButtonClicked() slot
    connectResult =  connect(mEatButton, SIGNAL
        (clicked()), this, SLOT(onEatButtonClicked()));

    Q_ASSERT(connectResult);

    // Create a disabled ImageButton
    mNewButton = ImageButton::create()
    		.enabled(false)
    		.topMargin(40.0f)
    		.horizontal(HorizontalAlignment::Center);

    // Specify images for the different states of the button
    mNewButton->setDefaultImageSource
        (QUrl("asset:///images/image_button_enabled.png"));
    mNewButton->setPressedImageSource
        (QUrl("asset:///images/image_button_selected.png"));
    mNewButton->setDisabledImageSource
        (QUrl("asset:///images/image_button_disabled.png"));

    // Connect the clicked() signal to the onNewButtonClicked() slot
    connectResult =  connect(mNewButton, SIGNAL(clicked()),
                                this, SLOT(onNewButtonClicked()));

    Q_ASSERT(connectResult);

    //Add the buttons to the container
    recipeContainer->add(mFruitButton);
    recipeContainer->add(mEatButton);
    recipeContainer->add(mNewButton);

    root->add(recipeContainer);
    page->setContent(root);
    app->setScene(page);
    mState = 0;
}

void ButtonRecipe::onRipenButtonClicked()
{
    // Alternate the button icon when clicked depending
    // on the state of the control
    switch (mState) {
        case 0: {
            mState = 1;
            mFruitButton->setImageSource(
                    QUrl("asset:///images/button_icon_ripe.png"));
            break;
        }
        case 1: {
            mState = 2;
            mFruitButton->setImageSource(
                    QUrl("asset:///images/button_icon_mouldy.png"));
            mNewButton->setEnabled(true);
            break;
        }
        case 2: {
            mFruitButton->setImageSource(
                    QUrl("asset:///images/button_icon_dust.png"));
            mFruitButton->setEnabled(false);
            break;
        }
    }
}

void ButtonRecipe::onEatButtonClicked()
{
    // Change the button text when clicked and hide the "Ripen" button
    if (mEatButton->text() =="Eat") {
        mEatButton->setText("Burp");
        mEatButton->setEnabled(false);
        mFruitButton->setOpacity(0.0);
        mNewButton->setEnabled(true);
    }
}

void ButtonRecipe::onNewButtonClicked()
{
    // Reset all the buttons to their original state
    mFruitButton->setImageSource
        (QUrl("asset:///images/button_icon_green.png"));
    mFruitButton->setEnabled(true);
    mFruitButton->setOpacity(1.0);
    mState = 0;

    mEatButton->setText("Eat");
    mEatButton->setEnabled(true);

    mNewButton->setEnabled(false);
}

main.cpp

#include "ButtonRecipe.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 ButtonRecipe(&app);
 
    return Application::exec();
}

Last modified: 2014-09-30



Got questions about leaving a comment? Get answers from our Disqus FAQ.

comments powered by Disqus