From 0d0cfa66fcf470f5532bb9a48018b40985f45f99 Mon Sep 17 00:00:00 2001 From: wang-qin928 <2830862261@qq.com> Date: Mon, 22 Dec 2025 16:46:03 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E6=B7=BB=E5=8A=A0=E9=83=A8=E5=88=86UI?= =?UTF-8?q?=20=E5=AE=8C=E5=96=84=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- StudentManager.pro.user | 36 +-- mainwindow.cpp | 674 +++++++++++++++++++++++++++++----------- mainwindow.h | 47 ++- 3 files changed, 527 insertions(+), 230 deletions(-) diff --git a/StudentManager.pro.user b/StudentManager.pro.user index 2bd6bd4..ed7ca8d 100644 --- a/StudentManager.pro.user +++ b/StudentManager.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -73,14 +73,14 @@ ProjectExplorer.Project.Target.0 - Desktop Qt 5.14.2 MinGW 32-bit - Desktop Qt 5.14.2 MinGW 32-bit - qt.qt5.5142.win32_mingw73_kit - 0 + Desktop Qt 5.14.2 MinGW 64-bit + Desktop Qt 5.14.2 MinGW 64-bit + qt.qt5.5142.win64_mingw73_kit + 1 0 0 - D:/UGit/build-StudentManager-Desktop_Qt_5_14_2_MinGW_32_bit-Debug + C:/Users/wq/Desktop/build-StudentManager-Desktop_Qt_5_14_2_MinGW_64_bit-Debug true @@ -128,7 +128,7 @@ 2 - C:/Users/wq/Desktop/build-StudentManager-Desktop_Qt_5_14_2_MinGW_32_bit-Release + C:/Users/wq/Desktop/build-StudentManager-Desktop_Qt_5_14_2_MinGW_64_bit-Release true @@ -176,7 +176,7 @@ 0 - C:/Users/wq/Desktop/build-StudentManager-Desktop_Qt_5_14_2_MinGW_32_bit-Profile + C:/Users/wq/Desktop/build-StudentManager-Desktop_Qt_5_14_2_MinGW_64_bit-Profile true @@ -296,7 +296,6 @@ 2 - StudentManager2 Qt4ProjectManager.Qt4RunConfiguration:D:/UGit/StudentManager/StudentManager.pro D:/UGit/StudentManager/StudentManager.pro @@ -309,7 +308,7 @@ false true - D:/UGit/build-StudentManager-Desktop_Qt_5_14_2_MinGW_32_bit-Debug + C:/Users/wq/Desktop/build-StudentManager-Desktop_Qt_5_14_2_MinGW_64_bit-Release 1 @@ -317,14 +316,14 @@ ProjectExplorer.Project.Target.1 - Desktop Qt 5.14.2 MinGW 64-bit - Desktop Qt 5.14.2 MinGW 64-bit - qt.qt5.5142.win64_mingw73_kit - 0 + Desktop Qt 5.14.2 MinGW 32-bit + Desktop Qt 5.14.2 MinGW 32-bit + qt.qt5.5142.win32_mingw73_kit + 1 0 0 - C:/Users/wq/Desktop/build-StudentManager-Desktop_Qt_5_14_2_MinGW_64_bit-Debug + D:/UGit/build-StudentManager-Desktop_Qt_5_14_2_MinGW_32_bit-Debug true @@ -372,7 +371,7 @@ 2 - C:/Users/wq/Desktop/build-StudentManager-Desktop_Qt_5_14_2_MinGW_64_bit-Release + D:/UGit/build-StudentManager-Desktop_Qt_5_14_2_MinGW_32_bit-Release true @@ -420,7 +419,7 @@ 0 - C:/Users/wq/Desktop/build-StudentManager-Desktop_Qt_5_14_2_MinGW_64_bit-Profile + C:/Users/wq/Desktop/build-StudentManager-Desktop_Qt_5_14_2_MinGW_32_bit-Profile true @@ -540,6 +539,7 @@ 2 + StudentManager2 Qt4ProjectManager.Qt4RunConfiguration:D:/UGit/StudentManager/StudentManager.pro D:/UGit/StudentManager/StudentManager.pro @@ -552,7 +552,7 @@ false true - C:/Users/wq/Desktop/build-StudentManager-Desktop_Qt_5_14_2_MinGW_64_bit-Debug + 1 diff --git a/mainwindow.cpp b/mainwindow.cpp index 0436db2..60a5a80 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -4,18 +4,19 @@ #include #include #include -#include #include -#include #include -//#include -//#include -//#include - -MainWindow::MainWindow(QWidget *parent) - : QMainWindow(parent) +#include +#include +#include +#include +#include +#include + +MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { setupUI(); + setWindowTitle("学生信息管理系统"); } MainWindow::~MainWindow() {} @@ -25,265 +26,564 @@ void MainWindow::setupUI() QWidget *central = new QWidget(this); setCentralWidget(central); - // 顶部菜单栏 - QMenuBar *menuBar = this->menuBar(); - - fileMenu = menuBar->addMenu("文件(&F)"); // 快捷键 alt + F - editMenu = menuBar->addMenu("编辑(&E)"); // 快捷键 alt + E - // TODO - - // 左侧班级树控件 + // Action 定义 + QAction *actImport = new QAction("导入", this); + QAction *actSave = new QAction("保存", this); + + QAction *actAddCls = new QAction("新增班级", this); + QAction *actDelCls = new QAction("删除班级", this); + QAction *actRenCls = new QAction("重命名班级", this); + + // 工具栏(唯一一行) + QToolBar *toolBar = addToolBar("主工具栏"); + toolBar->setMovable(false); + toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + + // 默认显示“文件”相关 + toolBar->addAction(actImport); + toolBar->addAction(actSave); + + // 伪菜单栏按钮 + QToolButton *fileBtn = new QToolButton(this); + fileBtn->setText("文件"); + fileBtn->setToolButtonStyle(Qt::ToolButtonTextOnly); + fileBtn->setAutoRaise(true); // 看起来像菜单 + + QToolButton *editBtn = new QToolButton(this); + editBtn->setText("编辑"); + editBtn->setToolButtonStyle(Qt::ToolButtonTextOnly); + editBtn->setAutoRaise(true); + + // 放到菜单栏位置 + QWidget *menuWidget = new QWidget(this); + QHBoxLayout *menuLayout = new QHBoxLayout(menuWidget); + menuLayout->setContentsMargins(6, 0, 0, 0); + menuLayout->setSpacing(10); + + menuLayout->addWidget(fileBtn); + menuLayout->addWidget(editBtn); + menuLayout->addStretch(); + + menuBar()->setCornerWidget(menuWidget, Qt::TopLeftCorner); + + // 按钮点击 → 切换工具栏 + connect(fileBtn, &QToolButton::clicked, this, [=]() { + toolBar->clear(); + toolBar->addAction(actImport); + toolBar->addAction(actSave); + }); + + connect(editBtn, &QToolButton::clicked, this, [=]() { + toolBar->clear(); + toolBar->addAction(actAddCls); + toolBar->addAction(actDelCls); + toolBar->addAction(actRenCls); + }); + + // 核心控件初始化 tree = new QTreeWidget; tree->setHeaderLabel("班级列表"); - tree->setContextMenuPolicy(Qt::CustomContextMenu); - // 显示学生信息控件 - table = new QTableWidget; - table->setColumnCount(5); + table = new QTableWidget(0, 5); table->setHorizontalHeaderLabels({"姓名", "性别", "年龄", "学号", "电话"}); table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + table->setSelectionBehavior(QAbstractItemView::SelectRows); - // 输入学生信息控件 + // 右侧编辑面板 nameEdit = new QLineEdit; genderEdit = new QLineEdit; ageEdit = new QLineEdit; idEdit = new QLineEdit; phoneEdit = new QLineEdit; - addBtn = new QPushButton("新增学生"); - delBtn = new QPushButton("删除学生"); + addBtn = new QPushButton("新增"); + delBtn = new QPushButton("删除"); + updateBtn = new QPushButton("修改"); + searchBtn = new QPushButton("查询"); + refreshBtn = new QPushButton("刷新/清空查询"); - // 布局 - QVBoxLayout *rightLayout = new QVBoxLayout; // 垂直布局 - rightLayout->addWidget(new QLabel("姓名")); // index 0 - rightLayout->addWidget(nameEdit); // index 1 - rightLayout->addWidget(new QLabel("性别")); + QVBoxLayout *rightLayout = new QVBoxLayout; + rightLayout->addWidget(new QLabel("姓名:")); + rightLayout->addWidget(nameEdit); + rightLayout->addWidget(new QLabel("性别:")); rightLayout->addWidget(genderEdit); - rightLayout->addWidget(new QLabel("年龄")); + rightLayout->addWidget(new QLabel("年龄:")); rightLayout->addWidget(ageEdit); - rightLayout->addWidget(new QLabel("学号")); + rightLayout->addWidget(new QLabel("学号:")); rightLayout->addWidget(idEdit); - rightLayout->addWidget(new QLabel("电话")); + rightLayout->addWidget(new QLabel("电话:")); rightLayout->addWidget(phoneEdit); rightLayout->addWidget(addBtn); + rightLayout->addWidget(updateBtn); rightLayout->addWidget(delBtn); - rightLayout->addStretch(); // 设置可伸缩对齐 - - QHBoxLayout *mainLayout = new QHBoxLayout(central); // 水平布局 - mainLayout->addWidget(tree, 1); // index 1 - mainLayout->addWidget(table, 3); // index 3 - mainLayout->addLayout(rightLayout, 2); // index 2 - - // 指定信号 槽 - // 右键点击弹出增删改班级窗口 - connect(tree, &QTreeWidget::customContextMenuRequested, // 右键点击信号 - this, &MainWindow::showTreeMenu); - // 左键点击班级名 刷新中间的学生信息 - connect(tree, &QTreeWidget::itemClicked, // 左键点击信号 - this, &MainWindow::onClassClicked); - // 左键点击执行添加学生逻辑 - connect(addBtn, &QPushButton::clicked, - this, &MainWindow::addStudent); - // 左键点击执行删除学生逻辑 - connect(delBtn, &QPushButton::clicked, - this, &MainWindow::deleteStudent); - // 点击学生单元格 回显学生信息 - connect(table, &QTableWidget::cellClicked, // 单元格点击信号 - this, &MainWindow::tableItemClicked); - - // 确认窗口大小 - resize(900, 600); - setMinimumSize(800, 500); + rightLayout->addWidget(searchBtn); + rightLayout->addWidget(refreshBtn); + rightLayout->addStretch(); + + // 分页控件 + btnPrev = new QPushButton("上一页"); + btnNext = new QPushButton("下一页"); + pageLabel = new QLabel("第 1/1 页"); + QHBoxLayout *pageLayout = new QHBoxLayout; + pageLayout->addStretch(); + pageLayout->addWidget(btnPrev); + pageLayout->addWidget(pageLabel); + pageLayout->addWidget(btnNext); + pageLayout->addStretch(); + + // 布局组合 + QVBoxLayout *centerLayout = new QVBoxLayout; + centerLayout->addWidget(table); + centerLayout->addLayout(pageLayout); + + QHBoxLayout *mainLayout = new QHBoxLayout(central); + mainLayout->addWidget(tree, 1); + mainLayout->addLayout(centerLayout, 3); + mainLayout->addLayout(rightLayout, 1); + + // 信号槽连接 + connect(actAddCls, &QAction::triggered, this, &MainWindow::addClass); + connect(actDelCls, &QAction::triggered, this, &MainWindow::deleteClass); + connect(actRenCls, &QAction::triggered, this, &MainWindow::renameClass); + connect(actImport, &QAction::triggered, this, &MainWindow::importData); + connect(actSave, &QAction::triggered, this, &MainWindow::saveData); + + connect(tree, &QTreeWidget::itemClicked, this, &MainWindow::onClassClicked); + connect(addBtn, &QPushButton::clicked, this, &MainWindow::addStudent); + connect(delBtn, &QPushButton::clicked, this, &MainWindow::deleteStudent); + connect(updateBtn, &QPushButton::clicked, this, &MainWindow::updateStudent); + connect(searchBtn, &QPushButton::clicked, this, &MainWindow::searchStudent); + connect(refreshBtn, &QPushButton::clicked, this, &MainWindow::refreshAll); + connect(table, &QTableWidget::cellClicked, this, &MainWindow::tableItemClicked); + connect(btnPrev, &QPushButton::clicked, this, &MainWindow::prevPage); + connect(btnNext, &QPushButton::clicked, this, &MainWindow::nextPage); + + resize(1000, 600); } -void MainWindow::showTreeMenu(const QPoint &pos) +// 业务逻辑实现 + +QString MainWindow::currentClass() const { - // 右键点击 后触发这个函数 - QMenu menu; - QAction *add = menu.addAction("新建班级"); - QAction *del = menu.addAction("删除班级"); - QAction *ren = menu.addAction("重命名班级"); - - // 显示右键菜单 并获取用户选择 - QAction *ret = menu.exec(tree->viewport()->mapToGlobal(pos)); - - // 执行用户选择的操作 - if (ret == add) - addClass(); - else if (ret == del) - deleteClass(); - else if (ret == ren) - renameClass(); + auto item = tree->currentItem(); + return item ? item->text(0) : ""; } -void MainWindow::addClass() +void MainWindow::refreshTable() { - // 弹出对话框 输入班级名称 - QString name = QInputDialog::getText(this, "新建班级", "班级名称"); - if (name.isEmpty()) - return; - // 检查班级是否已存在 - if (classData.contains(name)) + table->setRowCount(0); + int total = displayList.size(); + int maxPage = qMax(1, (total + pageSize - 1) / pageSize); + if (currentPage > maxPage) + currentPage = maxPage; + + pageLabel->setText(QString("第 %1/%2 页").arg(currentPage).arg(maxPage)); + + int start = (currentPage - 1) * pageSize; + int end = qMin(start + pageSize, total); + + for (int i = start; i < end; ++i) { - QMessageBox::warning(this, "错误", "班级已存在,请重新输入"); - return; + int r = table->rowCount(); + table->insertRow(r); + table->setItem(r, 0, new QTableWidgetItem(displayList[i].name)); + table->setItem(r, 1, new QTableWidgetItem(displayList[i].gender)); + table->setItem(r, 2, new QTableWidgetItem(QString::number(displayList[i].age))); + table->setItem(r, 3, new QTableWidgetItem(displayList[i].id)); + table->setItem(r, 4, new QTableWidgetItem(displayList[i].phone)); } - // 将新班级添加到数据结构和树控件中 - // 由于是新班级,初始化为空列表 - classData[name] = {}; - // 在树控件中添加新节点 - // 数据与UI同步更新 - tree->addTopLevelItem(new QTreeWidgetItem({name})); } -void MainWindow::deleteClass() +void MainWindow::onClassClicked(QTreeWidgetItem *item) { - // 获取当前选中班级 // auto == QTreeWidgetItem* - auto item = tree->currentItem(); - if (!item) - return; - QString name = item->text(0); // 获取选中项的班级名称 - // 弹出确认对话框 - if (QMessageBox::question(this, "确认", "确定删除班级?") == QMessageBox::Yes) - { - // 从数据结构和树控件中删除班级 - classData.remove(name); - // 数据与UI同步更新 - delete item; // 避免内存泄漏 - table->clearContents(); // 清理学生信息内容 - table->setRowCount(0); // 清空表格行数 - } - QMessageBox::information(this, "提示", "班级已删除"); + displayList = classData[item->text(0)]; + currentPage = 1; + refreshTable(); } -void MainWindow::renameClass() +void MainWindow::addStudent() { - // 获取当前选中班级 - auto item = tree->currentItem(); - if (!item) + QString cls = currentClass(); + if (cls.isEmpty()) return; - // 获取旧班级名称 - QString oldName = item->text(0); - // 弹出对话框 输入新名称 - QString newName = QInputDialog::getText(this, "重命名", "新名称"); - // 检查新名称有效性 - if (newName.isEmpty()) + + Student s{nameEdit->text(), genderEdit->text(), ageEdit->text().toInt(), idEdit->text(), phoneEdit->text()}; + if (s.name.isEmpty() || s.id.isEmpty()) + { + QMessageBox::warning(this, "错误", "姓名和学号不能为空"); // return; - if (classData.contains(newName)) - QMessageBox::warning(this, "提示", "班级已存在"); - // 更新数据结构和树控件 - classData[newName] = classData.take(oldName); // 从数据结构中移除旧键值对,并返回旧名称关联的值,赋给新名称 - item->setText(0, newName); + } + + // 查重 + for (const auto &st : classData[cls]) + { + if (st.id == s.id) + { + QMessageBox::warning(this, "错误", "学号重复"); + return; + } + } + + classData[cls].append(s); + saveClassToFile(cls); // 自动保存 + + // 刷新输入框内容 + nameEdit->clear(); + genderEdit->clear(); + ageEdit->clear(); + idEdit->clear(); + phoneEdit->clear(); + + refreshAll(); } -void MainWindow::onClassClicked(QTreeWidgetItem *item) +void MainWindow::updateStudent() { - // 用户点击班级节点后触发此函数 - Q_UNUSED(item) // 避免未使用参数警告 - refreshTable(); // 刷新右侧学生表格内容 + QString cls = currentClass(); + int row = table->currentRow(); + if (cls.isEmpty() || row < 0) + return; + + int realIdx = (currentPage - 1) * pageSize + row; + Student &s = classData[cls][realIdx]; + s.name = nameEdit->text(); + s.gender = genderEdit->text(); + s.age = ageEdit->text().toInt(); + s.phone = phoneEdit->text(); + + saveClassToFile(cls); + refreshAll(); } -QString MainWindow::currentClass() const // 只读成员函数 +void MainWindow::deleteStudent() { - // 获取当前选中班级名称 auto == QTreeWidgetItem* - auto item = tree->currentItem(); - return item ? item->text(0) : ""; + QString cls = currentClass(); + int row = table->currentRow(); + if (row < 0 || QMessageBox::question(this, "确认", "确定删除?") != QMessageBox::Yes) + return; + + int realIdx = (currentPage - 1) * pageSize + row; + classData[cls].removeAt(realIdx); + saveClassToFile(cls); + refreshAll(); } -void MainWindow::refreshTable() +void MainWindow::searchStudent() { QString cls = currentClass(); - table->setRowCount(0); // 先清空表格内容 - if (!classData.contains(cls)) - return; // 班级不存在 + if (cls.isEmpty()) + { + QMessageBox::warning(this, "提示", "请先在左侧选择一个班级再进行查询"); + return; + } - auto &list = classData[cls]; // 获取当前班级的学生列表引用 - table->setRowCount(list.size()); // 设置表格行数为学生数量 - for (int i = 0; i < list.size(); ++i) + // 1. 获取所有输入框的关键字,并去掉首尾空格 + QString nameKw = nameEdit->text().trimmed(); + QString genderKw = genderEdit->text().trimmed(); + QString ageKw = ageEdit->text().trimmed(); + QString idKw = idEdit->text().trimmed(); + QString phoneKw = phoneEdit->text().trimmed(); + + displayList.clear(); + + // 2. 遍历当前班级的所有学生 + for (const auto &s : classData[cls]) { - // 遍历学生列表 填充表格内容 - table->setItem(i, 0, new QTableWidgetItem(list[i].name)); - table->setItem(i, 1, new QTableWidgetItem(list[i].gender)); - table->setItem(i, 2, new QTableWidgetItem(QString::number(list[i].age))); - table->setItem(i, 3, new QTableWidgetItem(list[i].id)); - table->setItem(i, 4, new QTableWidgetItem(list[i].phone)); + // 初始假设该学生符合条件 + bool isMatch = true; + + // 3. 逐个字段进行条件校验(逻辑:如果输入框不为空,则必须匹配该条件) + + // 校验姓名 + if (!nameKw.isEmpty() && !s.name.contains(nameKw, Qt::CaseInsensitive)) + { + isMatch = false; + } + // 校验性别 + if (isMatch && !genderKw.isEmpty() && !s.gender.contains(genderKw, Qt::CaseInsensitive)) + { + isMatch = false; + } + // 校验年龄 + if (isMatch && !ageKw.isEmpty() && !QString::number(s.age).contains(ageKw)) + { + isMatch = false; + } + // 校验学号 + if (isMatch && !idKw.isEmpty() && !s.id.contains(idKw, Qt::CaseInsensitive)) + { + isMatch = false; + } + // 校验电话 + if (isMatch && !phoneKw.isEmpty() && !s.phone.contains(phoneKw, Qt::CaseInsensitive)) + { + isMatch = false; + } + + // 4. 如果所有非空条件都通过,则加入显示列表 + if (isMatch) + { + displayList.append(s); + } } + + currentPage = 1; // 重置到第一页 + refreshTable(); // 刷新表格显示 } -void MainWindow::addStudent() +void MainWindow::refreshAll() { QString cls = currentClass(); - if (cls.isEmpty()) - return; + if (!cls.isEmpty()) + displayList = classData[cls]; // 恢复初始状态 + currentPage = 1; - Student s; - s.name = nameEdit->text(); - s.gender = genderEdit->text(); - s.id = idEdit->text(); - s.phone = phoneEdit->text(); + // 刷新输入框内容 + nameEdit->clear(); + genderEdit->clear(); + ageEdit->clear(); + idEdit->clear(); + phoneEdit->clear(); - // 处理年龄:用toInt的第二个参数判断是否为有效数字 - bool isAgeValid; // 检测是否转换成功 - int age = ageEdit->text().toInt(&isAgeValid); + refreshTable(); +} - if (!isAgeValid || age <= 0 || age > 120) // 年龄有效条件:转换成功 + 年龄在合理范围 +// --- 文件与分页 --- + +void MainWindow::saveClassToFile(const QString &className) +{ + QFile file(className + ".txt"); // 按班级名保存 + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { - QMessageBox::warning(this, "错误", "年龄必须是1-120的整数"); + QTextStream out(&file); + for (const auto &s : classData[className]) + { + out << s.name << "," << s.gender << "," << s.age << "," << s.id << "," << s.phone << "\n"; + } + } +} + +void MainWindow::saveData() +{ + for (auto it = classData.begin(); it != classData.end(); ++it) + saveClassToFile(it.key()); + QMessageBox::information(this, "提示", "所有班级已保存"); +} + +void MainWindow::importData() +{ + // 1. 直接弹出文件选择框,不需要预先选中班级 + QString path = QFileDialog::getOpenFileName(this, "导入班级文件", "", "文本文件 (*.txt);;所有文件 (*.*)"); + if (path.isEmpty()) return; + + // 2. 提取文件名作为班级名 + QFileInfo fileInfo(path); + QString className = fileInfo.baseName(); // 例如 "高三二班" + + // 3. 检查班级是否已存在,不存在则新建 + if (!classData.contains(className)) + { + classData[className] = QList(); + QTreeWidgetItem *newItem = new QTreeWidgetItem({className}); + tree->addTopLevelItem(newItem); + tree->setCurrentItem(newItem); // 自动选中这个新创建的班级 + } + else + { + // 如果班级已存在,询问是追加还是清空 + QMessageBox::StandardButton reply; + reply = QMessageBox::question(this, "班级已存在", + QString("班级 '%1' 已存在,是否追加数据?\n(选“否”将清空原数据并覆盖)").arg(className), + QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); + + if (reply == QMessageBox::Cancel) + return; + if (reply == QMessageBox::No) + { + classData[className].clear(); // 清空原数据实现“覆盖” + } + + // 选中已有的班级节点 + QList items = tree->findItems(className, Qt::MatchExactly); + if (!items.isEmpty()) + tree->setCurrentItem(items[0]); } - s.age = age; // 只有年龄有效,才赋值给结构体 - // qDebug() << s.name << s.id << s.age << s.phone << s.gender; - if (s.name.isEmpty() || s.gender.isEmpty() || s.id.isEmpty() || s.phone.isEmpty()) + // 4. 读取文件内容 + QFile file(path); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QMessageBox::warning(this, "错误", "信息不完整(姓名、性别、学号、电话不能为空)"); + QMessageBox::critical(this, "错误", "无法打开文件"); return; } - for (auto &st : classData[cls]) + QTextStream in(&file); + int count = 0; + while (!in.atEnd()) { - if (st.id == s.id) + QString line = in.readLine(); + QStringList fields = line.split(","); + if (fields.size() >= 5) { - QMessageBox::warning(this, "错误", "学号重复"); - return; + Student s; + s.name = fields[0].trimmed(); + s.gender = fields[1].trimmed(); + s.age = fields[2].trimmed().toInt(); + s.id = fields[3].trimmed(); + s.phone = fields[4].trimmed(); + classData[className].append(s); + count++; } } + file.close(); - classData[cls].append(s); // 将新学生追加到当前班级的学生列表 + // 5. 更新显示 + displayList = classData[className]; + currentPage = 1; refreshTable(); - // 刷新输入框内容 - nameEdit->clear(); - genderEdit->clear(); - ageEdit->clear(); - idEdit->clear(); - phoneEdit->clear(); + QMessageBox::information(this, "导入成功", QString("已成功创建/更新班级 '%1',并导入 %2 条学生记录。").arg(className).arg(count)); } -void MainWindow::deleteStudent() +void MainWindow::prevPage() { - QString cls = currentClass(); // 拿到班级名称 - int row = table->currentRow(); // 获取当前选中行 - if (cls.isEmpty() || row < 0) - return; + if (currentPage > 1) + { + currentPage--; + refreshTable(); + } +} +void MainWindow::nextPage() +{ + if (currentPage * pageSize < displayList.size()) + { + currentPage++; + refreshTable(); + } +} + +void MainWindow::tableItemClicked(int row, int) +{ + int realIdx = (currentPage - 1) * pageSize + row; + if (realIdx < displayList.size()) + { + const auto &s = displayList[realIdx]; + nameEdit->setText(s.name); + genderEdit->setText(s.gender); + ageEdit->setText(QString::number(s.age)); + idEdit->setText(s.id); + phoneEdit->setText(s.phone); + } +} - if (QMessageBox::question(this, "确认", "删除该学生?") == QMessageBox::Yes) +// 班级管理槽函数(逻辑同前,移至菜单触发) +void MainWindow::addClass() +{ + while (true) { - classData[cls].removeAt(row); + bool ok; + // 弹出输入框 + QString name = QInputDialog::getText(this, "新建班级", "请输入班级名称:", QLineEdit::Normal, "", &ok); + + // 如果用户点击了“取消”或直接关闭窗口,则退出函数 + if (!ok) + return; + + name = name.trimmed(); // 去除首尾空格 + + // 逻辑判断 1:不能为空 + if (name.isEmpty()) + { + QMessageBox::warning(this, "错误", "班级名称不能为空,请重新输入!"); + continue; // 跳回循环开始,重新弹出输入框 + } + + // 逻辑判断 2:检查是否已存在 + if (classData.contains(name)) + { + QMessageBox::warning(this, "错误", QString("班级“%1”已存在,请换一个名称!").arg(name)); + continue; // 跳回循环开始,重新弹出输入框 + } + + // 校验通过:保存数据并更新界面 + classData[name] = QList(); + QTreeWidgetItem *newItem = new QTreeWidgetItem({name}); + tree->addTopLevelItem(newItem); + tree->setCurrentItem(newItem); // 自动选中新创建的班级 + + break; // 成功创建后跳出循环 + } +} + +void MainWindow::deleteClass() +{ + auto item = tree->currentItem(); + if (!item) + { + QMessageBox::warning(this, "提示", "请先选择要删除的班级"); + return; + } + if (item && QMessageBox::question(this, "确认", "删除班级及其信息?") == QMessageBox::Yes) + { + classData.remove(item->text(0)); + delete item; + displayList.clear(); refreshTable(); } } -void MainWindow::tableItemClicked(int row, int) // 点击学生信息进行回显 +void MainWindow::renameClass() { - QString cls = currentClass(); - if (cls.isEmpty()) + // 1. 获取当前选中的班级节点 + auto item = tree->currentItem(); + if (!item) + { + QMessageBox::warning(this, "提示", "请先选择要重命名的班级"); return; - auto s = classData[cls][row]; + } + + QString oldName = item->text(0); + + // 2. 使用循环处理重复或为空的情况 + while (true) + { + bool ok; + // 弹出输入框,默认显示旧名称 + QString newName = QInputDialog::getText(this, "重命名班级", "请输入新的班级名称:", + QLineEdit::Normal, oldName, &ok); + + // 如果用户点击了“取消”,则直接退出 + if (!ok) + return; - nameEdit->setText(s.name); - genderEdit->setText(s.gender); - ageEdit->setText(QString::number(s.age)); - idEdit->setText(s.id); - phoneEdit->setText(s.phone); + newName = newName.trimmed(); // 去除多余空格 + + // 情况 A:名称没变,直接退出 + if (newName == oldName) + return; + + // 情况 B:名称为空 + if (newName.isEmpty()) + { + QMessageBox::warning(this, "错误", "班级名称不能为空,请重新输入!"); + continue; // 跳回循环开始,再次弹出对话框 + } + + // 情况 C:名称与现有其他班级重复 + if (classData.contains(newName)) + { + QMessageBox::warning(this, "错误", QString("班级“%1”已存在,请换一个名称!").arg(newName)); + continue; // 跳回循环开始 + } + + // 3. 校验通过,更新底层数据结构 QMap + // 使用 take() 移除旧键并返回对应的数据列表,再赋值给新键 + classData[newName] = classData.take(oldName); + + // 4. 更新界面显示的名称 + item->setText(0, newName); + + break; // 完成重命名,跳出循环 + } } diff --git a/mainwindow.h b/mainwindow.h index d54f194..1794e6a 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -8,6 +8,7 @@ #include #include #include +#include struct Student { @@ -28,48 +29,44 @@ public: private slots: // 班级管理 - void showTreeMenu(const QPoint &pos); void addClass(); void deleteClass(); void renameClass(); void onClassClicked(QTreeWidgetItem *item); + // 学生管理 void addStudent(); void deleteStudent(); -// void updateStudent(); -// void searchStudent(); + void updateStudent(); + void searchStudent(); void tableItemClicked(int row, int column); - // 文件操作 与 分页 -// void importData(); -// void saveData(); -// void refreshAll(); -// void prevPage(); -// void nextPage(); + + // 文件操作与分页 + void importData(); + void saveData(); + void refreshAll(); + void prevPage(); + void nextPage(); private: void setupUI(); void refreshTable(); -// void saveClassToFile(const QString &className); + void saveClassToFile(const QString &className); QString currentClass() const; -private: - // 顶部菜单栏 - QMenu *fileMenu; - QMenu *editMenu; - // 左侧班级树控件 + // UI 控件 QTreeWidget *tree; - // 中间学生表格控件 QTableWidget *table; + QLineEdit *nameEdit, *genderEdit, *ageEdit, *idEdit, *phoneEdit; + QPushButton *addBtn, *delBtn, *updateBtn, *searchBtn, *refreshBtn; + QPushButton *btnPrev, *btnNext; + QLabel *pageLabel; - QLineEdit *nameEdit; - QLineEdit *genderEdit; - QLineEdit *ageEdit; - QLineEdit *idEdit; - QLineEdit *phoneEdit; - - QPushButton *addBtn; - QPushButton *delBtn; - // 班级数据存储 + // 数据存储 QMap> classData; + QList displayList; // 当前显示的(过滤后的)数据 + int currentPage = 1; + const int pageSize = 10; // 每页10条 }; + #endif // MAINWINDOW_H