Saturday, April 30, 2011

Audiobook Reader for N900 using QML and Phonon

Now days I am trying to learn Qt Quick (QML) and as exercise I decided to upgraded my Audiobook reader application to use QML.

Outcome is pretty good I think, GUI looks much more impressive than earlier though feature set remain same as before.

Currently new version is waiting to be approved by Ovi Store QA. As soon as its cleared you can download it for free from Ovi Store. But its only available for N900 users.

Following is demo video on Qt SDK simulator, Please note that File Dialog will be different on actual hardware.



Following are screen capture from application.



Friday, April 22, 2011

Creating scrollable large text with QML

Recently I wanted to show large text of help in my QML application. I used TextEdit QML element to show large text but it dose not support scrolling by default. We need to add it to Flickable element to support scrolling of text. We can add other QML element as well to Flickable to add scrolling support to those element.

Following is my code, My code dose not shows scrollbar, There are some QML example from Qt which shows how to add scrollbar to Flickable element.
Rectangle {
    id:main
    width:300; height:300

    Rectangle {
        id:helpScreen
        width:main.width; height:main.height

        Flickable {
            id: flickArea
             anchors.fill: parent
             contentWidth: helpText.width; contentHeight: helpText.height
             flickableDirection: Flickable.VerticalFlick
             clip: true

             TextEdit{
                  id: helpText
                   wrapMode: TextEdit.Wrap
                   width:helpScreen.width;
                   readOnly:true

                   text:  "Text goes here"
            }
        }
    }
}
Hope this helps.

Sunday, April 10, 2011

Creating QML element dynamically on runtime

Often while working with QML we need to create QML element dynamically on runtime depending upon some event like button click or something else.

Following code described how we can create QML element at runtime dynamically. In following code I am trying to create Rect QML element on runtime, set some property on element and also connecting signal from Rect element.

  function createRect(num)
  {       
        var component = Qt.createComponent("Rect.qml");               
        var rect = component.createObject(main,{"x":50,"y":10});
        if(rect != null ) {
            rect.name = "Test";      
            rect.x =  Math.floor(Math.random() * 300 );
            rect.y = Math.floor(Math.random() * 100 );
            rect.dropped.connect(dropped);
      }
  }

 function dropped(x,y,name)
 {
    console.log("################## Dropped:"+name+"::"+ x +":"+ y);
 }

In above code "dropped" is signal defined in Rect element. And I am calling connect method of signal to connect "dropped" signal to my slot "dropped".

Following is code from "Rect.qml" that define Rect element.

Rectangle {
    width:100
    height:50
    color:"lightblue"
    property string name: "";
    signal dropped(int x,int y,string name);
}

That's all, Hope this helps.

Saturday, April 9, 2011

Playing sound with Qt and Phonon

In games generally we need to play small sound clips. For Qt program in such case I prefer to use Phonon module.

Following is simple sample code that plays sound clips on button click event.

In constructor I am creating media object and audio output. MediaObject class provides playback interface, AudioOutput send audio data to output device and by createPath method call we are creating connection of media object to audio output.

Then in playSound method I am setting sound file which needs to be played by calling setCurrentSource api and providing path of sound file. Finally by calling play API on media object i am playing sound file.

SoundWidget::SoundWidget(QWidget *parent) :
    QWidget(parent) 
{
    QVBoxLayout* main = new QVBoxLayout(this);
    QPushButton* btn = new QPushButton("Play Sound");
    connect(btn,SIGNAL(clicked()),this,SLOT(playSound()));
    main->addWidget(btn);

    mMediaObject = new Phonon::MediaObject(this);
    mAudioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this);
    mAudioOutput->setVolume(0.5);

    Phonon::createPath(mMediaObject, mAudioOutput);
}

void SoundWidget::playSound() 
{
    mMediaObject->setCurrentSource(QString("./Sound5.wav") );
    mMediaObject->play();
}

Following is header file for above code. You also need to add phonon module in Qt project file by putting "QT += phonon" in pro file.
#ifndef SOUNDWIDGET_H
#define SOUNDWIDGET_H

#include <QWidget>
#include <phonon/mediaobject.h>
#include <phonon/audiooutput.h>

class SoundWidget : public QWidget
{
    Q_OBJECT
public:
    explicit SoundWidget(QWidget *parent = 0);   

public slots:
    void playSound();

private:
    Phonon::MediaObject* mMediaObject;
    Phonon::AudioOutput* mAudioOutput;
};

#endif // SOUNDWIDGET_H

Saturday, April 2, 2011

Signal Slot connection with QML and Qt C++ code

As you might already know, currently I am working on porting of my existing Qt application to QML. And while doing so I required to interconnect QML code to C++ code using signal slot.

Honestly, I found it quite cumbersome to connect QML signal to Qt C++ slot. I decided to avoid connecting QML signal to Qt Slot and instead choose to expose slot from Qt to QML,which it can invoke from any QML file. As it's quite convenient to expose Qt slot to QML element.

Connecting Qt signal to QML is quite easy. We can use Connections component to connect Qt signal to QML element.

Following code is exposing Qt C++ Object to QML, so QML elements can invoke Qt slot.
    TimerObject timerObj;
    QDeclarativeView view;
    view.setResizeMode(QDeclarativeView::SizeRootObjectToView);
    QDeclarativeContext *ctxt = view.rootContext();
    ctxt->setContextProperty("timer", &timerObj);

    view.setSource(QUrl("qrc:/main.qml"));
    view.show();

So, now we can use "timer" object from QML to invoke C++ slot. like shown in below.
Button {
    anchors.horizontalCenter:parent.horizontalCenter
    text: "Start Timer"
    width: parent.width/2

    onClicked: {
       timer.startStopTimer();
    }
}
If you want to use Button element used in above code visit this link.

Following code is connecting signal emitted from Qt C++ to QML. below I am connecting TimerObject's (timer in QML) timeChanged signal to QML element using Connection component.
    Connections {
        target:timer
        onTimeChanged: {
            clock.text = "<h1>"+time+"</h1>"
        }
    }

timeChanged signal is defined like following in C++ code.
signals:
    void timeChanged(QString time);

Creating Glossy button with QML


Recently while working on my pet QML project I created reusable glossy QML button element. Hope it will help someone.

Well it quite simple to achieve this, I used Gradient element with right color combination and proper mouse event handling. Following is output.



Here is code for Button element from Button.qml
import Qt 4.7

Rectangle {
    id: button
    signal clicked
    property alias text: btnText.text

    height: 50
    //radius: 10
    border.color:"#6a6363"

    gradient: off

     Gradient {
        id:off
        GradientStop { position: 0.0; color: "lightsteelblue" }
        GradientStop { position: 0.5; color: "lightsteelblue" }
        GradientStop { position: 0.5; color: "black" }
        GradientStop { position: 1.0; color: "black" }
    }

    Gradient {
        id:onn
        GradientStop { position: 0.0; color: "steelblue" }
        GradientStop { position: 0.5; color: "steelblue" }
        GradientStop { position: 0.5; color: "black" }
        GradientStop { position: 1.0; color: "black" }
    }

    Text {
        id:btnText
        anchors.centerIn:parent
        color:"white"
        text: "text"
    }

    MouseArea {
            id: mouseArea
            anchors.fill: parent
            onClicked:  {
                button.clicked();
            }

            onEntered:{
                button.gradient=onn
                border.color= "steelblue"
            }

            onCanceled:{
                border.color= "#6a6363"
                button.gradient=off
            }

            onExited: {
                border.color= "#6a6363"
                button.gradient=off
            }
        }
}

Following is how you can use above Button element.
    Button {
        anchors.centerIn:parent
        text: "Test Button"
        width: parent.width/2 -10

        onClicked: {
            console.log("Add folder clicked");
        }
    }