QT qml写了一个学生管理系统
此系统只是简单的实现学生信息的维护一.数据库端设计使用的是mysql数据库CREATE TABLE student ( id int NOT NULL, name varchar(45) COLLATE utf8mb3_bin DEFAULT NULL, age int DEFAULT NULL, classnum int DEFAULT NULL, gender varchar(1) COLLATE utf8mb3_bin DEFAULT NULL, phone varchar(11) COLLATE utf8mb3_bin DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb3 COLLATEutf8mb3_bin表里面存了大概100条数据二.model层设计建立了学生实体属性和数据库表属性保持一致学生实体头文件代码#ifndef STUDENT1_H #define STUDENT1_H #includestring #includeQString #includeQObject class Student1: public QObject { Q_OBJECT Q_PROPERTY(int id READ id1 CONSTANT) Q_PROPERTY(QString name READ name1 CONSTANT) Q_PROPERTY(int age READ age1 CONSTANT) Q_PROPERTY(int classNum READ classNum1 CONSTANT) Q_PROPERTY(QString gender READ gender1 CONSTANT) Q_PROPERTY(QString phone READ phone1 CONSTANT) /*Q_PROPERTY(int id READ id WRITE setId NOTIFY idChanged) Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) Q_PROPERTY(int age READ age WRITE setAge NOTIFY ageChanged) Q_PROPERTY(QString gender READ gender WRITE setGender NOTIFY genderChanged) Q_PROPERTY(int classNum READ classNum WRITE setClassNum NOTIFY classNumChanged) signals: void idChanged(const QString id); void nameChanged(const QString name); void ageChanged(int age); void genderChanged(const QString gender); void classNumChanged(const QString classNum);*/ public: int id; QString name; int age; QString gender; int classNum; QString phone; Student1(); Student1(int id,QString name,int age,int classnum,QString gender,QString phone); int id1() const { return this-id; } QString name1() const { return this-name; } int age1() const { return this-age; } int classNum1() const { return this-classNum; } QString gender1() const { return this-gender; } QString phone1() const { return this-phone; } QString getPhone() const; void setPhone(const QString newPhone); int getAge() const; void setAge(int newAge); int getId() const; void setId(int newId); QString getGender() const; void setGender(const QString newGender); QString getName() const; void setName(const QString newName); int getClassnum() const; void setClassnum(int newClassnum); }; Q_DECLARE_METATYPE(Student1*) #endif // STUDENT1_HQ_PROPERTY一定要加上因为在qml中我们能够调用student的属性Q_DECLARE_METATYPE(Student1*)注册学生了类我们也需要注册学生方便qml访问学生实体。三.业务层DBManagerDBManager主要就是对数据库表的增加、删除、修改、查询代码如下#ifndef DBMANAGER_H #define DBMANAGER_H #include QtSql/QSqlDatabase #include QObject #include Database/database.h #include Model/student1.h #include QtSql/QSqlQuery class Dbmanager: public QObject { Q_OBJECT private: QSqlDatabase db; public: explicit Dbmanager(QObject *parent nullptr); //对数据库的增删改查 Q_INVOKABLE bool deleteStudent(int id); Q_INVOKABLE bool updateStudent(const int id, const QString name, int age, const int classNum, const QString gender, const QString phone); Q_INVOKABLE QVariantList QueryStudent(); Q_INVOKABLE bool addStudent(const int id, const QString name,const int age, const int classNum, const QString gender, const QString phone,QString *errorMsg nullptr); QSqlQuery queryDatabase(const QString query); }; #endif // DBMANAGER_H函数一定要加上Q_INVOKABLE这样在qml能够直接调用四.工具层因为qml要用到treeModel所以我们实现这个左边菜单栏的工具代码如下#ifndef TREEMODEL_H #define TREEMODEL_H #include QAbstractItemModel #include QVariant #include QVector #include QIcon // 1. 定义树节点结构 struct TreeItem { QString name; // 显示名称 QString url; // 页面路径 (自定义数据) QIcon icon; // 图标 (可选) TreeItem *parent; // 父节点 QVectorTreeItem* children; // 子节点列表 explicit TreeItem(const QString name, const QString url , TreeItem *parentItem nullptr) : name(name), url(url), parent(parentItem) {} ~TreeItem() { qDeleteAll(children); } void appendChild(TreeItem *child) { children.append(child); } TreeItem *child(int row) { if (row 0 || row children.size()) return nullptr; return children.at(row); } int childCount() const { return children.count(); } int row() const { if (parent) return parent-children.indexOf(const_castTreeItem*(this)); return 0; } }; // 2. 定义模型类 class TreeModel : public QAbstractItemModel { Q_OBJECT // 注册自定义角色以便在 QML 中通过 model.url 访问 Q_ENUMS(Roles) public: enum Roles { NameRole Qt::UserRole 1, UrlRole, IconRole }; explicit TreeModel(QObject *parent nullptr); ~TreeModel(); // --- 必须实现的核心虚函数 --- QVariant data(const QModelIndex index, int role) const override; Qt::ItemFlags flags(const QModelIndex index) const override; QVariant headerData(int section, Qt::Orientation orientation, int role Qt::DisplayRole) const override; QModelIndex index(int row, int column, const QModelIndex parent QModelIndex()) const override; QModelIndex parent(const QModelIndex index) const override; int rowCount(const QModelIndex parent QModelIndex()) const override; int columnCount(const QModelIndex parent QModelIndex()) const override; // --- 辅助函数构建测试数据 --- void setupModelData(); protected: // 映射 Role 到 QML 属性名 QHashint, QByteArray roleNames() const override; private: TreeItem *rootItem; // 根节点不可见 }; #endif // TREEMODEL_H实现代码可以用ai生成。五.前端页面实现层Main.qml代码主要实现通过子页面进行实现import QtQuick import QtQuick.Layouts import QtQuick.Controls ApplicationWindow { id: root width: 640 height: 480 minimumWidth: 200 minimumHeight: 250 visible: true title: qsTr(Hello World) color: lightblue /*Component.onCompleted: { // 直接输出数组长度 console.log(学生数组长度, students.length) console.log(第一个属性, students[0]) }*/ /*property var students1: [ { id: 1, name: 张三, age: 20, major: 计算机科学, email: zhangsanexample.com }, { id: 2, name: 李四, age: 21, major: 软件工程, email: lisiexample.com }, { id: 3, name: 王五, age: 19, major: 人工智能, email: wangwuexample.com } ]*/ ColumnLayout { anchors.fill: parent // 让布局填满整个窗口 spacing: 10 // Text 和 StackView 之间的间距 Text { text: 学生信息管理系统 font.pixelSize: 32 font.bold: true color: #2c3e50 // 在 ColumnLayout 中Layout.alignment 控制水平对齐 Layout.alignment: Qt.AlignHCenter // 如果希望 Text 高度自适应不需要设置固定高度 } StackView { id: stackView5 // 使用 Layout 属性来控制大小而不是固定的 width/height Layout.fillWidth: true // 宽度填满父容器 Layout.fillHeight: true // 高度占据剩余所有空间 Layout.preferredHeight: 400 // 可选设置一个首选高度 background: Rectangle { color: lightblue } initialItem: qml1/first.qml } Text { text: 系统注册号4353465465654 font.pixelSize: 32 font.bold: true color: #2c3e50 // 在 ColumnLayout 中Layout.alignment 控制水平对齐 Layout.alignment: Qt.AlignHCenter // 如果希望 Text 高度自适应不需要设置固定高度 } } }实现效果图这是主页面点击编辑跳转到编辑界面点击更新就可成功保存到数据库。点击删除提示后即可从数据库删除成功点击菜单栏增加学生信息成功后会提示增加成功。主页面的分页菜单是通过ai生成的listStudent.qml代码如下import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 Rectangle { id: root1 color: lightblue property var students: dbManager.QueryStudent() // 分页相关属性 property int currentPage: 1 // 当前页码从1开始 property int pageSize: 10 // 每页显示条数 property int totalCount: students.length // 总条数 property int totalPages: Math.ceil(totalCount / pageSize) // 总页数 // 计算当前页的数据 property var pagedStudents: { var start (currentPage - 1) * pageSize var end Math.min(start pageSize, totalCount) return students.slice(start, end) } // 过滤后的数据搜索 分页 property var filteredStudents: pagedStudents.filter(function(s) { return s.name.indexOf(searchField.text) ! -1 }) ColumnLayout { anchors.fill: parent spacing: 0 // 工具栏 Rectangle { Layout.fillWidth: true Layout.preferredHeight: 50 color: white border.color: #e0e0e0 RowLayout { anchors.fill: parent anchors.leftMargin: 20 anchors.rightMargin: 20 TextField { id: searchField placeholderText: 搜索学生姓名... Layout.preferredWidth: 200 background: Rectangle { color: #f9f9f9 radius: 4 border.color: #ddd } // 搜索时重置到第一页 onTextChanged: root1.currentPage 1 } Item { Layout.fillWidth: true } Button { text: 新增学生 background: Rectangle { color: parent.pressed ? #45a049 : #4caf50 radius: 4 } contentItem: Text { text: parent.text color: white horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } onClicked: { stackView.push(EditStudentPage.qml, { student: null, isEdit: false }) } } } } // 表头 Rectangle { Layout.preferredWidth: parent.width * 0.8 Layout.preferredHeight: 50 Layout.alignment: Qt.AlignHCenter radius: 8 clip: true border.color: #e0e0e0 color: #e0e0e0 RowLayout { anchors.fill: parent anchors.leftMargin: 20 anchors.rightMargin: 20 spacing: 0 Text { Layout.fillHeight: true Layout.fillWidth: true Layout.preferredWidth: 100 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter text: id font.bold: true } Text { Layout.fillHeight: true Layout.fillWidth: true Layout.preferredWidth: 100 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter text: name font.bold: true } Text { Layout.fillHeight: true Layout.fillWidth: true Layout.preferredWidth: 100 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter text: age font.bold: true } Text { Layout.fillHeight: true Layout.fillWidth: true Layout.preferredWidth: 100 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter text: classNum font.bold: true } Text { Layout.fillHeight: true Layout.fillWidth: true Layout.preferredWidth: 100 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter text: gender font.bold: true } Text { Layout.fillHeight: true Layout.fillWidth: true Layout.preferredWidth: 100 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter text: phone font.bold: true } Text { Layout.fillWidth: false Layout.preferredWidth: 160 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter text: 操作 font.bold: true } } } // 学生列表 ListView { id: studentListView Layout.preferredWidth: parent.width * 0.8 Layout.fillHeight: true Layout.alignment: Qt.AlignHCenter clip: true spacing: 2 model: filteredStudents delegate: Rectangle { width: studentListView.width height: 60 color: white radius: 4 border.color: #e0e0e0 RowLayout { anchors.fill: parent anchors.leftMargin: 20 anchors.rightMargin: 20 spacing: 0 Text { Layout.fillHeight: true Layout.fillWidth: true Layout.preferredWidth: 100 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter text: modelData.id font.pixelSize: 14 color: #333 } Text { Layout.fillHeight: true Layout.fillWidth: true Layout.preferredWidth: 100 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter text: modelData.name font.pixelSize: 14 color: #333 } Text { Layout.fillHeight: true Layout.fillWidth: true Layout.preferredWidth: 100 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter text: modelData.age font.pixelSize: 14 color: #333 } Text { Layout.fillHeight: true Layout.fillWidth: true Layout.preferredWidth: 100 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter text: modelData.classNum font.pixelSize: 14 color: #333 } Text { Layout.fillHeight: true Layout.fillWidth: true Layout.preferredWidth: 100 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter text: modelData.gender font.pixelSize: 14 color: #333 } Text { Layout.fillHeight: true Layout.fillWidth: true Layout.preferredWidth: 100 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter text: modelData.phone font.pixelSize: 14 color: #333 } RowLayout { Layout.fillWidth: false Layout.preferredWidth: 160 spacing: 5 Button { Layout.preferredWidth: 75 Layout.preferredHeight: 30 text: 编辑 padding: 0 background: Rectangle { color: parent.pressed ? #1565c0 : #2196f3 radius: 4 } contentItem: Text { text: parent.text color: white horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.pixelSize: 12 } onClicked: { stackView1.pop() stackView1.push(EditStudentPage.qml, { student: modelData, isEdit: true }, StackView.Immediate) } } Button { Layout.preferredWidth: 75 Layout.preferredHeight: 30 text: 删除 padding: 0 background: Rectangle { color: parent.pressed ? #c62828 : #f44336 radius: 4 } contentItem: Text { text: parent.text color: white horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.pixelSize: 12 } onClicked: { console.log(删除学生 id:, modelData.id) var result dbManager.deleteStudent(modelData.id) if (result) { console.log(删除成功) // 重新加载数据 root1.students dbManager.QueryStudent() root1.totalCount root1.students.length root1.totalPages Math.ceil(root1.totalCount / root1.pageSize) // 如果当前页超出范围回到最后一页 if (root1.currentPage root1.totalPages root1.totalPages 0) { root1.currentPage root1.totalPages } } else { console.log(删除失败) } } } } } } } // 分页控件 Rectangle { Layout.fillWidth: true Layout.preferredHeight: 50 color: white border.color: #e0e0e0 RowLayout { anchors.centerIn: parent spacing: 5 // 每页条数选择 Text { text: 每页 color: #666 font.pixelSize: 13 } ComboBox { id: pageSizeCombo Layout.preferredWidth: 90 Layout.preferredHeight: 30 model: [5, 10, 20, 50] currentIndex: 1 // 默认 10 onCurrentTextChanged: { root1.pageSize parseInt(currentText) root1.currentPage 1 root1.totalPages Math.ceil(root1.totalCount / root1.pageSize) } } Text { text: 条 color: #666 font.pixelSize: 13 } Item { Layout.preferredWidth: 20 } // 上一页 Button { Layout.preferredWidth: 70 Layout.preferredHeight: 30 text: 上一页 enabled: root1.currentPage 1 padding: 0 background: Rectangle { color: parent.enabled ? (parent.pressed ? #1976d2 : #2196f3) : #ccc radius: 4 } contentItem: Text { text: parent.text color: white horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.pixelSize: 12 } onClicked: { if (root1.currentPage 1) { root1.currentPage-- } } } // 页码显示 Text { text: root1.currentPage / root1.totalPages 页 color: #333 font.pixelSize: 13 Layout.alignment: Qt.AlignVCenter } // 页码输入跳转 TextField { id: jumpPageField Layout.preferredWidth: 50 Layout.preferredHeight: 30 placeholderText: text: root1.currentPage horizontalAlignment: Text.AlignHCenter validator: IntValidator { bottom: 1; top: root1.totalPages } background: Rectangle { color: #f9f9f9 radius: 4 border.color: #ddd } onEditingFinished: { var page parseInt(text) if (page 1 page root1.totalPages) { root1.currentPage page } else { text root1.currentPage } } } Button { Layout.preferredWidth: 50 Layout.preferredHeight: 30 text: 跳转 padding: 0 background: Rectangle { color: parent.pressed ? #1976d2 : #2196f3 radius: 4 } contentItem: Text { text: parent.text color: white horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.pixelSize: 12 } onClicked: { var page parseInt(jumpPageField.text) if (page 1 page root1.totalPages) { root1.currentPage page } } } // 下一页 Button { Layout.preferredWidth: 70 Layout.preferredHeight: 30 text: 下一页 enabled: root1.currentPage root1.totalPages padding: 0 background: Rectangle { color: parent.enabled ? (parent.pressed ? #1976d2 : #2196f3) : #ccc radius: 4 } contentItem: Text { text: parent.text color: white horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.pixelSize: 12 } onClicked: { if (root1.currentPage root1.totalPages) { root1.currentPage } } } Item { Layout.preferredWidth: 20 } // 总条数显示 Text { text: 共 root1.totalCount 条 color: #666 font.pixelSize: 13 Layout.alignment: Qt.AlignVCenter } } } } // 数据变化时更新总页数 onStudentsChanged: { totalCount students.length totalPages Math.ceil(totalCount / pageSize) if (currentPage totalPages totalPages 0) { currentPage totalPages } } }资源下载链接创作中心-CSDN