2014-03-26 35 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造型。