【发布时间】:2020-04-04 05:36:42
【问题描述】:
我正在对应用程序进行原型设计,并且我想从应用程序的 C++ 端的 QStateMachine 控制 QML UI 转换。为了让事情变得更简单,我们可以说 QML UI 由多个页面组成,其中包含应该触发从一个页面转换到另一个页面的按钮。
// main.qml
Window {
// ..
StackLayout {
id: layout
anchors.fill: parent
currentIndex: uiController.currentPage // binding with the C++ side
Page0 {
id: page0
}
Page1 {
id: page1
}
Page2 {
id: page2
}
Page3 {
id: page3
}
}
// ..
}
}
现在每个Page 都有一个Button 以便用户可以转到另一个页面:
// example of Page0.qml
Page {
id: root
// ..
Button {
text: "Page 1"
width: 100
height: 100
anchors.top: text.bottom
anchors.horizontalCenter: text.horizontalCenter
anchors.horizontalCenterOffset: 10
onClicked: {
console.log("Button clicked")
backend.msg = "Button clicked !"
uiController.buttonClicked = 1; // binding with the C++ side
}
}
// ..
}
在 C++ 方面,我有一个控制器,它在内部使用状态机来控制转换:
class UIController : public QObject
{
Q_OBJECT
Q_PROPERTY(int buttonClicked READ buttonClicked WRITE setButtonClicked NOTIFY buttonClickedChanged)
Q_PROPERTY(int currentPage READ currentPage WRITE setCurrentPage NOTIFY currentPageChanged)
public:
// ..
private:
QStateMachine m_machine;
int m_buttonClicked;
int m_currentPage;
};
现在重要的部分是 QStateMachine 的设置:
UIController::UIController()
: m_buttonClicked(0)
{
QState *page1 = new QState();
QState *page2 = new QState();
QState *page3 = new QState();
QState *page4 = new QState();
// ButtonTransition rely on a ButtonEvent
ButtonTransition *tr1 = new ButtonTransition(1);
ButtonTransition *tr2 = new ButtonTransition(2);
ButtonTransition *tr3 = new ButtonTransition(3);
ButtonTransition *tr4 = new ButtonTransition(4);
// the current page is a state property
page1->assignProperty(this, "currentPage", 0);
page2->assignProperty(this, "currentPage", 1);
page3->assignProperty(this, "currentPage", 2);
page4->assignProperty(this, "currentPage", 3);
tr1->setTargetState(page2);
tr2->setTargetState(page3);
tr3->setTargetState(page4);
tr4->setTargetState(page1);
page1->addTransition(tr1);
page2->addTransition(tr2);
page3->addTransition(tr3);
page4->addTransition(tr4);
m_machine.addState(page1);
m_machine.addState(page2);
m_machine.addState(page3);
m_machine.addState(page4);
m_machine.setInitialState(page1);
m_machine.start();
}
最后要发生转换:
/* this setter function is called everytime the QML side change the
buttonClicked property of the UiController */
void UIController::setButtonClicked(int button)
{
if (m_buttonClicked != button) {
m_buttonClicked = button;
m_machine.postEvent(new ButtonEvent(button));
emit buttonClickedChanged();
}
}
它确实有效,但我想问是否有更好的方法来做到这一点:我认为这种方法有点“笨拙”。
特别是可以将状态机转换直接绑定到 QML 信号吗? (至于QSignalTransition)
谢谢。
【问题讨论】:
-
“至于
QSignalTransition” - 你为什么不用那个? -
我不确定我是否正确...我会尝试回答。
-
好的,我想我现在遇到了你的问题:你想要那个信号
buttonClickedChanged,但你只想转换,当m_buttonClicked具有正确的值时?还是您更愿意将buttonClickedChanged和m_buttonClicked一起根除? -
这是我已经拥有的:只有当
ButtonEvent匹配在ButtonTransition的ctor 中传递的按钮值时才会触发ButtonTransition。现在我的问题与 1 更相关 - 有更好的设计吗? 2 - 如果可能,使用从 QML 对象触发的信号作为状态机的转换是否更好? -
您应该看看 QML 声明性状态机。它非常简洁,比类似的 QStateMachine 更容易阅读。您的 C++ 状态机可以用 25 行代码编写。