diff --git a/StudentManager.pro b/StudentManager.pro index 171b59b..ef4366c 100644 --- a/StudentManager.pro +++ b/StudentManager.pro @@ -20,8 +20,7 @@ SOURCES += \ mainwindow.cpp HEADERS += \ - mainwindow.h \ - student.h + mainwindow.h # Default rules for deployment. diff --git a/StudentManager.pro.user b/StudentManager.pro.user index c69ff49..2bd6bd4 100644 --- a/StudentManager.pro.user +++ b/StudentManager.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -59,6 +59,15 @@ -fno-delayed-template-parsing true + + true + Builtin.TidyAndClazy + 16 + + + + true + @@ -71,7 +80,7 @@ 0 0 - C:/Users/wq/Desktop/build-StudentManager-Desktop_Qt_5_14_2_MinGW_32_bit-Debug + D:/UGit/build-StudentManager-Desktop_Qt_5_14_2_MinGW_32_bit-Debug true @@ -300,7 +309,7 @@ false true - C:/Users/wq/Desktop/build-StudentManager-Desktop_Qt_5_14_2_MinGW_32_bit-Debug + D:/UGit/build-StudentManager-Desktop_Qt_5_14_2_MinGW_32_bit-Debug 1 @@ -531,19 +540,19 @@ 2 - - ProjectExplorer.CustomExecutableRunConfiguration - + Qt4ProjectManager.Qt4RunConfiguration:D:/UGit/StudentManager/StudentManager.pro + D:/UGit/StudentManager/StudentManager.pro false false true + true false false true - + C:/Users/wq/Desktop/build-StudentManager-Desktop_Qt_5_14_2_MinGW_64_bit-Debug 1 diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..347bd60 Binary files /dev/null and b/favicon.ico differ diff --git a/main.cpp b/main.cpp index fd3e533..c4adc5c 100644 --- a/main.cpp +++ b/main.cpp @@ -5,6 +5,7 @@ int main(int argc, char *argv[]) { QApplication a(argc, argv); + a.setWindowIcon(QIcon("D:/UGit/StudentManager/favicon.ico")); // 设置全局icon文件 MainWindow w; w.show(); return a.exec(); diff --git a/mainwindow.cpp b/mainwindow.cpp index f6bab88..0436db2 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -1,123 +1,289 @@ #include "mainwindow.h" +#include +#include +#include #include +#include +#include +#include #include +#include +//#include +//#include +//#include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) +{ + setupUI(); +} + +MainWindow::~MainWindow() {} + +void MainWindow::setupUI() { QWidget *central = new QWidget(this); setCentralWidget(central); - // 表格 - tableView = new QTableView(this); - model = new QStandardItemModel(this); - model->setHorizontalHeaderLabels({"学号", "姓名", "成绩"}); - tableView->setModel(model); + // 顶部菜单栏 + QMenuBar *menuBar = this->menuBar(); - // 输入框 - idEdit = new QLineEdit(); - idEdit->setPlaceholderText("学号"); // 占位符 && 水印文字 - nameEdit = new QLineEdit(); - nameEdit->setPlaceholderText("姓名"); - scoreEdit = new QLineEdit(); - scoreEdit->setPlaceholderText("成绩"); + fileMenu = menuBar->addMenu("文件(&F)"); // 快捷键 alt + F + editMenu = menuBar->addMenu("编辑(&E)"); // 快捷键 alt + E + // TODO - // 按钮 - addButton = new QPushButton("添加"); - deleteButton = new QPushButton("删除"); + // 左侧班级树控件 + tree = new QTreeWidget; + tree->setHeaderLabel("班级列表"); + tree->setContextMenuPolicy(Qt::CustomContextMenu); + + // 显示学生信息控件 + table = new QTableWidget; + table->setColumnCount(5); + table->setHorizontalHeaderLabels({"姓名", "性别", "年龄", "学号", "电话"}); + table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + + // 输入学生信息控件 + nameEdit = new QLineEdit; + genderEdit = new QLineEdit; + ageEdit = new QLineEdit; + idEdit = new QLineEdit; + phoneEdit = new QLineEdit; + + addBtn = new QPushButton("新增学生"); + delBtn = new QPushButton("删除学生"); // 布局 - // Edit水平布局 - QHBoxLayout *formLayout_Edit = new QHBoxLayout(); - formLayout_Edit->addWidget(idEdit); - formLayout_Edit->addWidget(nameEdit); - formLayout_Edit->addWidget(scoreEdit); // 使各个Edit之间水平分布 - - // Button水平布局 - QHBoxLayout *formLayout_button = new QHBoxLayout(); - formLayout_button->addWidget(addButton); - formLayout_button->addWidget(deleteButton); - - // 垂直布局 - QVBoxLayout *mainLayout = new QVBoxLayout(); - mainLayout->addWidget(tableView); // index 0:垂直布局中第0个元素(表格) - mainLayout->addLayout(formLayout_Edit); // index 1:垂直布局中第1个元素(水平排列的输入框/按钮) - mainLayout->addLayout(formLayout_button); // index 2:垂直布局中第2个元素 (按钮) - - // 控制大小 - mainLayout->setStretch(0, 1); // 表格撑满 - mainLayout->setStretch(1, 0); // 输入区最小 - mainLayout->setContentsMargins(10, 10, 10, 10); // 让每一个控件都与边缘保持10个像素的距离 - - central->setLayout(mainLayout); - - tableView->setSizePolicy( - QSizePolicy::Expanding, - QSizePolicy::Expanding); - - // 信号槽 - connect(addButton, &QPushButton::clicked, this, &MainWindow::on_addButton_clicked); - connect(deleteButton, &QPushButton::clicked, this, &MainWindow::on_deleteButton_clicked); + QVBoxLayout *rightLayout = new QVBoxLayout; // 垂直布局 + rightLayout->addWidget(new QLabel("姓名")); // index 0 + rightLayout->addWidget(nameEdit); // index 1 + rightLayout->addWidget(new QLabel("性别")); + rightLayout->addWidget(genderEdit); + rightLayout->addWidget(new QLabel("年龄")); + rightLayout->addWidget(ageEdit); + rightLayout->addWidget(new QLabel("学号")); + rightLayout->addWidget(idEdit); + rightLayout->addWidget(new QLabel("电话")); + rightLayout->addWidget(phoneEdit); + rightLayout->addWidget(addBtn); + 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); } -// 这个析构还必须得有 -MainWindow::~MainWindow() +void MainWindow::showTreeMenu(const QPoint &pos) { + // 右键点击 后触发这个函数 + 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(); } -void MainWindow::on_addButton_clicked() +void MainWindow::addClass() { - // 添加学生信息的逻辑 - Student stu; - stu.id = idEdit->text(); - stu.name = nameEdit->text(); - stu.score = scoreEdit->text().toDouble(); - // qDebug() << "id : " << stu.id - // << "name : " << stu.name - // << "score : " << stu.score; - - // 判空F - if (stu.id.isEmpty() || stu.name.isEmpty()) + // 弹出对话框 输入班级名称 + QString name = QInputDialog::getText(this, "新建班级", "班级名称"); + if (name.isEmpty()) + return; + // 检查班级是否已存在 + if (classData.contains(name)) { - QMessageBox::warning(this, "错误", "学号和姓名不能为空!"); + QMessageBox::warning(this, "错误", "班级已存在,请重新输入"); return; } - students.push_back(stu); + // 将新班级添加到数据结构和树控件中 + // 由于是新班级,初始化为空列表 + classData[name] = {}; + // 在树控件中添加新节点 + // 数据与UI同步更新 + tree->addTopLevelItem(new QTreeWidgetItem({name})); +} - // 刷新表格 - refreshTable(); +void MainWindow::deleteClass() +{ + // 获取当前选中班级 // 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, "提示", "班级已删除"); +} - // 刷新输入框内容 - idEdit->clear(); - nameEdit->clear(); - scoreEdit->clear(); +void MainWindow::renameClass() +{ + // 获取当前选中班级 + auto item = tree->currentItem(); + if (!item) + return; + // 获取旧班级名称 + QString oldName = item->text(0); + // 弹出对话框 输入新名称 + QString newName = QInputDialog::getText(this, "重命名", "新名称"); + // 检查新名称有效性 + if (newName.isEmpty()) + return; + if (classData.contains(newName)) + QMessageBox::warning(this, "提示", "班级已存在"); + // 更新数据结构和树控件 + classData[newName] = classData.take(oldName); // 从数据结构中移除旧键值对,并返回旧名称关联的值,赋给新名称 + item->setText(0, newName); +} + +void MainWindow::onClassClicked(QTreeWidgetItem *item) +{ + // 用户点击班级节点后触发此函数 + Q_UNUSED(item) // 避免未使用参数警告 + refreshTable(); // 刷新右侧学生表格内容 +} + +QString MainWindow::currentClass() const // 只读成员函数 +{ + // 获取当前选中班级名称 auto == QTreeWidgetItem* + auto item = tree->currentItem(); + return item ? item->text(0) : ""; } -void MainWindow::on_deleteButton_clicked() +void MainWindow::refreshTable() +{ + QString cls = currentClass(); + table->setRowCount(0); // 先清空表格内容 + if (!classData.contains(cls)) + return; // 班级不存在 + + auto &list = classData[cls]; // 获取当前班级的学生列表引用 + table->setRowCount(list.size()); // 设置表格行数为学生数量 + for (int i = 0; i < list.size(); ++i) + { + // 遍历学生列表 填充表格内容 + 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)); + } +} + +void MainWindow::addStudent() { - int row = tableView->currentIndex().row(); - if (row < 0) + QString cls = currentClass(); + if (cls.isEmpty()) + return; + + Student s; + s.name = nameEdit->text(); + s.gender = genderEdit->text(); + s.id = idEdit->text(); + s.phone = phoneEdit->text(); + + // 处理年龄:用toInt的第二个参数判断是否为有效数字 + bool isAgeValid; // 检测是否转换成功 + int age = ageEdit->text().toInt(&isAgeValid); + + if (!isAgeValid || age <= 0 || age > 120) // 年龄有效条件:转换成功 + 年龄在合理范围 + { + QMessageBox::warning(this, "错误", "年龄必须是1-120的整数"); return; + } + s.age = age; // 只有年龄有效,才赋值给结构体 - students.remove(row); - // 刷新表格 + // qDebug() << s.name << s.id << s.age << s.phone << s.gender; + if (s.name.isEmpty() || s.gender.isEmpty() || s.id.isEmpty() || s.phone.isEmpty()) + { + QMessageBox::warning(this, "错误", "信息不完整(姓名、性别、学号、电话不能为空)"); + return; + } + + for (auto &st : classData[cls]) + { + if (st.id == s.id) + { + QMessageBox::warning(this, "错误", "学号重复"); + return; + } + } + + classData[cls].append(s); // 将新学生追加到当前班级的学生列表 refreshTable(); + + // 刷新输入框内容 + nameEdit->clear(); + genderEdit->clear(); + ageEdit->clear(); + idEdit->clear(); + phoneEdit->clear(); } -void MainWindow::refreshTable() +void MainWindow::deleteStudent() { - model->removeRows(0, model->rowCount()); + QString cls = currentClass(); // 拿到班级名称 + int row = table->currentRow(); // 获取当前选中行 + if (cls.isEmpty() || row < 0) + return; - for (const Student &stu : students) + if (QMessageBox::question(this, "确认", "删除该学生?") == QMessageBox::Yes) { - QList row; - row << new QStandardItem(stu.id) - << new QStandardItem(stu.name) - << new QStandardItem(QString::number(stu.score)); - model->appendRow(row); + classData[cls].removeAt(row); + refreshTable(); } } + +void MainWindow::tableItemClicked(int row, int) // 点击学生信息进行回显 +{ + QString cls = currentClass(); + if (cls.isEmpty()) + return; + auto s = classData[cls][row]; + + nameEdit->setText(s.name); + genderEdit->setText(s.gender); + ageEdit->setText(QString::number(s.age)); + idEdit->setText(s.id); + phoneEdit->setText(s.phone); +} diff --git a/mainwindow.h b/mainwindow.h index ee0088b..d54f194 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -2,21 +2,21 @@ #define MAINWINDOW_H #include -#include -#include -#include +#include +#include #include #include -#include -#include -#include "student.h" +#include +#include -QT_BEGIN_NAMESPACE -namespace Ui +struct Student { - class MainWindow; -} -QT_END_NAMESPACE + QString name; + QString gender; + int age; + QString id; + QString phone; +}; class MainWindow : public QMainWindow { @@ -25,23 +25,51 @@ class MainWindow : public QMainWindow public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); + private slots: - void on_addButton_clicked(); - void on_deleteButton_clicked(); + // 班级管理 + void showTreeMenu(const QPoint &pos); + void addClass(); + void deleteClass(); + void renameClass(); + void onClassClicked(QTreeWidgetItem *item); + // 学生管理 + void addStudent(); + void deleteStudent(); +// void updateStudent(); +// void searchStudent(); + void tableItemClicked(int row, int column); + // 文件操作 与 分页 +// void importData(); +// void saveData(); +// void refreshAll(); +// void prevPage(); +// void nextPage(); private: - QVector students; // 学生信息列表 - QStandardItemModel *model; // 数据模型 + void setupUI(); + void refreshTable(); +// void saveClassToFile(const QString &className); + QString currentClass() const; - // 纯代码声明控件 - QTableView *tableView; - QLineEdit *idEdit; - QLineEdit *nameEdit; - QLineEdit *scoreEdit; +private: + // 顶部菜单栏 + QMenu *fileMenu; + QMenu *editMenu; + // 左侧班级树控件 + QTreeWidget *tree; + // 中间学生表格控件 + QTableWidget *table; - QPushButton *addButton; - QPushButton *deleteButton; + QLineEdit *nameEdit; + QLineEdit *genderEdit; + QLineEdit *ageEdit; + QLineEdit *idEdit; + QLineEdit *phoneEdit; - void refreshTable(); // 刷新表格显示 + QPushButton *addBtn; + QPushButton *delBtn; + // 班级数据存储 + QMap> classData; }; #endif // MAINWINDOW_H diff --git a/student.h b/student.h deleted file mode 100644 index f8a0603..0000000 --- a/student.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef STUDENT_H -#define STUDENT_H - -#include - -class Student -{ -public: - QString id; // 学号 - QString name; // 姓名 - double score; // 成绩 -}; - -#endif // STUDENT_H