1

I have got this Projekt which uses a QStatemachine to manage the UI, where I want to add a customized List. The UI is supposed to be only manipulated by key events. As far as I understand I need a ListView on the qml side.

The delegate of ListView only reacts on mouse input or direct key input. But I have use the QStatemachine in C++ to operate it, since it is handling all key events for the UI. What I want to happen when I press the right arrow key is vor the list to be shifted to the left.
(The currentItem is alway in the middle of the screen.)

this is the inital State of the lisfview

enter image description here

So my ListView is looking like this at the Moment.

Component {
            id:myDelegation
            Item {
               x: 50
               width: 80
               height: 60
               Rectangle {
                  width: 60
                  height: 60

                  Text {
                    text: name
                    anchors.centerIn: parent
                  }

                  color: parent.ListView.isCurrentItem ? "red" : "steelblue";
                  scale: parent.ListView.isCurrentItem ? 1.5 : 1;
              }

          }
        }


        ListView {
            id: listView1
            x: 0
            y: 50
            width: 1920
            height: 214
            orientation: ListView.Horizontal
            spacing: 4
            model: TileList{}
            delegate: myDelegation
            preferredHighlightBegin: width / 2 - 10
            preferredHighlightEnd: width / 2 + 10
            highlightRangeMode: ListView.StrictlyEnforceRange
        }

The c++ Statemachine is a QStatemachine which sends Signals to qml.

How do I bind the signals to the delegate of the Listview?

user1997675
  • 144
  • 1
  • 10
  • You can use `StateMachine` directly from QML. It is easier and faster than using the C++ classes. – dtech Dec 17 '16 at 15:39
  • Well I already got the finished Statemachine in c++ and it is quite big. So I cannot change it without starting from scratch. – user1997675 Dec 17 '16 at 15:54
  • Then just interface it to QML. It is already a QObject derived, so you can just expose it as a context property and use its signals and slots. – dtech Dec 17 '16 at 16:11

2 Answers2

2

The easiest way is to just have the state machine set the "currentIndex"

A common pattern is to have an interface object that bridges between QML and the QStateMachine

class StateInterface : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int currentIndex MEMBER m_currentIndex NOTIFY currentIndexChanged)

public:
    explicit StateInterface(QObject *parent = 0);

signals:
    void currentIndexChanged() const;

private:
    int m_currentIndex;
};

An instance of that object is exposed to QML via the "context property" mechansism

StateInterface stateInterface;
qmlEngine->rootContext()->setContextProperty("_stateInterface", &stateInterface);

And used in QML as needed

ListView {
    currentIndex: _stateInterface.currentIndex
}

The QStateMachine uses the same stateInterface object as a target for state property assignments

QState *beginState = new QState(stateMachine);
beginState->assignProperty(&stateInterface, "currentIndex", 0);
// and so on.

The StateInterface object can also provide slots to be used by QML to affect state changes. E.g.

public slots:
    void triggerReset() { emit trigger reset(); }

signals:
    void reset();

And the QStateMachine can, for example, then react to those signals wth a signal transition into the beginState

To summarize this technique:

  1. the QStateMachine controls the application state
  2. all state data that is of interest to QML is exposed via one or more interface objects
  3. the QML side uses the state data in a nice, declarative way just like it would if it did the state handling itself
Kevin Krammer
  • 5,159
  • 2
  • 9
  • 22
1

Step one - expose the state machine as a context property so that it is visible to qml:

engine.rootContext()->setContextProperty("SM", stateMachinePtr);

Step two - use a Connections element to establish a connection:

Connections {
  target: SM
  onSomeSignal: doSomeStuff()
}
dtech
  • 47,916
  • 17
  • 112
  • 190
  • Is it possible to expose the statemachine if i am using QTQuickView instead of an engine? – user1997675 Dec 17 '16 at 18:24
  • Yes, `QQuickView` also has `rootContext()`. – dtech Dec 17 '16 at 18:28
  • Ok. Then how am I able to use onSignal to manipulate a listView? I cannot just overwrite `delegate:`. Can I? – user1997675 Dec 17 '16 at 18:32
  • @user1997675 - I am not a psychic, I don't know what your C++ code does and how it does it. You asked how to bind the state machines signals to a qml object, I provided the answer. – dtech Dec 17 '16 at 19:01
  • I did not mean to offend you. I am just trying to understand how this works. I am very new to QT and I do not understand how to use this with ListView. Thanks anyway. – user1997675 Dec 17 '16 at 19:13
  • You did not offend me, you are simply not pulling your weight. It is very simple - once the state machine is exposed as a qml root context property, it is visible from everywhere in QML, so you put the `Connections` element where you need it to, and put whatever "influence" code you need in it. The state machine emits the signal, your code is executed, whatever you coded happens. As simple as that. – dtech Dec 17 '16 at 19:29