[SOLVED] Dynamic C++ objects in QML



  • Hello I was wondering if there were a way to dynamically pass a C++ object to QML for use outside of a connections element (say in a state). Currently I have a qml file animating a singular button.

    window.h
    @class Window : public QWidget
    {
    Q_OBJECT
    Q_PROPERTY(int viewHeight READ viewHeight SCRIPTABLE true NOTIFY rebindViewSize)
    Q_PROPERTY(int viewWidth READ viewWidth SCRIPTABLE true NOTIFY rebindViewSize)

    public:
    explicit Window(QWidget *parent = 0);
    ~Window();

    Q_INVOKABLE AnimatedButton* m_button;
    

    public slots:
    Q_INVOKABLE void setTitle(QString m_title) { setWindowTitle(m_title); }

    protected slots:
    virtual void resizeEvent(QResizeEvent event);
    void buttonPressing(AnimatedButton
    button);

    private:
    Ui::Window *ui;
    QGraphicsScene *scene;
    int viewHeight() const;
    int viewWidth() const;

    QDeclarativeEngine engine;
    QList<QDeclarativeComponent*> loadedPlugins;
    

    Q_SIGNALS:
    void finishedLoading();
    void rebindViewSize();
    void buttonPressed(AnimatedButton* button);
    };@

    window.cpp
    @Window::Window(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Window)
    {
    ui->setupUi(this);
    scene = new QGraphicsScene(this);
    QGraphicsWidget *widget = new QGraphicsWidget();
    QGraphicsGridLayout grid = new QGraphicsGridLayout(widget);
    scene->addItem(widget);
    QGraphicsView view = new QGraphicsView(scene);
    ui->verticalLayout->addWidget(view);
    m_button = new AnimatedButton();
    connect(m_button,SIGNAL(clicked(AnimatedButton
    )),this,SLOT(buttonPressing(AnimatedButton
    )));

    engine.rootContext()->setContextProperty(QString("Katana"),this);
    engine.rootContext()->setContextProperty(QString("iButton"),m_button);
    engine.addPluginPath(QApplication::applicationDirPath());
    //QDeclarativeContext
    
    // encapsulates a QML component definition
    QDeclarativeComponent component(&engine,QUrl(QString("qrc:/scripts/qml/Katana/main.qml")));
    
    // creates the graphics item for QML at the engine's root context
    QDeclarativeItem *item = qobject_cast<QDeclarativeItem *>(component.create());
    
    if(item)
        scene->addItem(item);
    
    loadedPlugins.append(&component);
    
    view->setRenderHint(QPainter::Antialiasing,true);
    
    qDebug() << component.errors();
    
    this->setLayout(ui->verticalLayout);
    
    Q_EMIT finishedLoading();
    m_button->setVisible(true);
    scene->addItem(m_button);
    m_button->setGeometry(0,0,100,100);
    m_button->setZValue(100);
    //m_button->raise();
    

    }

    Window::~Window()
    {
    delete ui;
    }

    void Window::buttonPressing(AnimatedButton *button) {
    Q_EMIT buttonPressed(button);
    }

    int Window::viewHeight() const {
    return height() - 10;
    }

    int Window::viewWidth() const {
    return width() - 10;
    }

    void Window::resizeEvent(QResizeEvent *event) {
    emit rebindViewSize();
    }@

    main.qml
    @Rectangle {
    id: mainView
    width: Katana.viewWidth
    height: Katana.viewHeight
    color: "black"
    state: ""

    Connections {
        target: Katana
        onButtonPressed: {
            state = "clicking"
        }
    }
    
    Connections {
        target: Katana
        onRebindViewSize: {
            mainView.width = Katana.viewWidth
            mainView.height = Katana.viewHeight
    
        }
    }
    
    states: [
        State {
            name: "clicking"
            PropertyChanges { target: button; opacity: 0.6; yRotation: 360; }
        }
    
    ]
    
    transitions: [
        Transition {
             from: ""; to: "clicking"; reversible: true
             ParallelAnimation {
                 NumberAnimation { properties: "opacity,yRotation"; duration: 300; easing.type: Easing.InOutQuad }
             }
         }
    ]
    

    }@

    Now, if I had say 30 buttons in my view, I would be able to access which button has been clicked dynamically through the Connections element with the use of 'button', however, how would I be able to pass the object 'button' information to the appropriate state for use as the PropertyChange's target?



  • if you solved your problem how about you post your solution so other people who are experiencing the same problem can benefit from you ?



  • My apologies, I thought I had updated this thread again, obviously, that is not the case. This issue is only partly solved at this point.

    window.h
    @#ifndef WINDOW_H
    #define WINDOW_H

    #include <QWidget>
    #include <QPushButton>
    #include <QDebug>
    #include <QGraphicsScene>
    #include <QGraphicsWidget>
    #include <QGraphicsProxyWidget>
    #include <QGraphicsLinearLayout>
    #include <QGraphicsGridLayout>
    #include <QState>
    #include <QStateMachine>
    #include <QGraphicsView>
    #include <QStackedWidget>

    #include <QtDeclarative/QDeclarativeEngine>
    #include <QtDeclarative/QDeclarativeContext>
    #include <QtDeclarative/QDeclarativeComponent>
    #include <QtDeclarative/QDeclarativeItem>
    #include <QtDeclarative/QDeclarativeError>

    #include "gui/animatedbutton.h"

    namespace Ui {
    class Window;
    }

    class Window : public QWidget
    {
    Q_OBJECT
    Q_PROPERTY(int viewHeight READ viewHeight SCRIPTABLE true NOTIFY rebindViewSize)
    Q_PROPERTY(int viewWidth READ viewWidth SCRIPTABLE true NOTIFY rebindViewSize)

    public:
    explicit Window(QWidget *parent = 0);
    ~Window();

    Q_INVOKABLE AnimatedButton* m_button;
    

    public slots:
    Q_INVOKABLE void setTitle(QString m_title) { setWindowTitle(m_title); }

    protected slots:
    virtual void resizeEvent(QResizeEvent event);
    void buttonClicking(AnimatedButton
    button);
    void buttonPressing(AnimatedButton* button);
    void buttonReleasing(AnimatedButton* button);
    void buttonHoverIn(AnimatedButton* button,int originX,int originY);
    void buttonHoverOut(AnimatedButton* button,int originX,int originY);
    void buttonHoverMove(AnimatedButton* button,int originX,int originY);
    void setupQmlTypes();

    private:
    Ui::Window *ui;
    QGraphicsScene *scene;
    int viewHeight() const;
    int viewWidth() const;

    QDeclarativeEngine engine;
    QList<QDeclarativeComponent*> loadedPlugins;
    

    Q_SIGNALS:
    void finishedLoading();
    void rebindViewSize();
    void buttonClicked(AnimatedButton* button);
    void buttonPressed(AnimatedButton* button);
    void buttonReleased(AnimatedButton* button);
    void buttonRollOver(AnimatedButton* button,int originX,int originY);
    void buttonRollOut(AnimatedButton button,int originX,int originY);
    void buttonRolling(AnimatedButton
    button,int originX,int originY);
    };

    #endif // WINDOW_H@

    main.qml
    @import QtQuick 1.0

    Rectangle {
    id: mainView
    width: Katana.viewWidth
    height: Katana.viewHeight
    color: "black"
    state: ""

    property variant target_button: null;
    property variant event_x: null;
    property variant event_y: null;
    
    Connections {
        target: Katana
        onButtonPressed: {
            target_button = button;
            state = "pressed"
        }
    
        onButtonReleased: {
            target_button = button;
            state = "released"
        }
    
        onButtonRollOver: {
            target_button = button;
            event_x = originX;
            event_y = originY;
            state = "rollover"
        }
    }
    
    Connections {
        target: Katana
        onRebindViewSize: {
            mainView.width = Katana.viewWidth
            mainView.height = Katana.viewHeight
    
        }
    }
    
    states: [
        State {
            name: "pressed"
            PropertyChanges { target: target_button; opacity: 0.2; }
        },
        State {
            name: "released"
            PropertyChanges { target: target_button; opacity: 1.0; }
        },
        State {
            name: "rollover"
            PropertyChanges { target: target_button; opacity: 0.4; }
        }
    
    ]
    
    transitions: [
        Transition {
             to: "pressed"; reversible: false
             ParallelAnimation {
                 NumberAnimation { properties: "opacity"; duration: 300; easing.type: Easing.InOutQuad }
             }
         },
        Transition {
             to: "released"; reversible: false
             ParallelAnimation {
                 NumberAnimation { properties: "opacity"; duration: 300; easing.type: Easing.InOutQuad }
             }
         },
        Transition {
             to: "rollover"; reversible: true
             ParallelAnimation {
                 NumberAnimation { properties: "opacity"; duration: 100; easing.type: Easing.InOutQuad }
             }
         }
    
    ]
    

    }@

    As posted, this current method works, by declaring target_button as a property variant, I am able to access it through-out the qml file, however, when altering the yRotation of the button, press/release animations are only correct on the first button spawned, the other buttons' animation for release is only updated on the press event of another button in the scene.



  • window.cpp
    @#include "window.h"
    #include "ui_window.h"

    Window::Window(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Window)
    {
    this->setupQmlTypes();
    ui->setupUi(this);
    scene = new QGraphicsScene(this);
    QGraphicsWidget *widget = new QGraphicsWidget();
    QGraphicsGridLayout *grid = new QGraphicsGridLayout(widget);
    QGraphicsView *view = new QGraphicsView(scene);
    m_button = new AnimatedButton;
    scene->addItem(widget);

    ui->verticalLayout->addWidget(view);
    
    for(qint8 i = 0; i < 5; i++) {
        qDebug() << "here";
        AnimatedButton* n_button = new AnimatedButton();
        scene->addItem(n_button);
        n_button->setGeometry((100 * i) + (5 * i),0,100,100);
        n_button->setZValue(100);
        connect(n_button,SIGNAL(pressed(AnimatedButton*)),this,SLOT(buttonPressing(AnimatedButton*)));
        connect(n_button,SIGNAL(released(AnimatedButton*)),this,SLOT(buttonReleasing(AnimatedButton*)));
    }
    
    engine.addPluginPath(QApplication::applicationDirPath());
    //QDeclarativeContext
    
    // encapsulates a QML component definition
    QDeclarativeComponent component(&engine,QUrl(QString("qrc:/scripts/qml/Katana/main.qml")));
    
    // creates the graphics item for QML at the engine's root context
    QDeclarativeItem *item = qobject_cast<QDeclarativeItem *>(component.create());
    
    if(item) {
        scene->addItem(item);
    
    }
    
    loadedPlugins.append(&component);
    
    view->setRenderHint(QPainter::Antialiasing,true);
    
    qDebug() << component.errors();
    
    this->setLayout(ui->verticalLayout);
    
    Q_EMIT finishedLoading();
    m_button->setVisible(true);
    //m_button->raise();
    

    }

    Window::~Window()
    {
    delete ui;
    }

    void Window::setupQmlTypes() {
    qmlRegisterType<AnimatedButton>();
    engine.rootContext()->setContextProperty(QString("Katana"),this);
    }

    void Window::buttonClicking(AnimatedButton* button) {
    Q_EMIT buttonClicked(button);
    }

    void Window::buttonPressing(AnimatedButton *button) {
    Q_EMIT buttonPressed(button);
    }

    void Window::buttonReleasing(AnimatedButton* button) {
    Q_EMIT buttonReleased(button);
    }

    void Window::buttonHoverIn(AnimatedButton* button,int originX,int originY) {
    Q_EMIT buttonRollOver(button,originX,originY);
    }

    void Window::buttonHoverOut(AnimatedButton* button,int originX,int originY) {
    Q_EMIT buttonRollOut(button,originX,originY);
    }

    void Window::buttonHoverMove(AnimatedButton *button, int originX, int originY) {
    Q_EMIT buttonRolling(button,originX,originY);
    }

    int Window::viewHeight() const {
    return height() - 10;
    }

    int Window::viewWidth() const {
    return width() - 10;
    }

    void Window::resizeEvent(QResizeEvent *event) {
    emit rebindViewSize();
    }@


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.