• c++小学期大作业攻略(三)用户系统


    Update

      at 2019/07/22 14:16

      发现一个大坑,我们后期是打算用QSS统一堆样式进行美化的,于是我把之前对QLabel进行的setAlignment全部去掉了,打算统一丢进Qss里面,一下子使程序简洁了很多。但是发现QLabel在QSS里面不支持text-align,也找不到其他将其设置为居中的接口。暂时的解决方案是新建一个QLabelCenter类,完全从QLabel继承,但是构造函数里面加上setAlignment。

      附一段加载qss的代码:

    void Translation::LoadQss(const QString sRoad){
        QFile fQss(sRoad);
        fQss.open(QFile::ReadOnly);
        setStyleSheet(fQss.readAll());
        fQss.close();
    }

      sRoad是qss文件的路径。

      

      


      感觉自己花了两天时间完成了一下午的工作量,基本上都是单纯地堆代码,没有什么技术性比较强的活,所以这篇巨水无比。我现在主要的参考资料已经变成官方的手册了:

      https://doc.qt.io/qt-5/classes.html

      目前正在一步一步朝着GMA的样式前进。

      

      用户的存储是在全局的位置放了std::vector<User> g_Users,下面是遍历这个vector的一种比较优雅的做法:

      std::vector<User>::iterator itUserTemp;
      for (itUserTemp = g_Users.begin(); itUserTemp != g_Users.end(); itUserTemp++) {
        //itUserTemp->GetNickname()....   }

      

      

     1. Register

      

      这里的样式结构非常简单,画面整体是竖向排列的,里面再套一个横向排列用来放提示和输入框。文字输入用的是QLineEdit,下拉列表选项用的是QComboBox。

      按照我的写法,Register类中需要存储一下被输入的QLineEdit的指针,还有Register的父元素MainWindow的指针,响应的槽函数放在Register中,这样响应函数可以调用MainWindow的切换界面函数。

      ^_^

    QWidget* Register::ShowInformation(bool Show) {
        QWidget* pwBox = new QWidget();
        QVBoxLayout* pvLayout = new QVBoxLayout(pwBox);
    
        //CreateLineInput是预先写好的一个函数,返回一个QWidget,里面横向放了一个QLabel和一个QLineEdit
        //m_pleNickname会变成一个指向QLineEdit的指针
        pvLayout->addWidget(CreateLineInput(STR_TIP_NICKNAME, m_pleNickname, Show));
        m_pleNickname->setMaxLength(20);
    
        pvLayout->addWidget(CreateLineInput(STR_TIP_PASSWORD, m_plePassword, Show));
        m_plePassword->setEchoMode(QLineEdit::Password);
        m_plePassword->setMaxLength(40);
    
        pvLayout->addWidget(CreateLineInput(STR_TIP_PASSWORDCON, m_plePasswordCon, Show));
        m_plePasswordCon->setEchoMode(QLineEdit::Password);
        m_plePasswordCon->setMaxLength(40);
    
        pvLayout->addWidget(CreateLineInput(STR_TIP_AGE, m_pleAge, Show));
    
        //CreateGenderInput跟CreateLineInput类似
        pvLayout->addWidget(CreateGenderInput(STR_TIP_AGE, m_pleGender, Show));
    
        return pwBox;
    }
    void Register::Init() {
        QVBoxLayout *pvlLayout = new QVBoxLayout(this);//整体竖向排版
    
        QLabel* plMainTitle = new QLabel(this);
        plMainTitle->setText(STR_MAINTITLE_REGISTER);//主标题
        plMainTitle->setAlignment(Qt::AlignCenter);
        pvlLayout->addWidget(plMainTitle, INT_SIZERATE_MAINTITAL);//主标题加入整体的竖向排版
    
        pvlLayout->addWidget(ShowInformation(), INT_SIZERATE_INFORMATION);//调用函数,获得一个QWidget,加进主排版
    
    
    
        //按钮部分
        QWidget* pwButton = new QWidget(this);
        QHBoxLayout* phlButton = new QHBoxLayout(pwButton);
        QPushButton* ppbRegister = new QPushButton(pwButton);
        ppbRegister->setText(STR_BUTTON_REGISTER);
        phlButton->addWidget(ppbRegister, INT_SIZERATE_BUTTON_REGISTER);
    
    
        pvlLayout->addWidget(pwButton, INT_SIZERATE_BUTTON);
    
    
    
        connect(ppbRegister, SIGNAL(clicked(bool)), this, SLOT(RegisterRequest()));
    }
    View Code

    2. Login

      

      和Register非常相似,用一个User* g_pCurrentUser来指向当前的已登录用户。

      

      

      ^_^

    QWidget* Login::ShowInformation(bool Show) {
        QWidget* pwBox = new QWidget();
        QVBoxLayout* pvLayout = new QVBoxLayout(pwBox);
    
        //CreateLineInput是写好的一个创建输入提示和输入框的函数
        pvLayout->addWidget(CreateLineInput(STR_TIP_NICKNAME, m_pleNickname, Show));
        pvLayout->addWidget(CreateLineInput(STR_TIP_PASSWORD, m_plePassword, Show));
        m_plePassword->setEchoMode(QLineEdit::Password);
        return pwBox;
    }
    void Login::Init() {
        //竖直布局
        QVBoxLayout *pvlLayout = new QVBoxLayout(this);
    
        //加入主标题
        pvlLayout->addWidget(new QLabelCenter(STR_MAINTITLE_LOGIN), INT_SIZERATE_MAINTITAL);
    
        //加入输信息模块
        pvlLayout->addWidget(ShowInformation(), INT_SIZERATE_INFORMATION);
    
    
        //加入按钮模块
        QPushButton* ppbLogin = new QPushButton(STR_BUTTON_LOGIN);
        connect(ppbLogin, SIGNAL(clicked(bool)), this, SLOT(LoginRequest()));
        pvlLayout->addWidget(ppbLogin, INT_SIZERATE_BUTTON_LOGIN);
    
        QPushButton* ppbRegister = new QPushButton(STR_BUTTON_REGISTER);
        connect(ppbRegister, SIGNAL(clicked(bool)), this, SLOT(RegisterRequest()));
        pvlLayout->addWidget(ppbRegister, INT_SIZERATE_BUTTON_REGISTER);
    }
    View Code

    3. Database

      我们需要在程序开启时从数据库加载表里的用户,程序关闭时把相关数据存入数据库。

      我专门写了一个Database类,初始化时传入地址、账号、密码之类的初始信息,当然为了方便你也可以把数据库写成全局的函数,初始信息写死。

      每次存数据先把数据库里的表清空:TRUNCATE Users,然后再逐个用户INSERT INTO Users。取数据直接SELECT即可。

      后来听说直接清空之后存数据给的分会低,已有的数据只进行update效率比较高,mark起来以后改

      ^_^

    //存数据
    void Database::SaveData(std::vector<User>& Users) {
        MYSQL MysqlTemp;
        MYSQL* pSock;
        mysql_init(&MysqlTemp);
        if ((pSock = mysql_real_connect(&MysqlTemp, HOST, USERNAME, PASSWORD, DB, PORT, UNIX_SOCKET, CLIENT_FLAG)) == nullptr) {
    #ifdef DEBUG_MOD
            qDebug() << "Fail to connect mysql.
    ";
            qDebug() << mysql_error(&MysqlTemp) << endl;
    #endif
            return;
        }
    
        std::string sQuery;
        if (mysql_query(&MysqlTemp, "TRUNCATE Users") != 0) {
    #ifdef DEBUG_MOD
            qDebug() << "Fail to query : " << QString::fromStdString(sQuery) << endl;
    #endif
        }
    
        std::vector<User>::iterator itUserTemp;
    #ifdef DEBUG_MOD
        qDebug() << "Save : " << Users.size() << endl;
    #endif
        for (itUserTemp = Users.begin(); itUserTemp != Users.end(); itUserTemp++) {
            //设置好语句
            sQuery = "INSERT INTO Users (ID, Nickname, Password, Introduction, Certificate, Gender, Age, Score) VALUES (";
            sQuery += std::to_string(itUserTemp->GetId()) + ", ";
            sQuery += "'" + itUserTemp->GetNickname() + "', ";
            sQuery += "'" + itUserTemp->GetPassword() + "', ";
            sQuery += "'" + itUserTemp->GetIntroduction() + "', ";
            sQuery += "'" + itUserTemp->GetCertificate() + "', ";
            sQuery += std::to_string(int(itUserTemp->GetGender())) + ", ";
            sQuery += std::to_string(itUserTemp->GetAge()) + ", ";
            sQuery += std::to_string(itUserTemp->GetScore()) + ")";
    
            if (mysql_query(&MysqlTemp, sQuery.data()) != 0) {
    #ifdef DEBUG_MOD
                qDebug() << "Fail to query : " << QString::fromStdString(sQuery) << endl;
    #endif
            }
        }
        mysql_close(pSock);
    }
    
    //取数据
    void Database::LoadData(std::vector<User>& Users) {
        MYSQL MysqlTemp;
        MYSQL* pSock;
        mysql_init(&MysqlTemp);
        if ((pSock = mysql_real_connect(&MysqlTemp, HOST, USERNAME, PASSWORD, DB, PORT, UNIX_SOCKET, CLIENT_FLAG)) == nullptr) {
    #ifdef DEBUG_MOD
            qDebug() << "Fail to connect mysql.
    ";
            qDebug() << mysql_error(&MysqlTemp) << endl;
    #endif
            return;
        }
        std::string sQuery = "SELECT ID, Nickname, Password, Introduction, Certificate, Gender, Age, Score FROM Users";
        if (mysql_query(&MysqlTemp, sQuery.data()) != 0){
    #ifdef DEBUG_MOD
            qDebug() << "Fail to query : " << QString::fromStdString(sQuery) << endl;
    #endif
            return;
        }
        MYSQL_RES * result;
        MYSQL_ROW row;
        if ((result = mysql_store_result(&MysqlTemp)) == NULL) {
    #ifdef DEBUG_MOD
            qDebug() << "Fail to store result!" << endl;
    #endif
            return;
        }
    
        Users.clear();
        //逐行取数据
        while ((row = mysql_fetch_row(result)) != NULL)    {
            User UserTemp(atoi(row[0]), std::string(row[1]), std::string(row[2]), std::string(row[3]), 
                          std::string(row[4]), Gender(atoi(row[5])), atoi(row[6]), atoi(row[7]));
    
            Users.push_back(UserTemp);
        }
    #ifdef DEBUG_MOD
        qDebug() << "Load : " << Users.size() << endl;
    #endif
        mysql_close(pSock);
    }
    View Code

     4. Leaderboard

      

      反正只是一个大作业而已就不打算做什么翻页的功能了,直接一个滚动条滑到底好了。

      首先是一个竖直的布局,有一个MainTitle(QLabel)和一个Leaderboard(QScrollArea)。QScrollArea里面先套了一个QWidget,在这个QWidget里面放竖直布局,竖直布局里面每行是一个水平布局,存放个人信息。值得注意的是QScrollArea需要执行一下setWidgetResizable(true),否则会有显示错误……

      

      ^_^

    namespace QtLeaderboard {
        QWidget* CreateTips() {
            QWidget* pwTips = new QWidget();
            QHBoxLayout* phlTipsLayout = new QHBoxLayout(pwTips);
            phlTipsLayout->addWidget(new QLabel(SET_TIP_HEAD), INT_SIZERATE_HEAD);
    
            phlTipsLayout->addWidget(new QLabel(SET_TIP_NICKNAME), INT_SIZERATE_NICKNAME);
    
            phlTipsLayout->addWidget(new QLabel(SET_TIP_INTRO), INT_SIZERATE_INTRO);
    
            phlTipsLayout->addWidget(new QLabel(SET_TIP_SCORE), INT_SIZERATE_SCORE);
    
            return pwTips;
        }
    
    
        QWidget* CreatePersonal(std::vector<User>::iterator itUserTemp) {
            QWidget* pPersonal = new QWidget();
            pPersonal->setFixedHeight(INT_PERSONAL_HEIGHT);
    
            QHBoxLayout* phlPersonalLayout = new QHBoxLayout(pPersonal);
    
    
            QLabel* plHead = new QLabel(pPersonal);
    
            {
                QImage Head(QString::fromStdString(itUserTemp->GetHead()));
                Head = Head.scaled(INT_HEAD_WIDTH, INT_HEAD_HEIGHT);
                plHead->setPixmap(QPixmap::fromImage(Head));
                plHead->setAlignment(Qt::AlignCenter);
            }
    
            phlPersonalLayout->addWidget(plHead, INT_SIZERATE_HEAD);
    
            phlPersonalLayout->addWidget(new QLabel(QString::fromStdString(itUserTemp->GetNickname())), INT_SIZERATE_NICKNAME);
    
            phlPersonalLayout->addWidget(new QLabel(QString::fromStdString(itUserTemp->GetIntroduction())), INT_SIZERATE_INTRO);
    
            phlPersonalLayout->addWidget(new QLabel(QString::number(itUserTemp->GetScore())), INT_SIZERATE_SCORE);
    
            return pPersonal;
        }
    
        QScrollArea* CreateBoard() {
            QScrollArea* psaBoard = new QScrollArea();
            QWidget* pwBoard = new QWidget(psaBoard);
    
            pwBoard->setFixedHeight(g_Users.size() * INT_PERSONAL_HEIGHT + INT_TIP_HEIGHT);
            QVBoxLayout* pvlBoardLayout = new QVBoxLayout(pwBoard);
    
            pvlBoardLayout->addWidget(QtLeaderboard::CreateTips());
    
    
            //逐个用户添加信息
            std::vector<User>::iterator itUserTemp;
            //sort(g_Users.begin(), g_Users.end(), User::SortByScore);
            for (itUserTemp = g_Users.begin(); itUserTemp != g_Users.end(); itUserTemp++) {
                pvlBoardLayout->addWidget(QtLeaderboard::CreatePersonal(itUserTemp));
            }
    
            psaBoard->setWidget(pwBoard);
            psaBoard->setWidgetResizable(true);
    
            return psaBoard;
        }
    }
    void Leaderboard::Init() {
        QVBoxLayout *pvlMainLayout = new QVBoxLayout(this);
    
        //加入主标题
        pvlMainLayout->addWidget(new QLabel(STR_MAINTITLE_LEADERBOARD), INT_SIZERATE_MAINTITAL);
    
    
        //加入排行榜界面
        pvlMainLayout->addWidget(QtLeaderboard::CreateBoard(), INT_SIZERATE_BOARD);
    }
    View Code

     5. Personal

      个人界面……写得还蛮久

      

      

      亮点是实现了一个上传头像的功能吧,但是用Qt的getOpenFileName,QImage自带load和save,很容易就造出来了。

      ^_^

    QWidget* Personal::CreateMainInfor() {
        QWidget* pwBox = new QWidget();
        QVBoxLayout* pvMainLayout = new QVBoxLayout(pwBox);
    
        QLabelCenter* plHead = new QLabelCenter();
        QImage Head = g_pCurrentUser->GetHead();
        Head = Head.scaled(INT_HEAD_WIDTH, INT_HEAD_HEIGHT);
        plHead->setPixmap(QPixmap::fromImage(Head));
        pvMainLayout->addWidget(plHead, INT_SIZERATE_HEAD);
    
        pvMainLayout->addWidget(new QLabelCenter(QString::fromStdString(g_pCurrentUser->GetNickname())), INT_SIZERATE_NICKNAME);
    
        pvMainLayout->addWidget(new QLabelCenter(QString::fromStdString(g_pCurrentUser->GetIntroduction())), INT_SIZERATE_INTRO);
    
        return pwBox;
    }
    QWidget* Personal::CreateSingleInfor(QString sTip, QString sInfor) {
        QWidget* pwBox = new QWidget();
        QHBoxLayout* phLayout = new QHBoxLayout(pwBox);
    
        phLayout->addWidget(new QLabelCenter(sTip), INT_SIZERATE_SIN_TIP);
        phLayout->addWidget(new QLabelCenter(sInfor), INT_SIZERATE_SIN_INFOR);
        phLayout->addStretch(INT_SIZERATE_SIN_SPACE);
    
        return pwBox;
    }
    QWidget* Personal::CreateInfor() {
        QWidget* pwBox = new QWidget();
        QVBoxLayout* pvLayout = new QVBoxLayout(pwBox);
    
        pvLayout->addWidget(CreateSingleInfor(STR_TIP_AGE, QString::number(g_pCurrentUser->GetAge())));
        pvLayout->addWidget(CreateSingleInfor(STR_TIP_GENDER, STR_GENDER[g_pCurrentUser->GetGender()]));
        pvLayout->addWidget(CreateSingleInfor(STR_TIP_CERITI, QString::fromStdString(g_pCurrentUser->GetCertificate())));
        pvLayout->addWidget(CreateSingleInfor(STR_TIP_SCORE, QString::number(g_pCurrentUser->GetScore())));
        pvLayout->addWidget(CreateSingleInfor(STR_TIP_BALANCE, QString::number(g_pCurrentUser->GetBalance())));
    
        return pwBox;
    }
    QWidget* Personal::CreateSingleModifyPassword() {
        QWidget* pwBox = new QWidget();
        QHBoxLayout* phLayout = new QHBoxLayout(pwBox);
    
    
        QWidget* pwTip = new QWidget();
        QVBoxLayout* pvLayoutTip = new QVBoxLayout(pwTip);
        pvLayoutTip->addWidget(new QLabelCenter(STR_TIP_PASSWORD));
        pvLayoutTip->addWidget(new QLabelCenter(STR_TIP_PASSWORDCON));
        phLayout->addWidget(pwTip, INT_SIZERATE_MOD_TIP);
    
        QWidget* pwEdit = new QWidget();
        QVBoxLayout* pvLayoutEdit = new QVBoxLayout(pwEdit);
        QLineEdit* pleInputPass = new QLineEdit();
        pvLayoutEdit->addWidget(pleInputPass);
        pleInputPass->setEchoMode(QLineEdit::Password);
        QLineEdit* pleInputCon = new QLineEdit();
        pvLayoutEdit->addWidget(pleInputCon);
        pleInputCon->setEchoMode(QLineEdit::Password);
        phLayout->addWidget(pwEdit, INT_SIZERATE_MOD_INPUT);
    
        QPushButton* ppbButton = new QPushButton(STR_TIP_SIN_MODITY);
        phLayout->addWidget(ppbButton, INT_SIZERATE_MOD_BUTTON);
    
    
        connect(ppbButton, &QPushButton::clicked, [=]() {
            if (pleInputPass->text() != pleInputCon->text()) {
                QMessageBox::information(this, STR_MODIFY_FAIL, STR_PASSWORD_UNMATCH);
                return;
            }
            if (g_pCurrentUser->ChangePassword(pleInputPass->text().toStdString()) == true) {
                m_pParentTrans->ChangeContent(new Personal(m_pParentTrans));
            }
            else {
                QMessageBox::information(this, STR_MODIFY_FAIL, STR_MODIFY_FAIL_TEXT);
                return;
            }
        });
        return pwBox;
    }
    QWidget* Personal::CreateSingleModify(QString sTip, bool(User::*pChange)(std::string)) {
        QWidget* pwBox = new QWidget();
        QHBoxLayout* phLayout = new QHBoxLayout(pwBox);
    
        phLayout->addWidget(new QLabelCenter(sTip), INT_SIZERATE_MOD_TIP);
        QLineEdit* pleInput = new QLineEdit();
        phLayout->addWidget(pleInput, INT_SIZERATE_MOD_INPUT);
        QPushButton* ppbButton = new QPushButton(STR_TIP_SIN_MODITY);
        phLayout->addWidget(ppbButton, INT_SIZERATE_MOD_BUTTON);
        connect(ppbButton, &QPushButton::clicked, [=]() {
            if ((g_pCurrentUser->*pChange)(pleInput->text().toStdString()) == true) {
                m_pParentTrans->ChangeContent(new Personal(m_pParentTrans));
            }
            else {
                QMessageBox::information(this, STR_MODIFY_FAIL, STR_MODIFY_FAIL_TEXT);
                return;
            }
        });
    
        return pwBox;
    }
    QWidget* Personal::CreateSingleModifyGender() {
        QWidget* pwBox = new QWidget();
        QHBoxLayout* phLayout = new QHBoxLayout(pwBox);
    
        phLayout->addWidget(new QLabelCenter(STR_TIP_GENDER), INT_SIZERATE_MOD_TIP);
        QComboBox* pcbInput = GetInformation::CreateGenderCom();
        phLayout->addWidget(pcbInput, INT_SIZERATE_MOD_INPUT);
        QPushButton* ppbButton = new QPushButton(STR_TIP_SIN_MODITY);
        phLayout->addWidget(ppbButton, INT_SIZERATE_MOD_BUTTON);
        connect(ppbButton, &QPushButton::clicked, [=]() {
            if (g_pCurrentUser->ChangeGender(pcbInput->currentIndex()) == true) {
                m_pParentTrans->ChangeContent(new Personal(m_pParentTrans));
            }
            else {
                QMessageBox::information(this, STR_MODIFY_FAIL, STR_MODIFY_FAIL_TEXT);
                return;
            }
        });
    
    
        return pwBox;
    }
    QScrollArea* Personal::CreateModify() {
        QScrollArea* psaBox = new QScrollArea();
    
        QWidget* pwBox = new QWidget();
        QVBoxLayout* pvLayout = new QVBoxLayout(pwBox);
        QPushButton* ppbUploadHead = new QPushButton(STR_HEAD_UPLOAD);
        connect(ppbUploadHead, &QPushButton::clicked, [this]() {
            QString filename = QFileDialog::getOpenFileName(this, STR_CHOOSE_IMAGE, "/", STR_IMAGE_FILTER);
            if (filename.isEmpty())
                return;
            else
            {
                QImage Image;
                if (!(Image.load(filename)))
                {
                    QMessageBox::information(this, STR_LOAD_FAIL, STR_LOAD_FAIL_TEXT);
                    return;
                }
                QString sSavePath = QCoreApplication::applicationDirPath() + STR_HEAD_PATH;
                Image.save(sSavePath + QString::number(g_pCurrentUser->GetId()) + STR_HEAD_TYPE);
                m_pParentTrans->UpdateMenu();
                m_pParentTrans->ChangeContent(new Personal(m_pParentTrans));
            }
        });
        pvLayout->addWidget(ppbUploadHead, INT_SIZERATE_MOD_UPLOAD);
    
    
        pvLayout->addWidget(CreateSingleModifyPassword(), INT_SIZERATE_MOD_INTRO);
        pvLayout->addWidget(CreateSingleModify(STR_TIP_AGE, &(User::ChangeAge)), INT_SIZERATE_MOD_AGE);
        pvLayout->addWidget(CreateSingleModify(STR_TIP_INTRO, &(User::ChangeIntro)), INT_SIZERATE_MOD_INTRO);
        pvLayout->addWidget(CreateSingleModify(STR_TIP_CERITI, &(User::ChangeCeriti)), INT_SIZERATE_MOD_CERITI);
        pvLayout->addWidget(CreateSingleModifyGender(), INT_SIZERATE_MOD_GENDER);
    
        psaBox->setWidget(pwBox);
        psaBox->setWidgetResizable(true);
        return psaBox;
    }
    QTabWidget* Personal::CreateTab() {
        QTabWidget* pwTabBox = new QTabWidget();
    
        //标签页暂时只有这俩元素
        pwTabBox->addTab(CreateInfor(), STR_TAB_INFOR);
        pwTabBox->addTab(CreateModify(), STR_TAB_MODIFY);
    
        return pwTabBox;
    }
    
    void Personal::Init() {
        if (g_pCurrentUser == NULL) {
            m_pParentTrans->ChangeContent(new Index(m_pParentTrans));
            return;
        }
        QVBoxLayout *pvlMainLayout = new QVBoxLayout(this);
    
        //主题拆成两块,主信息展示和标签页
        pvlMainLayout->addWidget(CreateMainInfor(), INT_SIZERATE_INFOR);
    
        pvlMainLayout->addWidget(CreateTab(), INT_SIZERATE_TAB);
    }
    View Code
  • 相关阅读:
    MySQL基础(二)
    MySQL练习题
    前端基础之css
    前端基础之初识HTML
    Ubuntu14.04 + Text-Detection-with-FRCN(CPU)
    简单HOG+SVM mnist手写数字分类
    汽车检测SIFT+BOW+SVM
    4. Neural Network
    2. Linear Model
    OpenCV2计算机编程手册(二)基于类的图像处理
  • 原文地址:https://www.cnblogs.com/Enceladus/p/11223592.html
Copyright © 2020-2023  润新知