×
Namespaces

Variants
Actions
(Difference between revisions)

Creating a custom QML element with Qt

From Nokia Developer Wiki
Jump to: navigation, search
croozeus (Talk | contribs)
m (Removing non-existing category)
hamishwillee (Talk | contribs)
m (Hamishwillee - Add Abstract. Improve categories)
 
(17 intermediate revisions by 5 users not shown)
Line 1: Line 1:
{{CodeSnippet
+
[[Category:Qt]][[Category:Qt Quick]][[Category:Code Snippet]][[Category:MeeGo Harmattan]][[Category:Symbian]][[Category:UI]]
|id=
+
{{Abstract|This snippet shows how to create a custom QML element.}}
|platform=S60 5th Edition<br>Maemo
+
{{ArticleMetaData <!-- v1.2 -->
|devices=Nokia 900
+
|sourcecode= <!-- Link to example source code (e.g. [[Media:The Code Example ZIP.zip]]) -->
|category=Qt
+
|installfile= <!-- Link to installation file (e.g. [[Media:The Installation File.sis]]) -->
|subcategory=Qt Quick
+
|devices= Nokia 900
|creationdate=June 16, 2010
+
|sdk= <!-- SDK(s) built and tested against (e.g. [http://linktosdkdownload/ Nokia Qt SDK 1.1]) -->
|keywords=QML, QDeclarativeItem
+
|platform= S60 5th Edition<br>Maemo
 +
|devicecompatability= <!-- Compatible devices (e.g.: All* (must have GPS) ) -->
 +
|dependencies= <!-- Any other/external dependencies e.g.: Google Maps Api v1.0 -->
 +
|signing= <!-- Empty or one of Self-Signed, DevCert, Manufacturer -->
 +
|capabilities= <!-- Capabilities required by the article/code example (e.g. Location, NetworkServices. -->
 +
|keywords= QML, QDeclarativeItem
 +
|language= <!-- Language category code for non-English topics - e.g. Lang-Chinese -->
 +
|translated-by= <!-- [[User:XXXX]] -->
 +
|translated-from-title= <!-- Title only -->
 +
|translated-from-id= <!-- Id of translated revision -->
 +
|review-by= <!-- After re-review: [[User:username]] -->
 +
|review-timestamp= <!-- After re-review: YYYYMMDD -->
 +
|update-by= <!-- After significant update: [[User:username]]-->
 +
|update-timestamp= <!-- After significant update: YYYYMMDD -->
 +
|creationdate= 20100617
 +
|author= [[User:Kratsan]]
 +
<!-- The following are not in current metadata -->
 +
|id= CS001627
 
}}
 
}}
  
 
==Overview==
 
==Overview==
  
This snippet shows how to create a custom QML element with Qt. Sometimes the elements provided by the Declarative module are not enough and new element must be implemented.
+
Sometimes the elements provided by the Declarative module are not enough and a new element must be implemented.
  
In the example below we create a <tt>Line</tt> element which simply draws a line. The coordinates of the lines beginning and end must be given. It is also possible to adjust the color, pen width and smoothing of line.
+
In the following example we create a {{Icode|Line}} element which simply draws a line. The coordinates of the beginning and end of the line must be given. It is also possible to adjust the color, pen width, and smoothing of the line.
  
 
==Preconditions==
 
==Preconditions==
Line 34: Line 51:
 
</code>
 
</code>
  
The new element is derived from <tt>QDeclarativeItem</tt> which gives us the functionality of QML <tt>Item</tt> such as <tt>x, y, width</tt> and <tt>height</tt>. We declare the new properties with macro <tt>Q_PROPERTY</tt> and tell which methods to use when properties are read and updated. The <tt>paint</tt> method handles the painting of our custom element. Finally, at the end of header, we declare class <tt>Line</tt> as QML type.
+
The new element is derived from {{Icode|QDeclarativeItem}} which gives us the functionality of a QML {{Icode|Item}}, such as {{Icode|x, y, width}} and {{Icode|height}}. We declare the new properties with the macro {{Icode|Q_PROPERTY}} and state which methods to use when properties are read and updated. The {{Icode|NOTIFY}} feature is used to notify bound properties to update their value when the property here changes. The {{Icode|paint}} method handles the painting of our custom element. Finally, at the end of the header, we declare the class {{Icode|Line}} as a QML type.
  
 
'''line.h'''
 
'''line.h'''
  
<code cpp>
+
<code cpp-qt>
 
#ifndef LINE_H
 
#ifndef LINE_H
 
#define LINE_H
 
#define LINE_H
Line 48: Line 65:
 
{
 
{
 
     Q_OBJECT
 
     Q_OBJECT
     Q_PROPERTY(int x1 READ x1 WRITE setX1);
+
     Q_PROPERTY(int x1 READ x1 WRITE setX1 NOTIFY x1Changed);
     Q_PROPERTY(int y1 READ y1 WRITE setY1);
+
     Q_PROPERTY(int y1 READ y1 WRITE setY1 NOTIFY y1Changed);
     Q_PROPERTY(int x2 READ x2 WRITE setX2);
+
     Q_PROPERTY(int x2 READ x2 WRITE setX2 NOTIFY x2Changed);
     Q_PROPERTY(int y2 READ y2 WRITE setY2);
+
     Q_PROPERTY(int y2 READ y2 WRITE setY2 NOTIFY y2Changed);
     Q_PROPERTY(QColor color READ color WRITE setColor);
+
     Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged);
     Q_PROPERTY(int penWidth READ penWidth WRITE setPenWidth);
+
     Q_PROPERTY(int penWidth READ penWidth WRITE setPenWidth NOTIFY penWidthChanged);
  
 
public:
 
public:
 
     Line(QDeclarativeItem *parent = 0) :
 
     Line(QDeclarativeItem *parent = 0) :
             QDeclarativeItem(parent), m_x1(0), m_y1(0), m_x2(0), m_y2(0), m_color(Qt::black), m_penWidth(1)
+
             QDeclarativeItem(parent), m_x1(0), m_y1(0), m_x2(0), m_y2(0),
 +
            m_color(Qt::black), m_penWidth(1)
 
     {
 
     {
 
         // Important, otherwise the paint method is never called
 
         // Important, otherwise the paint method is never called
Line 72: Line 90:
 
         }
 
         }
  
         painter->drawLine(m_x1, m_y1, m_x2, m_y2);
+
        int x = qMin(m_x1, m_x2) - m_penWidth/2;
 +
        int y = qMin(m_y1, m_y2) - m_penWidth/2;
 +
 
 +
         painter->drawLine(m_x1 - x, m_y1 - y, m_x2 - x, m_y2 - y);
 
     }
 
     }
  
Line 84: Line 105:
  
 
     // Set methods
 
     // Set methods
     void setX1(int x1) { m_x1 = x1; update(); }
+
     void setX1(int x1) {
     void setY1(int y1) { m_y1 = y1; update(); }
+
        if(m_x1 == x1) return;
     void setX2(int x2) { m_x2 = x2; update(); }
+
        m_x1 = x1;
     void setY2(int y2) { m_y2 = y2; update(); }
+
        updateSize();
     void setColor(const QColor &color) { m_color = color; }
+
        emit x1Changed();
     void setPenWidth(int newWidth) { m_penWidth = newWidth; }
+
        update();
 +
    }
 +
 
 +
     void setY1(int y1) {
 +
        if(m_y1 == y1) return;
 +
        m_y1 = y1;
 +
        updateSize();
 +
        emit y1Changed();
 +
        update();
 +
    }
 +
 
 +
     void setX2(int x2) {
 +
        if(m_x2 == x2) return;
 +
        m_x2 = x2;
 +
        updateSize();
 +
        emit x2Changed();
 +
        update();
 +
    }
 +
 
 +
     void setY2(int y2) {
 +
        if(m_y2 == y2) return;
 +
        m_y2 = y2;
 +
        updateSize();
 +
        emit x2Changed();
 +
        update();
 +
    }
 +
 
 +
     void setColor(const QColor &color) {
 +
        if(m_color == color) return;
 +
        m_color = color;
 +
        emit colorChanged();
 +
        update();
 +
    }
 +
 
 +
     void setPenWidth(int newWidth) {
 +
        if(m_penWidth == newWidth) return;
 +
        m_penWidth = newWidth;
 +
        updateSize();
 +
        emit penWidthChanged();
 +
        update();
 +
    }
 +
 
 +
signals:
 +
    void x1Changed();
 +
    void y1Changed();
 +
    void x2Changed();
 +
    void y2Changed();
 +
    void colorChanged();
 +
    void penWidthChanged();
 +
 
 +
protected:
 +
    void updateSize() {
 +
        setX(qMin(m_x1, m_x2) - m_penWidth/2);
 +
        setY(qMin(m_y1, m_y2) - m_penWidth/2);
 +
        setWidth(qAbs(m_x2 - m_x1) + m_penWidth);
 +
        setHeight(qAbs(m_y2 - m_y1) + m_penWidth);
 +
    }
  
 
protected:
 
protected:
Line 103: Line 180:
  
 
#endif // LINE_H
 
#endif // LINE_H
 
 
</code>
 
</code>
  
In the <tt>main.cpp</tt> we register the C++ type <tt>Line</tt> in the QML system with the name <tt>Line</tt> to the library <tt>CustomComponents</tt> with version number 1.0.
+
In '''main.cpp''', we register the C++ type {{Icode|Line}} in the QML system with the name {{Icode|Line}} to the library {{Icode|CustomComponents}} with version number 1.0.
  
 
'''main.cpp'''
 
'''main.cpp'''
  
<code cpp>
+
<code cpp-qt>
 
#include "line.h"
 
#include "line.h"
 
#include <QApplication>
 
#include <QApplication>
Line 136: Line 212:
 
</code>
 
</code>
  
In the QML document we import the <tt>CustomComponents</tt> library which contains the <tt>Line</tt> element.
+
In the QML document, we import the {{Icode|CustomComponents}} library which contains the {{Icode|Line}} element.
  
 
'''ui.qml'''
 
'''ui.qml'''
  
<code cpp>
+
<code cpp-qt>
 
import CustomComponents 1.0
 
import CustomComponents 1.0
 
import Qt 4.7
 
import Qt 4.7
Line 151: Line 227:
 
     Line {
 
     Line {
 
         id: diagonalLine
 
         id: diagonalLine
 
        anchors.fill: parent
 
  
 
         Behavior on x1 { NumberAnimation { duration: 1000 } }
 
         Behavior on x1 { NumberAnimation { duration: 1000 } }
Line 171: Line 245:
 
             evenClick = !evenClick
 
             evenClick = !evenClick
 
         }
 
         }
 +
    }
 +
 +
    Text {
 +
        id: textX1Y1
 +
        anchors.left: parent.left; anchors.top: parent.top
 +
        text: "x1: " + diagonalLine.x1 + " y1: " + diagonalLine.y1
 +
    }
 +
 +
    Text {
 +
        anchors.left: parent.left; anchors.top: textX1Y1.bottom; anchors.topMargin: 10
 +
        text: "x2: " + diagonalLine.x2 + " y2: " + diagonalLine.y2
 
     }
 
     }
 
}
 
}
Line 177: Line 262:
 
===Postconditions===
 
===Postconditions===
  
The custom QML element <tt>Line</tt> was created with Qt by deriving the class <tt>QDeclarativeItem</tt>, adding few new properties and overwriting the paint method. The Qt class was registered as QML type and it was then used in Qt Quick application.
+
The custom QML element {{Icode|Line}} was created with Qt by deriving the class {{Icode|QDeclarativeItem}}, adding a few new properties and overwriting the paint method. The Qt class was registered as QML type and then used in a Qt Quick application.
 
+
[[Category:Qt]][[Category:Code Examples]][[Category:Code Snippet]]
+

Latest revision as of 09:09, 17 October 2012

This snippet shows how to create a custom QML element.

Article Metadata
Tested with
Devices(s): Nokia 900
Compatibility
Platform(s): S60 5th Edition
Maemo
Symbian
Article
Keywords: QML, QDeclarativeItem
Created: kratsan (17 Jun 2010)
Last edited: hamishwillee (17 Oct 2012)

Contents

[edit] Overview

Sometimes the elements provided by the Declarative module are not enough and a new element must be implemented.

In the following example we create a Line element which simply draws a line. The coordinates of the beginning and end of the line must be given. It is also possible to adjust the color, pen width, and smoothing of the line.

[edit] Preconditions

  • Qt 4.7 or higher is installed on your platform.

[edit] Source

qmlapp.pro

QT       += core gui declarative
 
TARGET = qmlapp
TEMPLATE = app
 
SOURCES += main.cpp
HEADERS += line.h
OTHER_FILES += ui.qml

The new element is derived from QDeclarativeItem which gives us the functionality of a QML Item, such as x, y, width and height. We declare the new properties with the macro Q_PROPERTY and state which methods to use when properties are read and updated. The NOTIFY feature is used to notify bound properties to update their value when the property here changes. The paint method handles the painting of our custom element. Finally, at the end of the header, we declare the class Line as a QML type.

line.h

#ifndef LINE_H
#define LINE_H
 
#include <QDeclarativeItem>
#include <QPainter>
 
class Line : public QDeclarativeItem
{
Q_OBJECT
Q_PROPERTY(int x1 READ x1 WRITE setX1 NOTIFY x1Changed);
Q_PROPERTY(int y1 READ y1 WRITE setY1 NOTIFY y1Changed);
Q_PROPERTY(int x2 READ x2 WRITE setX2 NOTIFY x2Changed);
Q_PROPERTY(int y2 READ y2 WRITE setY2 NOTIFY y2Changed);
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged);
Q_PROPERTY(int penWidth READ penWidth WRITE setPenWidth NOTIFY penWidthChanged);
 
public:
Line(QDeclarativeItem *parent = 0) :
QDeclarativeItem(parent), m_x1(0), m_y1(0), m_x2(0), m_y2(0),
m_color(Qt::black), m_penWidth(1)
{
// Important, otherwise the paint method is never called
setFlag(QGraphicsItem::ItemHasNoContents, false);
}
 
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QPen pen(m_color, m_penWidth);
painter->setPen(pen);
 
if(smooth() == true) {
painter->setRenderHint(QPainter::Antialiasing, true);
}
 
int x = qMin(m_x1, m_x2) - m_penWidth/2;
int y = qMin(m_y1, m_y2) - m_penWidth/2;
 
painter->drawLine(m_x1 - x, m_y1 - y, m_x2 - x, m_y2 - y);
}
 
// Get methods
int x1() const { return m_x1; }
int y1() const { return m_y1; }
int x2() const { return m_x2; }
int y2() const { return m_y2; }
QColor color() const { return m_color; }
int penWidth() const { return m_penWidth; }
 
// Set methods
void setX1(int x1) {
if(m_x1 == x1) return;
m_x1 = x1;
updateSize();
emit x1Changed();
update();
}
 
void setY1(int y1) {
if(m_y1 == y1) return;
m_y1 = y1;
updateSize();
emit y1Changed();
update();
}
 
void setX2(int x2) {
if(m_x2 == x2) return;
m_x2 = x2;
updateSize();
emit x2Changed();
update();
}
 
void setY2(int y2) {
if(m_y2 == y2) return;
m_y2 = y2;
updateSize();
emit x2Changed();
update();
}
 
void setColor(const QColor &color) {
if(m_color == color) return;
m_color = color;
emit colorChanged();
update();
}
 
void setPenWidth(int newWidth) {
if(m_penWidth == newWidth) return;
m_penWidth = newWidth;
updateSize();
emit penWidthChanged();
update();
}
 
signals:
void x1Changed();
void y1Changed();
void x2Changed();
void y2Changed();
void colorChanged();
void penWidthChanged();
 
protected:
void updateSize() {
setX(qMin(m_x1, m_x2) - m_penWidth/2);
setY(qMin(m_y1, m_y2) - m_penWidth/2);
setWidth(qAbs(m_x2 - m_x1) + m_penWidth);
setHeight(qAbs(m_y2 - m_y1) + m_penWidth);
}
 
protected:
int m_x1;
int m_y1;
int m_x2;
int m_y2;
QColor m_color;
int m_penWidth;
};
 
QML_DECLARE_TYPE(Line)
 
#endif // LINE_H

In main.cpp, we register the C++ type Line in the QML system with the name Line to the library CustomComponents with version number 1.0.

main.cpp

#include "line.h"
#include <QApplication>
#include <QDeclarativeView>
 
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
 
qmlRegisterType<Line>("CustomComponents", 1, 0, "Line");
 
QDeclarativeView view;
view.setSource(QUrl("./ui.qml"));
view.setResizeMode(QDeclarativeView::SizeRootObjectToView);
 
#if defined(Q_WS_S60) || defined(Q_WS_MAEMO)
view.showMaximized();
#else
view.setGeometry(100,100, 800, 480);
view.show();
#endif
return a.exec();
}

In the QML document, we import the CustomComponents library which contains the Line element.

ui.qml

import CustomComponents 1.0
import Qt 4.7
 
Rectangle {
property bool evenClick : false
 
anchors.fill: parent; color: "lightsteelblue"
 
Line {
id: diagonalLine
 
Behavior on x1 { NumberAnimation { duration: 1000 } }
Behavior on y1 { NumberAnimation { duration: 1000 } }
Behavior on x2 { NumberAnimation { duration: 1000 } }
Behavior on y2 { NumberAnimation { duration: 1000 } }
 
x1: parent.x + 20; y1: parent.height / 2
x2: parent.width - 20; y2: parent.height / 2
color: "tomato"; penWidth: 3; smooth: true
}
 
MouseArea {
anchors.fill: parent
onClicked: {
if(evenClick) { diagonalLine.x1 = mouseX; diagonalLine.y1 = mouseY }
else { diagonalLine.x2 = mouseX; diagonalLine.y2 = mouseY }
evenClick = !evenClick
}
}
 
Text {
id: textX1Y1
anchors.left: parent.left; anchors.top: parent.top
text: "x1: " + diagonalLine.x1 + " y1: " + diagonalLine.y1
}
 
Text {
anchors.left: parent.left; anchors.top: textX1Y1.bottom; anchors.topMargin: 10
text: "x2: " + diagonalLine.x2 + " y2: " + diagonalLine.y2
}
}

[edit] Postconditions

The custom QML element Line was created with Qt by deriving the class QDeclarativeItem, adding a few new properties and overwriting the paint method. The Qt class was registered as QML type and then used in a Qt Quick application.

This page was last modified on 17 October 2012, at 09:09.
607 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×