2012년 6월 16일 토요일

[QML/Qt] Lecture 02. Property를 등록하자.

Lecture 01에서 만든 환경에서, Class인 MyObject를 만들고, 거기에 Property 인 name을 등록을 하자. 그리고, 내용을 MyObject에서 이름을 가져와서, QML에서 표시를 해 보자.

1. QObject에서 상속받은 MyObject 클래스를 만들자.
 Menu > File > New File or Project 를 선택하고, C++인 Class를 선택하자.
 이름은 MyObject로 하고, QObject에서 상속을 받도록 만들자.
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <QObject>
class MyObject : public QObject
{
  Q_OBJECT
public:
  explicit MyObject(QObject *parent = 0);

signals:
public slots:

};
#endif // MYOBJECT_H

: 기본적으로 클래스를 만들면 위와 같이 기본 클래스가 만들어진다.

2. 만든 MyObject에 name을 추가하고,  Q_PROPERTY로 등록하자.
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <QObject>
class MyObject : public QObject
{
  Q_OBJECT
public:
  explicit MyObject(QString n, QObject *parent = 0);
  Q_PROPERTY (QString myName READ getName WRITE setName NOTIFY nameChanged)
  QString getName(void) { return name; }
  void    setName(QString n) { name = n; nameChanged();}
 
signals:
  void nameChanged();
 
public slots:
private:
  QString name;
 
};
#endif // MYOBJECT_H

: 위에 녹색으로 배경이 된 부분이 추가된 부분이 된다.
QML에서 myName이라는 프로퍼티이름으로 name을 읽을 수 있는데,
text: myObject.myName 이라고 쓰면, getName()이 호출되어서, 값을 넘겨주게 되고,
myObjectt.myName = “david” 라고 하면, setName(..)이 호출되어 값을 설정하게 된다.
설정될 때, nameChange() 시그널을 발생시켜서, QML에서 바인딩 된 다른 곳에서도 데이터가 변경이 된다. 이건 Property Binding과 Signa/Slot을 설명하고 나면 자세하게 알게 된다.
여기서는 nameChange라는 함수를 통해서, QML에서 자동으로 값을 읽어가게 된다는 것을 알고 가자.

3. Main에서 MyObject의 인스턴스를 만들고, view의 rootContext에서 이것을 등록하자.
#include <QApplication>
#include <QDeclarativeContext>
#include <QDeclarativeView>
#include "myobject.h"
Q_DECL_EXPORT int main(int argc, char *argv[])
{
  QApplication app(argc, argv);
  QDeclarativeView view;
  MyObject myObject("David Bae");
  view.rootContext()->setContextProperty("myObject", myObject);
  view.setSource(QUrl("../QLecture/qml/QLecture/main.qml"));
  view.show();
  return app.exec();
}

main함수에서 “myObject”로 view의 rootContext에 등록을 했으므로, QML에서 “myObject”라는 이름을 사용하면, 다른 QML콤포넌트의 id에 접근하듯이 등록된 클래스에 접근을 할 수 있게 된다.
view의 setSource를 통해서 QML파일을 등록하기 전에, rootContext에 “myObject”라는 이름으로 myObject를 등록을 하면, setSource에서 등록되는 QML에서는 myObject라는 이름으로 사용할 수 있게 된다.


4. QML에서 등록된 MyObject를 읽어와서, 내부의 Name을 읽어서 화면에 표시를 하자.
QML에서 myName을 읽으면, MyObject의 getName이 호출되고, myName에 이름을 넣으면, setName이 되는 것이다.

main.qml
Rectangle {
  width: 360
  height: 360
  Text {
      text: qsTr("Hello World2")
      anchors.centerIn: parent
  }
  Text {
      x:50; y:50
      text:myObject.myName;
  }
}


그럼, Main.qml에서 사용자가 마우스 클릭으로 이름을 바꾸고, 바꾼 내용이 화면이 표시가 되는지 확인해 보자.

QML에 버튼 비슷한 것을 만들고, click이 되면, 이름을 “Jamie”로 바꿔보자.
// import QtQuick 1.0 // to target S60 5th Edition or Maemo 5
import QtQuick 1.1
Rectangle {
  width: 360
  height: 360
  Text {
      text: qsTr("Hello World2")
      anchors.centerIn: parent
  }
  Text {
      x:50; y:50
      text:myObject.myName;
      color:"green"
  }
  Rectangle{
      x:150;y:50
      width:100;
      height:15
      color:"steelBlue"
      Text{
          anchors.fill:parent;
          verticalAlignment: Text.AlignVCenter;
          horizontalAlignment: Text.AlignHCenter;
          text: "Change"
      }
      MouseArea{
          anchors.fill: parent;
          onClicked: {
              myObject.myName = "Jamie";
          }
      }
  }
}

실제 동작하는 화면을 보면, Change를 클릭하면, David Bae라는 이름이 Jamie로 바뀌고, 화면에 자동으로 갱신이 된다.


좀더 자세하게 Q_PROPERTY를 설정할 때 들어가는 내용을 알아봅시다.
(참조 사이트: http://doc.qt.nokia.com/4.7/qobject.html#Q_PROPERTY )
Q_PROPERTY(type name
           READ getFunction
           [WRITE setFunction]
           [RESET resetFunction]
           [NOTIFY notifySignal]
           [DESIGNABLE bool]
           [SCRIPTABLE bool]
           [STORED bool]
           [USER bool]
           [CONSTANT]
           [FINAL])

선언
- 일반적인 변수와 동일하게 동작함.
- 추가적으로 Meta-Object System을 통해서 접근이 가능한 Property가 됨.
- READ : reading the property value
- WRITE: setting the property value
- RESET: default value로 돌아올 때
- NOTIFY: 변경을 알리는 Signal을 명시
- DESIGNABLE: GUI design tool에서 보이도록
- SCRIPTABLE: script engine에서 접근 가능, 디폴트로 true임
STORED: property가 자기것으로 가지고 있거나, 혹은 다른 Property의 Value에 따라 변하는지를 표시한다. 일반적으로 True, minimumWidth()의 경우, minimumSize()의 값이 되므로 자기것을 가지고 있을 필요 없다는 것임.
- USER: 사용자가 보고, 변경할 수 있는 것인지를 표시하는 것. (??)
- CONSTANT: const이므로 READ함수가 같은 값을 return한다.
- FINAL: 상속받은 class에서 overridden을 하지 못한다는 의미.