Qt教程——從零開始的學生管理系統(文件)
一、項目設計
1、需求分析
記錄並處理學生成績信息。
1)添加新的學生數據;
2)根據學號對已有的學生數據進行修改;
3)根據學號刪除已存在的學生信息;
4)根據學號查詢學生信息;
5)根據各門成績與平均成績進行排序。
2、窗口設計
1)菜單窗口;
2)添加學生窗口;
3)修改信息窗口(包括刪除信息);
4)查詢學生窗口
5)排序窗口;
3、數據結構設計
以一個類StudentInfo儲存單個學生信息,學生類中包括:
姓名(字符串)
學號(整型)
數學成績(整型)
英語成績(整型)
C語言程序設計成績(整型)
平均成績(雙浮點數)
二、項目制作
1、建立項目
打開Qt Creator 文件->新建文件或項目(Ctrl+N)->其他項目->空的Qt項目(Empty qmacke Project)
2、添加窗口
將其命名為StudentManagementSystem_Qt一路下一步到結束。
右擊項目名稱->Add New->Qt -> Qt設計師界面模板選擇Widget下一步,我們當前建立的是菜單窗口,所以將其類名命名為MenuWidget一路下一步到結束。
以同樣的方式建立添加學生窗口:AddStudentWidget、修改信息窗口:ModifyWidget、查詢窗口:SelectWidget、排序窗口:SortWidget。
完成后的項目資源管理器頁面中應該有如下文件
我們可以看到Qt中建立模板為widget的設計師界面就是建立了一個c++類(繼承自QWidget)與其對應的ui文件 ,這個ui文件便是Qt Designer設計文件,它會在編譯時生成一個ui_*.h文件,這樣我們便可以用c++的方式對其進行調用。
Qt Designer的詳細使用方法可以看官方的手冊:https://doc.qt.io/archives/qt-4.8/designer-manual.html
之后打開我們的menuwidget.h,會發現其中存在錯誤。
這是因為我們的項目中沒有連接Qt Widgets庫,在StudentManagementSystem_Qt.pro中添加
QT += widgets
可解決問題。
3、實現窗口之間的切換
現在,就是實現我們新建立的幾個窗口之間的窗口切換問題的時候了,這里我打算使用QStackedLayout實現窗口切換。
QStackedLayout繼承自QLayout,提供了多頁面切換的布局,一次只能看到一個界面,在我的Qt5——從零開始的Hello World教程(Qt Creator) 中提到過,大部分控件都繼承自QFrame,而QFrame又繼承自QWidget,所以QStackedLayout完全可以實現窗口之間的切換。
現在我們用與上一步相同的方法建立一個窗口MainWidget。並添加一個main.cpp來寫main函數
在mainwidget.h中修改MainWidget的定義,為其添加成員
MenuWidget *menuwidget; //菜單窗口 AddStudentWidget *addstudentwidget; //添加學生窗口 SelectWidget *selectwidget; //查詢窗口 ModifyWidget *modifywidget; //修改窗口 SortWidget *sortwidget; //排序窗口 QStackedLayout *stackLayout; //QStackedLayout布局
當然,也需要引用其對應的頭文件。
#include <QStackedLayout> #include "menuwidget.h" #include "addstudentwidget.h" #include "selectwidget.h" #include "modifywidget.h" #include "sortwidget.h"
在MainWidget.cpp中將MainWidget設為stackLayout布局,聲明我們需要的窗口,並將其加入stackLayout布局中去。
在MainWidget.cpp中顯示調用MainWidget構造函數。
MainWidget::MainWidget(QWidget *parent) : QWidget(parent), ui(new Ui::MainWidget) { ui->setupUi(this); }
處添加。
menuwidget = new MenuWidget; addstudentwidget = new AddStudentWidget; selectwidget = new SelectWidget; modifywidget = new ModifyWidget; sortwidget = new SortWidget; stackLayout = new QStackedLayout; stackLayout->addWidget(menuwidget); stackLayout->addWidget(addstudentwidget); stackLayout->addWidget(selectwidget); stackLayout->addWidget(modifywidget); stackLayout->addWidget(sortwidget); setLayout(stackLayout);
之后就需要使用Qt designer 設計頁面了(當然在對應類中手動添加成員控件也沒有任何問題)。
雙擊menuwidget.ui就打開了設計頁面
在menuwidget中添加如下按鈕(push button)
以同樣的方法在addstudentwidget,selectwidget,modifywidget,sortwidget中都添加一個返回按鈕returnButton。
為這些按鈕設計點擊槽函數。
menuwidget.h: private slots: void on_addButton_clicked(); void on_selectButton_clicked(); void on_modifyButton_clicked(); void on_sortButton_clicked(); void on_exitButton_clicked();
還需要一個方法作為stackLayout切換頁面的信號
signals: void display(int number);
在menuwidget.cpp中給出函數定義
void MenuWidget::on_addButton_clicked(){ emit display(1); } void MenuWidget::on_selectButton_clicked(){ emit display(2); } void MenuWidget::on_modifyButton_clicked(){ emit display(3); } void MenuWidget::on_sortButton_clicked(){ emit display(4); } void MenuWidget::on_exitButton_clicked(){ QApplication::exit(); }
emit 把connect把信號和槽進行關聯,emit某個信號,就相當於調用這個信號connect時所關聯的槽函數。至於更多關於 emit信息諸位可以搜索或者看幫助文檔。
之后為addstudentwidget,selectwidget,modifywidget,sortwidget窗口中的按鈕設計信號與槽函數
在(類名).h中添加
signals: void display(int number); private slots: void on_returnButton_clicked();
在(類名).cpp中添加
void (類名)::on_returnButton_clicked(){ emit display(0); }
現在可以使用的只有退出按鈕,跳轉按鈕還需要在mainwidget.cpp中用connect函數連接。
到此為止便完成了頁面切換功能。
到次為止的源碼:
https://github.com/suvvm/StudentManagementSystem_Qt/tree/master/StudentManagementSystem_Qt
4、完善窗口設計
1:AddStudentWidget
我們需要提示標簽來指明輸入的數據,也需要輸入框來接收用戶的輸入,QLabel與QLineEdit可以滿足我們的要求。
QLabel,QLineEdit有方法setText(“內容”)來改變其顯示的文字,有方法setGeometry (起始橫坐標,起始縱坐標,寬, 高)來設置左上角起始位置與大小。
當然這些都可以在Qt Designer中直接設置。打開addstudentwidget.ui。
根據之前設計的數據結構,需要nameLineEdit、idLineEdit、mathLineEdit、enLineEdit、cLineEdit五個QLineEdit接收學生的姓名、學號、數學成績、英語成績、C語言成績(平均成績由計算得出),需要nameLabel、idLabel、mathLabel、enLabel、cLabel五個QLabel提醒用戶輸入數據,需要addButton 一個QPushButton來添加學生。
最終將addstudentwidget頁面設計為。
2:modifyWidget
我們需要nameLineEdit、idLineEdit、mathLineEdit、enLineEdit、cLineEdit五個QLineEdit接收學生的姓名、學號、數學成績、英語成績、C語言成績(平均成績由計算得出),需要nameLabel、idLabel、mathLabel、enLabel、cLabel五個QLabel提醒用戶輸入數據,需要deleteButton、modifyButton 兩個QPushButton來根據學號刪除學生,和根據學號修改學生信息。
3:selectwidget
我們需要idLabel一個QLabel提醒用戶輸入數據,需要idLineEdit一個QLineEdit接收學生的學號,之后需要nameLabel、avgLabel、mathLabel、enLabel、cLabel五個QLabel提醒用戶顯示的數據,需要showNameLabel、showMathLabel、showEnLabel、showCLabel、showAvgLabel五個QLabel來接收查詢到的數據,需要selectButton一個QPushButton來提交查詢。
4:sortwidget
QRadioButton單選框可以解決我們的排序根據選擇問題
(當然,許多方法都可以,這里只演示QRadioButton)
QTableWidget表格可以用來顯示排序后的信息。
我們需要mathRadioButton、enRadioButton、cRadioButton、avgRadioButton四個QRadioButton來選擇排序的根據,需要sortButton一個QPushButton來提交排序,需要tableWidget一個 QTableWidget來顯示排序結果。
到此為止的源碼:
https://github.com/suvvm/StudentManagementSystem_Qt/tree/master/StudentManagementSystem_Qt_1(uiOnly)
5、完成學生類的設計
之前在數據結構設計中我們已經設計好了,以一個類StudentInfo儲存單個學生信息,學生類中包括:
姓名(字符串)
學號(整型)
數學成績(整型)
英語成績(整型)
C語言程序設計成績(整型)
平均成績(雙浮點數)
現在着手去實現它
右擊項目Add New選擇C++ C++Class 為它起名叫StudentInfo之后下一步到完成,在studentinfo.h中為其創建對應的私有變量,及其對應的get與set函數。
studentinfo.h
class StudentInfo { private: QString name; int id, math, english, languageC; double avg; public: StudentInfo(); StudentInfo(QString tname, int tid, int tmath, int tenglish, int tlanguageC){ name = tname; id = tid; math = tmath; english = tenglish; languageC = tlanguageC; avg = (tmath + tenglish + tlanguageC) / 3.0; } int getId(){ return id; } QString getName(){ return name; } int getMath(){ return math; } int getEnglish(){ return english; } int getLanguageC(){ return languageC; } double getAvg(){ return avg; } void setId(int tid){ id = tid; } void setName(QString tname){ name = tname; } void setMath(int tmath){ math = tmath; avg = (math + english + languageC) / 3.0; } void setEnglish(int tenglish){ english = tenglish; avg = (math + english + languageC) / 3.0; } void setLanguageC(int tlanguageC){ languageC = tlanguageC; avg = (math + english + languageC) / 3.0; } };
6、完善添加學生信息
打開addstudentwidget.h為”添加”按鈕設計點擊槽函數,由於我們設計用文件對學生信息進行儲存,所以需要引用QFile,這里我使用對話框來提示用戶操作中的各種問題,所以需要引入QMessageBox。
QMessageBox中有很多類型的對話框,各對話框的用法這里就不詳細介紹了,這里我們只介紹我們即將用到的QMessageBox::about
QMessageBox::about(NULL, "About", "About this application");
其中三個參數分別對應,父窗口對象, 對話框標題, 對話框內容。
在addstudentwidget.cpp中給出函數定義:
在lineEdit中取出用戶輸入的數據,lineEdit擁有text()方法,會返回一個QString,而QString中又擁有入toInt() toDouble()等各種類型轉換函數,可以適應我們的大多數要求。
打開數據文件將我們剛剛獲取的數據追加在文件結尾。
addstudentwidget.h
#ifndef ADDSTUDENTWIDGET_H #define ADDSTUDENTWIDGET_H #include <QWidget> #include <QFile> #include <QMessageBox> #include <QDebug> namespace Ui { class AddStudentWidget; } class AddStudentWidget : public QWidget { Q_OBJECT public: explicit AddStudentWidget(QWidget *parent = nullptr); ~AddStudentWidget(); private: Ui::AddStudentWidget *ui; signals: void display(int number); private slots: void on_returnButton_clicked(); void on_addButton_clicked(); }; #endif // ADDSTUDENTWIDGET_H
addstudentwidget.cpp
#include "addstudentwidget.h" #include "ui_addstudentwidget.h" AddStudentWidget::AddStudentWidget(QWidget *parent) : QWidget(parent), ui(new Ui::AddStudentWidget) { ui->setupUi(this); } AddStudentWidget::~AddStudentWidget() { delete ui; } void AddStudentWidget::on_returnButton_clicked(){ //"主菜單"按鈕點擊 emit display(0); } void AddStudentWidget::on_addButton_clicked(){ //"添加"按鈕點擊 QString name = ui->nameLineEdit->text(); //將用戶輸入的姓名由nameLineEdit取出 int id = ui->idLineEdit->text().toInt(); //將用戶輸入的學號由idLineEdit取出,並轉換為整型 int math = ui->mathLineEdit->text().toInt(); //將用戶輸入的學號由mathLineEdit取出,並轉換為整型 int english = ui->enLineEdit->text().toInt(); //將用戶輸入的學號由enLineEdit取出,並轉化為整型 int languageC = ui->cLineEdit->text().toInt(); //將用戶輸入的學號由cLineEdit取出,並轉化為整型 if(ui->nameLineEdit->text() == "" || ui->idLineEdit->text() == "" || ui->mathLineEdit->text() == "" || ui->enLineEdit->text() == "" || ui->cLineEdit->text() == ""){ //插入的五項數據都不能為空,否則在讀取文件時會出現問題。 QMessageBox::about(NULL, "反饋", "存在空項"); } QFile file("student.txt"); //實例化一個QFile file為我們的數據文件student.txt file.open(QIODevice::WriteOnly|QIODevice::Text|QIODevice::Append); //open()可以用來打開文件這里QIODevice::WriteOnly代表將文件以只寫的方式打開 //QIODevice::Text代表我們打開的是文本文件,QIODevice::Text會對end-of-line結束符進行轉譯 //QIODevice::Append以追加的方式打開,新增加的內容將被追加到文件末尾 if(!file.isOpen()){ //如果數據文件沒有打開,彈出對話框提示用戶 QMessageBox::about(NULL, "反饋", "數據文件打開失敗"); return; } QTextStream out(&file); //QTextStream可以進行一些基本的文本讀寫,比如QString int char之類的數據QDataStream可以進行一個如QMap QPoint之類數據的讀寫。 out << name << " " << id << " " << math << " " << english << " " << languageC; //將我們剛剛獲取的數據寫入文件 file.close(); QMessageBox::about(NULL, "反饋", "插入成功"); ui->nameLineEdit->clear(); ui->idLineEdit->clear(); ui->mathLineEdit->clear(); ui->enLineEdit->clear(); ui->cLineEdit->clear(); //將用戶輸入的數據清空 }
運行一下
顯示插入成功,打開項目文件夾所在目錄build-StudentManagementSystem開頭的文件夾,我們的數據文件student就會出現在此處
打開看一看
這樣,我們的添加信息模塊就完成了。
以上源代碼:
https://github.com/suvvm/StudentManagementSystem_Qt/tree/master/StudentManagementSystem_Qt_2(add)
7、完善修改信息
打開modifywidget.h為”刪除”與”修改”按鈕設計點擊槽函數,在modifywidget.cpp中給出函數定義。
對於刪除和修改操作這里我打算以文件中的數據建立一個數據類型為StudentInfo的QVector容器,容器中盛放全體學生信息。對容器進行刪改操作,最后以容器內的數據覆蓋原有的數據即可。
modifywidget.h
#ifndef MODIFYWIDGET_H #define MODIFYWIDGET_H #include <QWidget> #include <QFile> #include <QMessageBox> #include <QtDebug> #include <QVector> #include "studentinfo.h" namespace Ui { class ModifyWidget; } class ModifyWidget : public QWidget { Q_OBJECT public: explicit ModifyWidget(QWidget *parent = nullptr); ~ModifyWidget(); private: Ui::ModifyWidget *ui; signals: void display(int number); private slots: void on_returnButton_clicked(); //點擊主菜單按鈕 void on_deleteButton_clicked(); //點擊刪除按鈕 void on_modifyButton_clicked(); //點擊修改按鈕 }; #endif // MODIFYWIDGET_H
modifywidget.cpp
#include "modifywidget.h" #include "ui_modifywidget.h" ModifyWidget::ModifyWidget(QWidget *parent) : QWidget(parent), ui(new Ui::ModifyWidget) { ui->setupUi(this); } ModifyWidget::~ModifyWidget() { delete ui; } void ModifyWidget::on_returnButton_clicked(){ emit display(0); } void ModifyWidget::on_deleteButton_clicked(){ QVector<StudentInfo> allStudentInfo; //數據類型為StudentInfo的QVector容器 if(ui->idLineEdit->text() == ""){ //如果id輸入欄為空則輸出錯誤提示並返回 QMessageBox::about(NULL, "反饋", "id不得為空!"); return; } QFile file("student.txt"); file.open(QIODevice::ReadOnly|QIODevice::Text); //以只讀 的方式打開文本文件 if(!file.isOpen()){ //如果數據文件沒有打開,彈出對話框提示用戶 QMessageBox::about(NULL, "反饋", "數據文件打開失敗"); return; } //QIODevice::Truncate在寫入時會從文件開始處寫入,覆蓋原有內容 QTextStream inp(&file); //以file建立一個QT的文本流 while(!inp.atEnd()){ QString name; int id, math, english, languageC; inp >> name >> id >> math >> english >> languageC; //讀入姓名 學號 數學成績 英語成績 C語言成績 allStudentInfo.push_back(StudentInfo(name, id, math, english, languageC)); //調用之前建立的構造函數實例化一個StudentInfo對象並將其加入allStudentInfo } allStudentInfo.pop_back(); //文件最后會多讀一個無用數據,將其拿出 file.close(); int id = ui->idLineEdit->text().toInt(); //獲取用戶輸入的id bool flag = false; //記錄是否進行過刪除 for(QVector<StudentInfo>::iterator it = allStudentInfo.begin(); it != allStudentInfo.end(); it++){ //用迭代器遍歷allStudentInfo if(it->getId() == id){ //如果找到有id與該id相同的學生,就進行刪除 allStudentInfo.erase(it); flag = true; } } if(flag){ //如果進行過刪除,彈出對話框並更新文件 QMessageBox::about(NULL, "反饋", "刪除成功"); file.open(QIODevice::WriteOnly|QIODevice::Text|QIODevice::Truncate); //以只寫覆蓋的方式打開文本文件 if(!file.isOpen()){ //如果數據文件沒有打開,彈出對話框提示用戶 QMessageBox::about(NULL, "反饋", "數據文件打開失敗"); return; } QTextStream out(&file); for(auto i : allStudentInfo){ out << i.getName() << " " << i.getId() << " " << i.getMath() << " " << i.getEnglish() << " " << i.getLanguageC() << endl; } file.close(); }else{ //如果沒有進行刪除,彈出不存在對話框 QMessageBox::about(NULL, "反饋", "id不存在!"); } //關閉文件 ui->idLineEdit->clear(); //清空id輸入框 } void ModifyWidget::on_modifyButton_clicked(){ if(ui->nameLineEdit->text() == "" || ui->idLineEdit->text() == "" || ui->mathLineEdit->text() == "" || ui->enLineEdit->text() == "" || ui->cLineEdit->text() == ""){ QMessageBox::about(NULL, "反饋", "存在空項"); return; } QVector<StudentInfo> allStudentInfo; //數據類型為StudentInfo的QVector容器 QFile file("student.txt"); file.open(QIODevice::ReadOnly|QIODevice::Text); //以只讀 的方式打開文本文件 if(!file.isOpen()){ //如果數據文件沒有打開,彈出對話框提示用戶 QMessageBox::about(NULL, "反饋", "數據文件打開失敗"); return; } //QIODevice::Truncate在寫入時會從文件開始處寫入,覆蓋原有內容 QTextStream inp(&file); //以file建立一個QT的文本流 while(!inp.atEnd()){ QString name; int id, math, english, languageC; inp >> name >> id >> math >> english >> languageC; //讀入姓名 學號 數學成績 英語成績 C語言成績 allStudentInfo.push_back(StudentInfo(name, id, math, english, languageC)); //調用之前建立的構造函數實例化一個StudentInfo對象並將其加入allStudentInfo } allStudentInfo.pop_back(); //文件最后會多讀一個無用數據,將其拿出 file.close(); int id = ui->idLineEdit->text().toInt(); QString name = ui->nameLineEdit->text(); int math = ui->mathLineEdit->text().toInt(); int english = ui->enLineEdit->text().toInt(); int languageC = ui->cLineEdit->text().toInt(); bool flag = false; for(QVector<StudentInfo>::iterator it = allStudentInfo.begin(); it != allStudentInfo.end(); it++){ if(it->getId() == id){ it->setName(name); it->setMath(math); it->setEnglish(english); it->setLanguageC(languageC); flag = true; } } if(flag){ //如果進行過修改,彈出對話框並更新文件 QMessageBox::about(NULL, "反饋", "修改成功"); file.open(QIODevice::WriteOnly|QIODevice::Text|QIODevice::Truncate); //以只寫覆蓋的方式打開文本文件 if(!file.isOpen()){ //如果數據文件沒有打開,彈出對話框提示用戶 QMessageBox::about(NULL, "反饋", "數據文件打開失敗"); return; } QTextStream out(&file); for(auto i : allStudentInfo){ out << i.getName() << " " << i.getId() << " " << i.getMath() << " " << i.getEnglish() << " " << i.getLanguageC() << endl; } file.close(); }else{ //如果沒有進行修改,彈出不存在對話框 QMessageBox::about(NULL, "反饋", "id不存在!"); } //關閉文件 ui->idLineEdit->clear(); ui->nameLineEdit->clear(); ui->mathLineEdit->clear(); ui->enLineEdit->clear(); ui->cLineEdit->clear(); //清空所有輸入框 }
這樣,修改模塊就完成了
以上源代碼:
8、查詢模塊
打開selectwidget.h為”刪除”與”修改”按鈕設計點擊槽函數,在selectwidget.cpp中給出函數定義。
查詢可以在從文件讀取時判斷是否會讀取到id為輸入id的學生,也可以向修改一樣江所有學生信息先讀入到數據類型為StudentInfo的QVector容器中,在從容器中查詢數據,這里我選擇讀入到容器的方法。
selectwidget.h
#ifndef SELECTWIDGET_H #define SELECTWIDGET_H #include <QWidget> #include <QtDebug> #include <QFile> #include <QVector> #include <QMessageBox> #include "studentinfo.h" namespace Ui { class SelectWidget; } class SelectWidget : public QWidget { Q_OBJECT public: explicit SelectWidget(QWidget *parent = nullptr); ~SelectWidget(); private: Ui::SelectWidget *ui; signals: void display(int number); private slots: void on_returnButton_clicked(); void on_selectButton_clicked(); }; #endif // SELECTWIDGET_H
selectwidget.cpp
#include "selectwidget.h" #include "ui_selectwidget.h" SelectWidget::SelectWidget(QWidget *parent) : QWidget(parent), ui(new Ui::SelectWidget) { ui->setupUi(this); } SelectWidget::~SelectWidget() { delete ui; } void SelectWidget::on_returnButton_clicked(){ emit display(0); } void SelectWidget::on_selectButton_clicked(){ if(ui->idLineEdit->text() == ""){ QMessageBox::about(NULL, "反饋", "id不能為空"); return; } QFile file("student.txt"); file.open(QIODevice::ReadOnly|QIODevice::Text); //以只讀的方式打開文本文件 if(!file.isOpen()){ //文件打開失敗 QMessageBox::about(NULL, "反饋", "文件打開失敗"); return; } QTextStream inp(&file); //以file作為Qt文本流 QVector<StudentInfo> allStudentInfo; //數據類型為StudentInfo的QVector容器 while(!inp.atEnd()){ //讀到文件結尾 QString name; int id, math, english, languageC; inp >> name >> id >> math >> english >> languageC; allStudentInfo.push_back(StudentInfo(name, id, math, english, languageC)); //調用之前建立的構造函數實例化一個StudentInfo對象並將其加入allStudentInfo } allStudentInfo.pop_back(); //扔掉最后的無用數據 file.close(); //關閉文件 int id = ui->idLineEdit->text().toInt(); bool flag = false; for(auto i : allStudentInfo){ if(i.getId() == id){ ui->showNameLabel->setText(i.getName()); ui->showMathLabel->setText(QString::number(i.getMath())); ui->showEnLabel->setText(QString::number(i.getEnglish())); ui->showCLabel->setText(QString::number(i.getLanguageC())); ui->showAvgLabel->setText(QString::number(i.getAvg())); flag = true; break; } } if(!flag){ QMessageBox::about(NULL, "反饋", "id不存在!"); } ui->idLineEdit->clear(); }
以上源代碼
9、排序模塊
老樣子,將數據從文件中讀入數據類型為StudentInfo的QVector容器后進行排序就容易很多了。
我們需要排序時只能根據數學、英語、C語言、平均成績中的一種進行排序,所以我們要做到代表這四種排序方式的QRedioButton有且只有一個能被選中,我們可以將其加入一個QButtonGroup,這樣便可以實現這個需求,至於顯示排序后的數據我們可以顯示在表格控件QTableWidget中。
QButtonGroup直接繼承自QObject,他有一個屬性exclusive當這個屬性為真時,所有在QButtonGroup內的按鈕同一時間只有一個可以被選擇。
QButtonGroup我們用到了addButton添加按鈕 與checkedId獲取選中按鈕的id兩個方法,其他方法諸位可以自己去搜索。
QTableWidget繼承自QTableView,QTableView可以自定義的數據模型顯示內容(setModel)但是QTableWidget不行,QTableWidget有固定的數據模型,在像其中填入數據時只需要一個單元格一個單元格的填好就可以了(setItem)
QTableWidget我們用到了setHorizontalHeaderLabels設置水平表頭標簽horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); 設置根據總寬度調整列寬;setRowCount設置行數;setItem設置單元格,其他方法諸位可以自己去搜索。
sortwidget.h
#ifndef SORTWIDGET_H #define SORTWIDGET_H #include <QWidget> #include <QButtonGroup> #include <QVector> #include <QFile> #include <QDebug> #include <QMessageBox> #include "studentinfo.h" namespace Ui { class SortWidget; } class SortWidget : public QWidget { Q_OBJECT public: explicit SortWidget(QWidget *parent = nullptr); ~SortWidget(); private: Ui::SortWidget *ui; QButtonGroup *sortButtonGroup; signals: void display(int number); private slots: void on_returnButton_clicked(); //返回菜單 void on_sortButton_clicked(); //排序 }; #endif // SORTWIDGET_H
sortwidget.cpp
#include "sortwidget.h" #include "ui_sortwidget.h" #include <algorithm> SortWidget::SortWidget(QWidget *parent) : QWidget(parent), ui(new Ui::SortWidget) { ui->setupUi(this); sortButtonGroup = new QButtonGroup(); //實例化sortButtonGroup sortButtonGroup->addButton(ui->mathRadioButton, 0); //將代表數學的單選框加入sortButtonGroup並將其id設為0 //不建議使用默認id,默認id是由-2開始依次遞減的 sortButtonGroup->addButton(ui->enRadioButton, 1); //將代表英語的單選框加入sortButtonGroup並將其id設為1 sortButtonGroup->addButton(ui->cRadioButton, 2); //將代表C語言的單選框加入sortButtonGroup並將其id設為2 sortButtonGroup->addButton(ui->avgRadioButton, 3); //將代表平均的單選框加入sortButtonGroup並將其id設為3 ui->avgRadioButton->setChecked(true); //平均成績默認選中 ui->tableWidget->setColumnCount(6); QStringList headerLabels; //QStringList headerLabels用來記錄表格表頭數據 headerLabels << tr("姓名") << tr("學號") << tr("數學") << tr("英語") << tr("C語言") << tr("平均"); ui->tableWidget->setHorizontalHeaderLabels(headerLabels); // void setHorizontalHeaderLabels(const QStringList &labels);設置水平表頭標簽 ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); //設置根據總寬度調整列寬 ui->tableWidget->setRowCount(1); //初始行數設為一行 } SortWidget::~SortWidget() { delete ui; } void SortWidget::on_returnButton_clicked(){ emit display(0); } bool getStudentInfo(QVector<StudentInfo> &allStudentInfo){ //讀取信息成功返回true 否則返回false QFile file("student.txt"); file.open(QIODevice::ReadOnly|QIODevice::Text); //以只讀方式打開文本文件student.txt QTextStream inp(&file); if(!file.isOpen()){ //文件打開失敗 QMessageBox::about(NULL, "反饋", "數據文件打開失敗"); return false; } while(!inp.atEnd()){ //讀到文件結尾 QString name; int id, math, english, languageC; inp >> name >> id >> math >> english >> languageC; allStudentInfo.push_back(StudentInfo(name, id, math, english, languageC)); //調用之前聲明的構造函數實例化一個StudentInfo對象並將其加入allStudentInfo } allStudentInfo.pop_back(); //扔掉最后的無用數據 file.close(); //關閉文件 return true; } bool cmp_math(StudentInfo a, StudentInfo b){ //數學排序 return a.getMath() > b.getMath(); } bool cmp_English(StudentInfo a, StudentInfo b){ //英語排序 return a.getEnglish() > b.getEnglish(); } bool cmp_languageC(StudentInfo a, StudentInfo b){ //C語言排序 return a.getLanguageC() > b.getLanguageC(); } bool cmp_avg(StudentInfo a, StudentInfo b){ //平均成績排序 return a.getAvg() > b.getAvg(); } void SortWidget::on_sortButton_clicked(){ ui->tableWidget->clearContents(); //清空除表頭外的所有數據 //若想清除表頭可使用clear() int sortTag = sortButtonGroup->checkedId(); //取得當前選中的單選框的id QVector<StudentInfo> allStudentInfo; //數據類型為StudentInfo的QVector容器 if(!getStudentInfo(allStudentInfo)) //從文件讀取數據到allStudentInfo return; //讀取失敗直接返回 if(allStudentInfo.empty()){ //allStudentInfo中沒有數據 QMessageBox::about(NULL, "反饋", "沒有學生信息"); return; } switch (sortTag) { case 0: //sortTag==0根據數學進行排序 std::sort(allStudentInfo.begin(), allStudentInfo.end(), cmp_math); break; case 1: //sortTag==1根據英語進行排序 std::sort(allStudentInfo.begin(), allStudentInfo.end(), cmp_English); break; case 2: //sortTag==2根據C語言進行排序 std::sort(allStudentInfo.begin(), allStudentInfo.end(), cmp_languageC); break; case 3: //sortTag==3根據平均成績進行排序 std::sort(allStudentInfo.begin(), allStudentInfo.end(), cmp_avg); break; } ui->tableWidget->setRowCount(allStudentInfo.size()); //將表格的行數設為與學生數量相同 //否則setItem添加單元格不會生效 for(int i = 0; i < allStudentInfo.size(); i++){ ui->tableWidget->setItem(i, 0, new QTableWidgetItem(allStudentInfo[i].getName())); ui->tableWidget->setItem(i, 1, new QTableWidgetItem(QString::number(allStudentInfo[i].getId()))); ui->tableWidget->setItem(i, 2, new QTableWidgetItem(QString::number(allStudentInfo[i].getMath()))); ui->tableWidget->setItem(i, 3, new QTableWidgetItem(QString::number(allStudentInfo[i].getEnglish()))); ui->tableWidget->setItem(i, 4, new QTableWidgetItem(QString::number(allStudentInfo[i].getLanguageC()))); ui->tableWidget->setItem(i, 5, new QTableWidgetItem(QString::number(allStudentInfo[i].getAvg()))); //設置各單元格的數據,非QString類型的數據需要轉換為QString } }
到此為止我們整個項目便完成了,以后可能還會繼續完善。
源代碼
https://github.com/suvvm/StudentManagementSystem_Qt/tree/master/StudentManagementSystem_Qt_5(all)