利用 Qt 模型实现嵌套数据结构

问题描述 投票:0回答:1

Configuration Page

这是我想要实现的目标的简化版本。对于添加的每个商店,可以添加一个或多个部门。对于添加的每个部门,可以添加一名或多名员工。选择列表中的一行将更新其右侧的列表。例如,选择芝麻街将更新部门列表以显示属于该商店的所有部门。选择服装将更新员工列表以显示属于该部门的所有员工。

这种关系也在下面进行了演示(请注意,这些实际上是类,并且能够在其数据在内部更改时(例如,从外部源更改)时发出信号):

struct Employee {
  std::string id;
  std::string name;
  double hourly_rate;
};

struct Department {
  std::string id;
  std::string name;
  int personCount;
  bool status;
  Employee* onShift;
  std::vector<Employee> employees;
};

struct Store {
  std::string id;
  std::string name;
  std::string address;
  std::vector<Department> departments;
};

在另一个选项卡上,我们有跨商店所有部门的汇总列表,显示实时数据,并带有一个下拉列表,可从属于该部门的员工池中选择轮班领导者。

All departments page

就 Qt 模型而言,我想有几种方法可以解决这个问题。我更喜欢将 Qt 模型视为视图和数据之间的接口,而不是它们本身对所述数据负责或拥有所述数据的所有权。

我建议将数据的所有权交给 Manager 类,该类还包含我们创建的任何子类模型。对于配置页面,我们有商店、部门和员工的三个 QAbstractListModel 子类。对于部门和员工模型,我们可以传递列表指针并根据需要调用 begin/endResetModel 以在选择项目时更新列表。

对于“所有部门”页面,我们有一个聚合部门模型,它也是 QAbstractListModel 的子类。这将包含商店中所有部门的指针列表。 On Shift Leader 下拉列表有点棘手,因为我们不能使用单一模型。我想知道在这种情况下,部门拥有自己的员工列表实例是否更有意义,可以将其返回给 QML 委托...

如您所见,我们现在有许多用于相当基本的数据层次结构的模型。模型之间的同步可能会成为一个问题,因此只能通过 Manager 类修改底层数据,然后 Manager 类可以协调模型的更新。

我是否描述了解决问题的有价值的方法,或者是否造成了混乱?我实在想不出更好的办法了

c++ qt qml
1个回答
0
投票

如果我设计数据结构,我会进行以下更改:

  • 不要使用
    id
    ,因为这可能会与 QML 的 id 混淆(使用 storeId、departmentId、employeeId 代替)
  • 建立门店、部门、员工1:M关系

如果我在 RDBMS 中表示这一点,我的 DDL 将如下所示:

CREATE TABLE Store
(
     storeId int    primary key,
     name    string            ,
     address string
);

CREATE TABLE Department
(
     departmentId int primary key,
     storeId      int foreign key REFERENCES Store(storeId),
     name         string,
     personCount  int,
     status       boolean
);

CREATE TABLE Employee
(
     employeeId   int primary key,
     departmentId int foreign key REFERENCES Department(departmentId),
     name         string,
     hourlyRate   real,
     shiftLeader  boolean
);

如果我需要持久性并存储超过 100 条记录,我会考虑使用 SQLite 之类的东西。如果我的应用程序位于内存中并且很小,我会使用 Qt6.4

list<var>
类型,因为:

  1. 与ListView有缘分
  2. 像过滤器一样使用Javascript数组很容易
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Page {
    property list<var> stores: ([
        {"storeId": 1, "name": "Cherry Tree Lane"},
        {"storeId": 2, "name": "Sesame Street"},
        {"storeId": 3, "name": "Diagon Alley"}
    ])
    property int currentStoreId: 2
    property list<var> departments: ([
        {"departmentId": 1, "storeId": 2, "name": "Clothing"},
        {"departmentId": 2, "storeId": 2, "name": "Kitchen"},
        {"departmentId": 3, "storeId": 3, "name": "Olivanders"},
        {"departmentId": 4, "storeId": 3, "name": "Borgen and Burkes"}
    ])
    property int currentDepartmentId: 1
    property list<var> employees: ([
        {"employeeId": 1, "departmentId": 1, "name": "Alex"},
        {"employeeId": 2, "departmentId": 1, "name": "John"},
        {"employeeId": 3, "departmentId": 1, "name": "Alice"},
        {"employeeId": 4, "departmentId": 1, "name": "Emma"},
        {"employeeId": 5, "departmentId": 4, "name": "Garrick"}
    ])
    property int currentEmployeeId: 1
    RowLayout {
        anchors.fill: parent
        ListView {
            Layout.fillWidth: true
            Layout.fillHeight: true
            model: stores
            delegate: ItemDelegate {
                text: modelData.name
                background: Rectangle {
                    color: modelData.storeId === currentStoreId ? "skyblue" : "white"
                }
                onClicked: {
                    currentStoreId = modelData.storeId;
                    currentDepartmentId = -1;
                    currentEmployeeId = -1;
                }
            }
        }
        ListView {
            Layout.fillWidth: true
            Layout.fillHeight: true
            model: departments.filter(d => d.storeId === currentStoreId)
            delegate: ItemDelegate {
                text: modelData.name
                background: Rectangle {
                    color: modelData.departmentId === currentDepartmentId ? "skyblue" : "white"
                }
                onClicked: {
                    currentDepartmentId = modelData.departmentId;
                    currentEmployeeId = -1;
                }
            }
        }
        ListView {
            Layout.fillWidth: true
            Layout.fillHeight: true
            model: employees.filter(e => e.departmentId === currentDepartmentId)
            delegate: ItemDelegate {
                text: modelData.name
                background: Rectangle {
                    color: modelData.employeeId === currentEmployeeId ? "skyblue" : "white"
                }
                onClicked: currentEmployeeId = modelData.employeeId
            }
        }
    }
}

您可以在线尝试以上方法!

© www.soinside.com 2019 - 2024. All rights reserved.