2014-03-26 54 views
2

我目前正在嘗試用Qt 5.2和Qt Quick 2開發一個相當重要的應用程序(類似於操作系統);我想要做的是在C++中實現所有的邏輯,由於QML聲明瞭UI。在這一點上,這似乎是合乎邏輯和解決問題的方法。然而,我不知道如何做到這一點乾淨的方式..我讀了很多文檔,教程和示例,但沒有這麼大......C++/QML體系結構 - 一種在QML中重現C++結構的方法?

讓我們來解釋一下我想作爲一個體繫結構;假設我們有一個Scene對象,其中可能包含未定義數量的Application對象。我想要的是定義CPP中的邏輯(我如何從XML加載應用程序,場景應該具有哪些屬性,...),然後用QML顯示場景。此外,我們必須注意場景和應用程序元素應該重新用作組件;所以,這裏有一個基本的想法:我想用QML中的文件定義每個對象通用的圖形樣式(擴展CPP類型)。

例如,我可以創建一個文件與此內容:

Application { 
    Rectangle { ... } 
} 

說,應用程序應該representated爲矩形;那麼當我創建一個具有Application列表的Scene對象(或一個唯一的應用程序,首先)時,我希望它自動顯示(因爲這是Scene對象的一個​​屬性)。它甚至有可能嗎?我怎樣才能做到這一點 ?

我認爲,如果我擴展C++對象併爲它聲明一些圖形元素,它將是自動的..但實際上它看起來不是這樣!

也許還有另外一種方法?

感謝

+0

什麼問題? 「它看起來不像那個」是什麼意思?我們需要具體細節。 – Mitch

回答

1

我不喜歡這個問題太多,因爲它是不是真的問什麼特別。 Qt文檔非常全面,所以當人們說他們閱讀過文檔,教程和示例,但仍然沒有找到他們想要的東西時,我經常發現它很奇怪。但是,我認爲我理解你所問的要點,並認爲答案可能對某些人有用,所以我會試着回答它。

的main.cpp

#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" 

I表示兩個類作爲子類QQuickItemSceneItem由許多ApplicationItem實例組成,它們通過調用startApp()添加到場景中。此插槽將QML文件的路徑作爲其參數。該文件可以通過網絡或本地文件加載,因此我們考慮了同步和異步加載的可能性。

QML文件應描述應用程序的外觀,場景預計其根類型爲ApplicationItem。作爲一個例子,這裏的MySweetApp.qml

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()槽封閉自己。

這裏的主。QML

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") 
    } 
} 

這就是SceneItem聲明,用一個簡單的界面啓動我的甜蜜應用程序的多個實例一起(這是一個非常有用的應用程序)。

我相信這是最合適的方式做你的要求。它避免了在C++中設置列表ApplicationItems的麻煩,這些列表暴露於QML(實際上並不困難,但這是文檔可能更明顯的一個區域),並允許操作系統的用戶自由地顯示應用程序。如果你想更加嚴格的樣式,我會建議看看如何Qt Quick Controls造型。