MokaT
MokaT

Reputation: 1416

QML Dynamic insertions of components in loader from C++

I've fully edit my question since I've made some progress, and the first one was unclear.

I use Qt 4.8, with QtQuick 1.0.

I have a page where I need to keep the top and the bottom margin. So I've defined a Main.qml like that :

Item  {
    id: salesWindow
    width: 800
    height: 600

[...] //Properties def

TopBar {[...]}

CloseButton{[...]}

Rectangle {[...]}

//I want to load qml file in this loader. The QML file loaded use some of the Main.qml properties
Loader {
    id: appPlaceHolder
    objectName: "loader"
    anchors.centerIn: parent
 }

Rectangle {[...]}

BotBar {[...]}

}

If I put a qml file into the loader sourceComponent, it works. Now I want to do it with C++, and well designed. I've subclass QDeclarativeComponent in SalesAppDisplay.h

class SalesAppDisplay : public IDisplayScreen
{
  Q_OBJECT

  static const std::string QML_FILENAME;
  static const std::string QML_DIR_PATH;
public:
  SalesAppDisplay(DisplayContext& context, QDeclarativeEngine& engine, QObject* parent = 0);

  ~SalesAppDisplay();

  void doScreenInit();

  const std::string getQmlFilename() const;    
};

class IDisplayScreen : public QDeclarativeComponent
{
  Q_OBJECT
[...]
}

and the Ctor in charge of component instanciation :

IDisplayScreen::IDisplayScreen(DisplayContext& context, QDeclarativeEngine& engine, std::string     qmlFilepath, QObject* parent)
: QDeclarativeComponent(&engine, QString(qmlFilepath.c_str()), parent)

Instead of loading a qml file in the loader by changing the source, I want to insert my component into the QML from main.cpp :

  m_view.setSource(QUrl::fromLocalFile("../displaymanager/rsrc/qml/Main.qml"));

  QObject* mainObj = m_view.rootObject();
  [ .. Set file property ]

  //this is the component subclass instantiation (made by factory)
  m_currentScreen = displaymanager::createDisplayScreen(IDisplayScreen::SALESAPP, *(m_context), *(m_view.engine()), mainObj);

  QDeclarativeItem* saleAppObj = qobject_cast<QDeclarativeItem*>(m_currentScreen->create(m_view->rootContext()));
  saleAppObj->setParentItem(qobject_cast<QDeclarativeItem*>(mainObj));
  [ .. Set file property ]

  //I can find my loader without any problems
  QDeclarativeItem *loader = mainObj->findChild<QDeclarativeItem*>("loader");
  /* I don't know what to do here for making it works */

  m_view.show();
  m_qApp.exec();

I've tried loader->setProperty("sourceComponent", qobject_cast<QVariant>(saleAppObj));, and some other tricks like that without any results.

I have errors from my saleApp.qml saying that he don't know Main.qml properties that i used in it (he is clearly load at the Components instanciation). And despite that main.qml is perfectly loaded, nothing from SaleApp.qml appears.

Upvotes: 1

Views: 2456

Answers (1)

MokaT
MokaT

Reputation: 1416

I have made it work.

There is the screen handling function :

void QtDisplayManager::switchScreen(int screenID)
{
  if(m_currentScreen)
  {
    m_currentScreen->destroyItem();
  }

  //App screen creation
  m_currentScreen = displaymanager::createDisplayScreen(screenID, m_context, *m_engine, m_mainObj);

  //Get App placehoder 
  QDeclarativeItem* loaderItem = m_mainObj->findChild<QDeclarativeItem*>("loader");

  //Put app in placeholder
  if(loaderItem)
  {
    m_currentScreen->getItem()->setParentItem(loaderItem);
    m_engine->clearComponentCache();
    m_context.setcurrentDisplayID(screenID);
  }
}

destroyItem() is a function I've add to delete item pointer without deleting the whole component, just because I had a problem where the component was not removed from the view when a new was added.

SalesApp.qml have no reference on the MainWindow.qml, so I have add two wrapper :

m_view.rootContext()->setContextProperty("managerWrapper", this);
m_view.rootContext()->setContextProperty("appWrapper", m_currentScreen);  

Works perfectly, design is good, code is sweet.

Upvotes: 1

Related Questions