한국어
Qt
 

Qml과 C++로 구현하는 GUI어플리케이션, 두번째 글로 C++로 작성한 클래스를 QML에서 생성하고 사용하는 방법이다.

 

C++과 QML 을 통합하는 방법중 QQmlContext의 setContextProperty 라는 메서드를 사용하면 C++ 코드에서 이미 생성된 객체를 QML 컨텍스트에 등록하여 QML에서 C++ 클래스의 메서드 및 프로퍼티에 접근할 수 있음을 기억할 것이다. 이 경우 QQmlContext 에서 객체의 소유권을 갖지 않기 때문에 객체가 더 이상 사용되지 않을 때(프로그램 종료)에 객체를 파괴 해줘야 한다.

반면 qmlRegisterType 템플릿 함수는 QML 시스템에 C++ 로 작성된 유형을 등록하고 QML컨텍스트에서 직접 생성한다. 

 

File을 읽고 쓰는 간단한 C++클래스를 작성하고 qmlRegisterType 함수를 이용해 이 클래스를 등록하여 최종적으로 QML에서 파일을 읽고 쓰는 예제를 작성해 본다.

 

FileIO 클래스의 헤더 파일이다. FileIO 구현은 간단하다. read, write 메서스와 source, text 프로퍼티 가 있는 간단한 클래스다.

fileio.h

#include <QtCore>

class FileIO : public QObject
{
    Q_OBJECT
    Q_DISABLE_COPY(FileIO)
    Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
    Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
public:
    FileIO(QObject *parent = nullptr);
    ~FileIO() override;

    Q_INVOKABLE void read();
    Q_INVOKABLE void write();
    QUrl source() const;
    QString text() const;

public slots:
    void setSource(QUrl source);
    void setText(QString text);

signals:
    void sourceChanged(QUrl arg);
    void textChanged(QString arg);

private:
    QUrl m_source;
    QString m_text;
};

 

read 메서드는 읽기 모드에서 파일을 열고 텍스트 스트림을 사용하여 데이터를 읽는다. 텍스트가 변경되면 emit textChanged(m_text)를 사용하여 변경 사항을 외부에 알려야한다.

void FileIO::read()
{
    if(m_source.isEmpty()) {
        return;
    }
    QFile file(m_source.toLocalFile());
    if(!file.exists()) {
        qWarning() << "Does not exits: " << m_source.toLocalFile();
        return;
    }
    if(file.open(QIODevice::ReadOnly)) {
        QTextStream stream(&file);
        m_text = stream.readAll();
        emit textChanged(m_text);
    }
}

 

write 메서드는 동일한 작업을 수행하지만 파일을 쓰기 모드로 열고 스트림을 사용하여 내용을 쓴다.

void FileIO::write()
{
    if(m_source.isEmpty()) {
        return;
    }
    QFile file(m_source.toLocalFile());
    if(file.open(QIODevice::WriteOnly)) {
        QTextStream stream(&file);
        stream << m_text;
    }
}

 

이제 qmlRegisterType 템플릿 함수를 호출하여 작성한 클래스를 QML 컨텍스트에 등록한다. 이때 네임스페이스 문자열( "net.makersweb.file"), 메이져 버전, 마이너 버전 번호, 그리고 QML 타입 이름을 지정한다.

#include "fileio.h"

...
qmlRegisterType<FileIO>("net.makersweb.file", 1, 0, "FileIO");
...

 

QML에서 등록된 유형을 사용하기위해 import net.makersweb.file 1.0 를 포함한다. 다음은 FileIO 를 사용하는 간단한 QML 코드이다.

main.qml

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import QtQuick.Dialogs 1.2

import net.makersweb.file 1.0

Window {
    id: window
    visible: true
    width: 640
    height: 480

    property FileIO backend: FileIO{}

    FileDialog{
        id: dialog

        onAccepted: {
            backend.setSource(window.title = dialog.fileUrl)
            backend.read()

            text.text = backend.text
        }
    }

    Column {
        anchors.fill: parent

        Row {
            id: buttons
            anchors.horizontalCenter: parent.horizontalCenter
            Button {
                id: open
                text: qsTr("Open")

                onClicked: {
                    dialog.open()
                }
            }
            Button {
                id: save
                text: qsTr("Save")
                onClicked: {
                    backend.text = text.text
                    backend.write()
                }
            }
        }

        ScrollView {
            id: view
            contentHeight: Window.height - buttons.height
            contentWidth: parent.width

            TextArea {
                id: text
                selectByMouse: true
            }
        }

    }
}

 

프로그램을 실행 후 Open 버튼을 클릭 후 텍스트 파일을 읽고, 써지는 것을 확인 할 수 있다.

fileio.png

 

본문에서 사용된 FileIO 클래스 출처: http://qmlbook.github.io/ch18-extensions/extensions.html#using-fileio