[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?
-
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.0Rectangle {
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();
}@