我有一个玩具QML应用程序(Qt 5.7),它由以下QML页面和一些C++代码组成,允许QML在音频设备上订阅某个状态并在QML GUI中反映该状态.玩具QML看起来像这样:
import QtQuick 2.6
import QtQuick.Controls 1.5
import QtQuick.Window 2.2
Item {
id: deviceState
property bool mute1: false
property bool mute2: false
property bool mute3: false
property bool mute4: false
Component.onCompleted: {
// Call out to C++ land, to tell the server what
// control points we are interested in tracking the state of
topLevelWindow.subscribeToControlPoints("Input 1-4 Mute", deviceState);
}
// Called by C++ land to tell us the current state of
// a control point we previously subscribed to.
function onControlPointValueUpdated(address, value) {
if (address == "Input 1 Mute") {
mute1 = value
}
else if (address == "Input 2 Mute") {
mute2 = value
}
else if (address == "Input 3 Mute") {
mute3 = value
}
else if (address == "Input 4 Mute") {
mute4 = value
}
}
// Absurdly minimalist example GUI
Text {
text: parent.mute4 ? "MUTED" : "unmuted"
}
}
Run Code Online (Sandbox Code Playgroud)
当我运行它时,只要我的音频设备上的四个静音状态之一发生变化,我的C++代码就会调用onControlPointValueUpdated(),并且根据调用中的'address'参数,四个muteN QML属性中的一个被更改.并且,每当更改mute4属性时,"文本"区域中的文本都会更新以反映出来.
这一切都很好,就目前而言,但在某些时候我需要扩大规模; 特别是我需要跟踪数百或数千个值,而不仅仅是四个,并且必须为每个值手动声明一个单独的,手工命名的QML属性将很快变得艰难且难以维护; 如果必须手动if/elseif通过每个属性,onControlPointValueUpdated()的实现将变得非常低效.
所以我的问题是,在QML中是否有某种方式可以声明属性的数组(或者更好的是字典/映射),这样我就可以一次声明大量的QML属性?即是这样的:
property bool mutes[256]: {false} // would declare mutes[0] through mutes[255], all default to false
Run Code Online (Sandbox Code Playgroud)
......或者如果没有,是否有其他推荐的方法在QML文档中保存大量的可观察状态?我喜欢我的GUI控件的能力绑定到一个QML属性作为必要得到自动更新,但看起来也许QML性能不打算使用集体?
一旦你获得了大量必须显示的数据(特别是如果它们共享一个共同的格式),你应该考虑使用QAbstractItemModel衍生物.
另外需要指出的是,从C++调用用户界面的QML并不是一个好主意,因为它往往会限制你在QML中可以做的事情,并将QML与C++联系起来.
例如,如果要在列表中显示数据:
视图中的项目是按需创建的,并且在任何时候都分配了有限的数量,这有助于您拥有大量数据和可能复杂的委托.
以下是QAbstractListModel使用自定义角色的简单自定义方式:
main.cpp:
#include <QtGui>
#include <QtQuick>
class UserModel : public QAbstractListModel
{
public:
UserModel() {
for (int i = 0; i < 100; ++i) {
mData.append(qMakePair(QString::fromLatin1("Input %1").arg(i), i % 5 == 0));
}
}
enum Roles
{
NameRole = Qt::UserRole,
MutedRole
};
QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE
{
if (!index.isValid())
return QVariant();
switch (role) {
case Qt::DisplayRole:
case NameRole:
return mData.at(index.row()).first;
case MutedRole:
return mData.at(index.row()).second;
}
return QVariant();
}
int rowCount(const QModelIndex &/*parent*/ = QModelIndex()) const Q_DECL_OVERRIDE
{
return mData.size();
}
int columnCount(const QModelIndex &/*parent*/ = QModelIndex()) const Q_DECL_OVERRIDE
{
return 1;
}
virtual QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE
{
QHash<int, QByteArray> names;
names[NameRole] = "name";
names[MutedRole] = "muted";
return names;
}
private:
QVector<QPair<QString, int> > mData;
};
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
UserModel userModel;
engine.rootContext()->setContextProperty("userModel", &userModel);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
Run Code Online (Sandbox Code Playgroud)
main.qml:
import QtQuick 2.3
import QtQuick.Layouts 1.1
import QtQuick.Window 2.2
Window {
width: 300
height: 300
visible: true
ListView {
id: listView
anchors.fill: parent
anchors.margins: 10
model: userModel
spacing: 20
delegate: ColumnLayout {
width: ListView.view.width
Text {
text: name
width: parent.width / 2
font.pixelSize: 14
horizontalAlignment: Text.AlignHCenter
}
RowLayout {
Rectangle {
width: 16
height: 16
radius: width / 2
color: muted ? "red" : "green"
}
Text {
text: muted ? qsTr("Muted") : qsTr("Unmuted")
width: parent.width / 2
horizontalAlignment: Text.AlignHCenter
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
例如,您可以轻松地将其换ListView出GridView.最重要的是,C++对QML一无所知.
您可以在此处阅读有关使用Qt Quick的C++模型的更多信息.
查看您在评论中发布的图像,可以通过多种方式制作这种类型的UI.您可以使用上面的方法,但Loader在委托中使用a .在Loader能够确定哪种类型的组件来示出了基于模型中的一些数据.但是,看起来UI上显示的数据量虽然数量很大,但如果没有视图,可能会更好.
你仍然可以使用一个模型(例如,Repeater提到类似@peppe),但你也可以通过列出每个"面板"(我不知道他们被称为什么)而以与你目前正在做的类似的方式离开它.看起来一个面板中的大多数数据是相同的,因此每个数据都可以是它自己的类(未经测试的代码如下):
#include <QtGui>
#include <QtQuick>
class Panel : public QObject
{
Q_OBJECT
Q_PROPERTY(bool muted READ muted WRITE setMuted NOTIFY mutedChanged)
Panel() { /* stuff */ }
// getters
// setters
signals:
// change signals
private:
// members
};
class WeirdPanel : public QObject
{
Q_OBJECT
Q_PROPERTY(int level READ level WRITE setLevel NOTIFY levelChanged)
WeirdPanel() { /* stuff */ }
// getters
// setters
signals:
// change signals
private:
// members
};
class Board : public QObject
{
Q_OBJECT
Q_PROPERTY(Panel *panel1 READ panel1 CONSTANT)
Q_PROPERTY(Panel *panel2 READ panel2 CONSTANT)
Q_PROPERTY(Panel *panel3 READ panel3 CONSTANT)
// etc.
Q_PROPERTY(WeirdPanel *weirdPanel READ weirdPanel WRITE setWeirdPanel NOTIFY weirdPanelChanged)
public:
Board() {
}
// getters
// setters
signals:
// change signals
private:
Panel panel1;
Panel panel2;
Panel panel3;
Panel panel4;
WeirdPanel weirdPanel;
};
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
Board board;
engine.rootContext()->setContextProperty("board", &board);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
Run Code Online (Sandbox Code Playgroud)
main.qml:
import QtQuick 2.3
import QtQuick.Layouts 1.1
import QtQuick.Window 2.2
Window {
width: 300
height: 300
visible: true
RowLayout {
anchors.fill: parent
Panel {
id: panel1
panel: board.panel1
}
Panel {
id: panel2
panel: board.panel2
}
Panel {
id: panel3
panel: board.panel3
}
WeirdPanel {
id: weirdPanel
panel: board.weirdPanel
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后,Panel.qml可能只是一列按钮和诸如此类的东西:
import QtQuick 2.0
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.0
Rectangle {
property var panel
color: "#444"
implicitWidth: columnLayout.implicitWidth
implicitHeight: columnLayout.implicitHeight
ColumnLayout {
anchors.fill: parent
Text {
text: panel.name
width: parent.width / 2
font.pixelSize: 14
horizontalAlignment: Text.AlignHCenter
}
RowLayout {
Rectangle {
width: 16
height: 16
radius: width / 2
color: panel.muted ? "red" : "green"
}
Text {
text: panel.muted ? qsTr("Muted") : qsTr("Unmuted")
width: parent.width / 2
horizontalAlignment: Text.AlignHCenter
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1867 次 |
| 最近记录: |