2014-03-26 3 views
2

저는 현재 Qt 5.2 및 Qt Quick 2에서 매우 중요한 응용 프로그램 (OS와 비슷한)을 개발하려고합니다. 내가하고 싶은 것은 C++로 모든 로직을 구현하는 것입니다. UI는 QML 덕분에 선언됩니다. 이 시점에서, 그것은 논리적이며 주위를 둘러 보는 길로 보입니다. 그러나 나는 그것을 깨끗하게하는 방법을 생각할 수 없다. 나는 많은 문서, 튜토리얼 및 예제를 읽었지만 너무 큰 것은 아무것도 없다 ...C++/QML 아키텍처 - QML에서 C++ 구조를 재현하는 방법?

내가 건축물에 넣고 싶은 것을 조금 설명해 보자. ; 정의되지 않은 수의 Application 개체를 포함 할 수있는 Scene 개체가 있다고 가정 해 보겠습니다. 내가 원하는 것은 CPP에서 논리를 정의하는 것입니다 (XML에서 응용 프로그램을로드하는 방법, 장면을 속성으로 가져 오는 방법 ...). 그런 다음 QML로 장면을 표시합니다. 또한 Scene 및 Application 요소를 구성 요소로 다시 사용해야 함을 알아야합니다. 여기에 기본적인 아이디어가 있습니다. QML (CPP 유형 확장)의 파일로 각 객체에 공통적 인 그래픽 스타일을 정의하고 싶습니다.

예를 들어,이 내용으로 파일을 만들 수 있습니다

Application { 
    Rectangle { ... } 
} 

응용 프로그램이 사각형으로 representated해야한다고 말하는; 그런 다음 Application (또는 고유 한 Application) 목록이있는 Scene 객체를 만들면 자동으로 표시되기를 바랍니다 (Scene 객체의 속성이므로). 심지어 가능할까요? 어떻게해야합니까?

나는 C++ 객체를 확장하고 그래픽 요소를 선언하면 자동으로 처리 될 것이라고 생각했다. 그러나 실제로 그렇게 보이지 않는다!

어쩌면 다른 방법이 있을까요? 정말 특히 아무것도 요구하지 것 같이 내가 너무 많은이 질문을 좋아하지 않는

+0

무엇이 문제입니까? "그게 그렇게 보이지 않는다"는 것은 무엇을 의미합니까? 우리는 세부 사항이 필요합니다. – Mitch

답변

1

감사합니다. Qt 문서는 매우 포괄적이어서, 사람들이 문서, 튜토리얼 및 예제를 읽었다 고 말하면서 종종 찾고있는 것을 발견하지 못했다고 종종 이상하게 생각합니다. 그러나, 나는 당신이 요구하는 것의 요지를 이해하고 그 대답이 어떤 사람들에게 유용 할 수 있다고 생각한다. 그래서 나는 그것에 대답하려고 노력할 것이다.

#include <QtGui/QGuiApplication> 
#include <QtQml> 
#include <QQuickItem> 
#include "qtquick2applicationviewer.h" 

class ApplicationItem : public QQuickItem 
{ 
    Q_OBJECT 
    Q_PROPERTY(QString title MEMBER mTitle NOTIFY titleChanged) 
public: 
    ApplicationItem(QQuickItem *parent = 0) : QQuickItem(parent) { 
    } 

public slots: 
    void close() { 
     emit closed(this); 
    } 
signals: 
    void titleChanged(QString title); 
    void closed(ApplicationItem *app); 
private: 
    QString mTitle; 
}; 

class SceneItem : public QQuickItem 
{ 
    Q_OBJECT 
public: 
    SceneItem() { 
    } 

public slots: 
    void startApp(const QString &qmlFile) { 
     QQmlComponent *component = new QQmlComponent(qmlEngine(this), QUrl(qmlFile)); 
     if (component->isLoading()) { 
      QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)), 
       this, SLOT(componentStatusChanged())); 
     } else { 
      // The component was synchronously loaded, but it may have errors. 
      if (component->isError()) { 
       qWarning() << "Failed to start application:" << component->errorString(); 
      } else { 
       addApp(component); 
      } 
     } 
    } 

    void componentStatusChanged(QQmlComponent::Status status) { 
     QQmlComponent *component = qobject_cast<QQmlComponent*>(sender()); 
     if (status == QQmlComponent::Ready) { 
      addApp(component); 
     } else if (status == QQmlComponent::Error) { 
      qWarning() << "Failed to start application:" << component->errorString(); 
     } 
    } 

    void appClosed(ApplicationItem *app) { 
     int appIndex = mApplications.indexOf(app); 
     if (appIndex != -1) { 
      mApplications.removeAt(appIndex); 
      app->deleteLater(); 
     } 
    } 
private: 
    void addApp(QQmlComponent *component) { 
     ApplicationItem *appItem = qobject_cast<ApplicationItem*>(component->create()); 
     appItem->setParentItem(this); 

     connect(appItem, SIGNAL(closed(ApplicationItem*)), this, SLOT(appClosed(ApplicationItem*))); 

     mApplications.append(appItem); 
     delete component; 
    } 

    QList<ApplicationItem*> mApplications; 
}; 

int main(int argc, char *argv[]) 
{ 
    QGuiApplication app(argc, argv); 

    QtQuick2ApplicationViewer viewer; 
    qmlRegisterType<ApplicationItem>("Test", 1, 0, "ApplicationItem"); 
    qmlRegisterType<SceneItem>("Test", 1, 0, "SceneItem"); 
    viewer.setMainQmlFile(QStringLiteral("qml/quick/main.qml")); 
    viewer.showExpanded(); 

    return app.exec(); 
} 

#include "main.moc" 

MAIN.CPP 나는 QQuickItem 서브 클래스로 두 클래스를 표현. SceneItem은 많은 ApplicationItem 인스턴스로 구성되며 startApp()을 호출하여 장면에 추가됩니다. 이 슬롯은 인수로 QML 파일의 경로를 사용합니다. 이 파일은 네트워크 또는 로컬 파일을 통해로드 될 수 있으므로 동기 및 비동기 로딩의 가능성을 고려합니다.

QML 파일은 응용 프로그램의 시각적 모양을 나타내야하며 장면의 루트 유형은 ApplicationItem입니다.

import QtQuick 2.0 
import QtQuick.Controls 1.0 
import Test 1.0 

ApplicationItem { 
    id: someAppStyle 
    title: "My Sweet App" 
    width: 100 
    height: 100 

    MouseArea { 
     anchors.fill: parent 
     drag.target: parent 
    } 

    Rectangle { 
     radius: 4 
     color: "lightblue" 
     anchors.fill: parent 

     Text { 
      anchors.left: parent.left 
      anchors.right: closeButton.right 
      anchors.leftMargin: 4 
      anchors.top: parent.top 
      anchors.topMargin: 4 
      text: someAppStyle.title 
     } 

     Button { 
      id: closeButton 
      anchors.right: parent.right 
      anchors.rightMargin: 4 
      anchors.top: parent.top 
      anchors.topMargin: 2 
      onClicked: close() 
      text: "x" 
      width: 20 
      height: width 
     } 
    } 
} 

응용 프로그램 ApplicationItem에 선언 된 close() 슬롯을 호출하여 자신을 닫을 수 있습니다 : 예를 들어, 여기 MySweetApp.qml입니다.

여기에 메인이 있습니다.QML :

SceneItem 내 달콤한 응용 프로그램의 여러 인스턴스를 시작하는 간단한 인터페이스와 함께 선언 된 곳입니다
import QtQuick 2.0 
import QtQuick.Controls 1.0 
import Test 1.0 

SceneItem { 
    id: scene 
    width: 360 
    height: 360 

    Button { 
     anchors.horizontalCenter: parent.horizontalCenter 
     anchors.bottom: parent.bottom 
     text: "Launch app" 

     onClicked: scene.startApp("qml/quick/MySweetApp.qml") 
    } 
} 

은 (그것은 매우 유용한 응용 프로그램입니다).

나는 이것이 당신이 요구하는 것을하는 가장 적절한 방법이라고 생각합니다. QML에 노출되어있는 C++에서 ApplicationItems의 목록을 설정하는 번거 로움을 피할 수 있습니다 (사실은 그렇게 어렵지는 않지만 문서가 더 분명해질 수있는 영역 중 하나입니다). 그리고 OS 사용자는 응용 프로그램의 표시 방법을 자유롭게 할 수 있습니다 . 스타일링이 더 엄격 해지고 싶다면 Qt Quick Controls 스타일 지정 방법을 살펴 보는 것이 좋습니다.