目录
------------------
------------------
- 开发环境/工具: Linux,QT,libevent库,Mysql数据库,jsoncpp库。
- 基于 Qt 平台:分别在 windows 和 Linux 下构建客户端和服务器,实现“头脑 风暴” 在线对战小游戏。
- 实现功能:实现了用户注册、用户登录、排位匹配对战答题、个人训练答题、段位记 录系统、段位匹配系统等功能。
补上需要的代码:
-
- CONFIG += console c++11
-
-
- #jsoncpp
- LIBS +=-L/usr/local/lib -levent -lpthread -lmysqlclient -ljson
- #ifndef TCPSERVER_H
- #define TCPSERVER_H
- #include"thread.h"
- #include
- #include
- #include
- #include
-
- #include
- #include
- #include"tcpsocket.h"
-
- class TcpSocket;
-
- //Tcp服务器的基类
- class TcpServer
- {
- friend class TcpSocket;
- public:
- TcpServer(int threadNum=8);
- int listen(int port, const char *ip=NULL);
-
- //服务器开始运行
- void start();
-
- protected:
- //监听回调函数,有客户端连接的时候会调用
- static void listenCb(struct evconnlistener *, evutil_socket_t fd, struct sockaddr *clientAdd, int socklen, void *data);
-
- //监听处理函数
- void listenEvent(evutil_socket_t fd, struct sockaddr_in *clientAdd);
-
- //--------虚函数,去具体处理客户端的逻辑--------
- //客户端连接事件
- virtual void connectEvent(TcpSocket *){}
- //客户端可读事件
- virtual void readEvent(TcpSocket *){}
- //客户端可写事件
- virtual void writeEvent(TcpSocket *){}
- //客户端可读事件
- virtual void closeEvent(TcpSocket *,short){}
-
- private:
- int m_threadNum;//线程个数
- Thread *m_threadPool;//线程池
- struct event_base *m_base;
- struct evconnlistener *m_listener;//监听客户端的连接(事件)。类似于监听套接字。
- int m_nextThread; //记录下一个线程的下标
- };
-
- #endif // TCPSERVER_H
- #ifndef THREAD_H
- #define THREAD_H
-
- #include
- #include
- #include
- #include
-
- #include
- #include
- #include
- class Thread
- {
- public:
- Thread();
- void start();//线程运行
-
- //获取事件集合
- struct event_base *getBase();
-
- protected:
- //在类的内部调用回调函数就要变成静态,加static
- static void* worker(void*);//线程的工作函数
- static void pipeRead(evutil_socket_t,short,void *);//管道可读
- void run(); //线程的逻辑处理函数
-
- private:
- struct event_base *m_base;//事件集合
- pthread_t m_threadId; //线程ID
- int m_pipeReadFd; //管道的读端
- int m_pipeWriteFd; //管道的写端
- struct event m_pipeEvent; //管道事件
-
- };
-
- #endif // THREAD_H
- #ifndef TCPSOCKET_H
- #define TCPSOCKET_H
-
- #include"tcpserver.h"
- #include
-
- class TcpServer;
-
- //通信类,负责与客户端进行通信
- class TcpSocket
- {
-
- public:
- TcpSocket(TcpServer *tcpServer, struct bufferevent *bev, char *ip, u_int16_t port);
-
- //可读事件的回调函数
- static void readEventCb(struct bufferevent *bev,void *etc);
- //可写事件的回调函数
- static void writeEventCb(struct bufferevent *bev,void *etc);
- //异常事件的回调函数
- static void closeEventCb(struct bufferevent *bev,short what,void *etc);
-
- char *getIp();//获取IP地址
- u_int16_t getPort();//获取端口
-
- //从客户端读数据
- int readDate(void *data, int size);
- //向客户端写数据
- int writeDate(const void *data, int size);
-
- void setUserName(std::string name);
- std::string getUserName();
-
- private:
- static TcpServer *m_tcpServer;//服务器类对象。需要初始化
- struct bufferevent *m_bev;//通信用的句柄,用来与客户端通信
- char *m_ip; //客户端的IP地址
- u_int16_t m_port; //客户端的端口
-
- std::string _userName;//当前使用他这个用户
- };
-
- #endif // TCPSOCKET_H
- #ifndef DB_H
- #define DB_H
- #include"mysql/mysql.h"
- #include
- #include
- #include
-
- class DB
- {
- public:
- DB(const char *host,const char *userName,const char *passwd,const char *dbName);
- //执行数据库语句
- bool db_exec(const char *sql);
-
- //数据库查询
- //[in] sql 查询语句
- //[out] outJson 查询结果到json变量中
- bool db_select(const char *sql,Json::Value &outJson);
-
-
-
- private:
- std::mutex _mutex;//数据库句柄互斥锁
- MYSQL *_mysql;//数据库
- };
-
- #endif // DB_H
- #ifndef USER_H
- #define USER_H
- #include
- #include"tcpsocket.h"
-
- class User
- {
- public:
- User(std::string n,std::string p,int rank,TcpSocket *s);
-
- TcpSocket *getSocket();
- const char *getName();
-
- int getRank();
-
- void setRank(int rank);
-
- private:
- std::string _userName; //用户名
- std::string _passwd; //用户密码
- int _rank; //rank分数
-
-
- TcpSocket *_s; //通信类套接字
- };
-
- #endif // USER_H
- #ifndef MYSERVER_H
- #define MYSERVER_H
-
- #include"tcpserver.h"
- #include
- #include"db.h"
- #include
- #include
- #include"../common.h"
- #include
- #include
- #include"user.h"
- #define DEBUG
- //#define QUESTION_NUM 5
-
- class MyServer:public TcpServer//继承
- {
- public:
- MyServer();
-
- void connectEvent(TcpSocket *);
-
- void readEvent(TcpSocket *);
-
- void writeEvent(TcpSocket *);
-
- void closeEvent(TcpSocket *s, short);
-
- private:
- //发送数据
- void writeData(TcpSocket *s,const Json::Value &inJson);
-
- //用户注册
- void Register(TcpSocket *s,const Json::Value &inJson);
-
- //用户登录
- void Login(TcpSocket *s,const Json::Value &inJson);
-
- //获取个人训练题目
- void get_SingleQuestion(TcpSocket *s);
-
- //进行排位
- void Rank(TcpSocket *s);
-
- //rank 回答一道问题
- void rankAnswerOneQuestion(TcpSocket *s,const Json::Value &inJson);
-
- //开始对决
- void startRank(TcpSocket *first,TcpSocket *second);
-
- //rank结果
- void rankResult(TcpSocket *s, const Json::Value &inJson);
-
- //初始化rank积分对照表
- void initRankMap();
-
- private:
- std::shared_ptr
_log;//记录日志的句柄 - DB* _db;//数据库句柄
-
- //键是用户名,值是用户指针
- std::mutex _userLock;//锁_Users
- std::map
_users; //在线用户列表 -
- //key : rank积分
- //值 : 对应的段位说明
- std::map<int,std::string> _rankMap; //rank积分比对表
-
- //key : rank积分
- //value : 参与rank的用户socket句柄
- std::mutex _rankLock;
- std::map<int,TcpSocket*> _rankQueue; //等待排位的队列
- };
-
- #endif // MYSERVER_H
---------------------------------------------------------------------------------------------------------------------------------
- #include "tcpserver.h"
-
- TcpServer::TcpServer(int threadNum):m_nextThread(0)//下标初始化为0
- {
- if(threadNum<=0)
- {
- printf("threadNum<=0");
- exit(-1);
- }
- m_threadNum=threadNum;
- m_threadPool=new Thread[threadNum];
- if(m_threadPool==NULL)
- {
- printf("create threadPool error\n");
- exit(-1);
- }
- m_base=event_base_new();
- if(!m_base)
- {
- printf("Could not initialize libevent!\n");
- exit(-1);
- }
- }
-
- //evutil_socket_t fd: 与客户端通信的文件描述符
- //struct sockaddr *clientAdd: 客户端的IP地址,地址信息。
- void TcpServer::listenCb(struct evconnlistener *,evutil_socket_t fd,struct sockaddr *clientAdd,int ,void *data)
- {
- TcpServer *p=(TcpServer*)data;
- p->listenEvent(fd,(struct sockaddr_in *)clientAdd);
- }
-
- void TcpServer::listenEvent(evutil_socket_t fd,struct sockaddr_in *clientAdd)
- {
- char *ip =inet_ntoa(clientAdd->sin_addr);//客户端的IP地址
- uint16_t port=ntohs(clientAdd->sin_port);//客户端的使用的端口
-
- //从线程池中选择一个线程去处理客户端的请求
- //以论寻的方式选择线程
- struct event_base *base=m_threadPool[m_nextThread].getBase();
- m_nextThread=(m_nextThread+1) % m_threadNum;
-
- //base监测fd
- struct bufferevent *bev=bufferevent_socket_new(base,fd,BEV_OPT_CLOSE_ON_FREE);
- if(!bev)
- {
- fprintf(stderr,"Error constructing bufferevent!");
- event_base_loopbreak(base);
- return;
- }
-
- //创建一个对象
- TcpSocket *s=new TcpSocket(this,bev,ip,port);
-
- //单独封装一个类负责和客户端的通信
-
- bufferevent_setcb(bev,s->readEventCb,s->writeEventCb,s->closeEventCb,s);
- bufferevent_enable(bev,EV_WRITE);//打开是否可写
- bufferevent_enable(bev,EV_READ);//打开是否可读
- bufferevent_enable(bev,EV_SIGNAL);
-
- //调用客户端连接函数
- connectEvent(s);
- }
-
- int TcpServer::listen(int port,const char *ip)
- {
- struct sockaddr_in sin;
- memset(&sin,0,sizeof(sin));
- sin.sin_family=AF_INET;
- sin.sin_port=htons(port);
- if(ip!=NULL)
- inet_aton(ip,&sin.sin_addr);
-
- m_listener=evconnlistener_new_bind(m_base,listenCb,this,LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE,-1,(struct sockaddr*)&sin,sizeof(sin));
- if(!m_listener)
- {
- printf("Could not create a listener!\n");
- return -1;
- }
-
- //开启线程池
- for(int i=0;i
- {
- m_threadPool[i].start();
- printf("线程 %d 启动\n",i+1);
- }
- return 0;
- }
-
- void TcpServer::start()
- {
- event_base_dispatch(m_base);
- evconnlistener_free(m_listener);
- event_base_free(m_base);
- printf("done\n");
- }
thread.cpp
- #include "thread.h"
-
- Thread::Thread()
- {
- m_base=event_base_new();
- if(!m_base)
- {
- printf("Couldn't creat an event_base:exiting\n");
- exit(-1);
- }
- //在构造函数里创建管道
- int fd[2];
- if (pipe(fd) == -1)
- {
- perror("fork");
- exit(-1);
- }
- //管道的读写端
- m_pipeReadFd=fd[0];
- m_pipeWriteFd=fd[1];
-
- //让管道事件监听管道的读端
- //如果监听到,管道的读端有数据可读
- //EV_READ:监听管道是否有可读事件
- //EV_PERSIST:让事件永久有效,不然读完一次下次就不监听了
- //pipeRead:管道事件来了之后自动调用这个函数,类似于槽函数
- event_set(&m_pipeEvent,m_pipeReadFd,EV_READ | EV_PERSIST,pipeRead,this);
-
- //将事件添加到m_base集合中
- event_base_set(m_base,&m_pipeEvent);
-
- //开始事件的监听
- event_add(&m_pipeEvent,0);
-
- }
-
- void Thread::pipeRead(int, short, void *)
- {
-
- }
-
- void Thread::start()
- {
- //创建线程
- pthread_create(&m_threadId,NULL,worker,this);
- //线程分离
- pthread_detach(m_threadId);
- }
-
- void* Thread::worker(void* arg)
- {
- Thread* p=(Thread*)arg;
- p->run(); //
- return NULL;
- }
-
- void Thread::run()
- {
- /*测试用的
- while(1)
- {
- printf("thread:%d\n",m_threadId);
- sleep(2);
- }
- */
- //printf("%d:start\n",m_threadId);
- //监听base事件集合
- //dispatch是一个死循环,一直监听。用来处理事件,类似于qt的exec()
- //如果m_base集合是空的,则event_base_dispatch不运行会立马返回
- //初始化的时候需要给m_base添加一个事件,让它不空
- event_base_dispatch(m_base);
- event_base_free(m_base);
-
- //printf("%d:done\n",m_threadId);
- }
-
- struct event_base *Thread::getBase()
- {
- return m_base;
- }
tcpsocket.cpp
- #include "tcpsocket.h"
-
- TcpServer *TcpSocket::m_tcpServer=NULL;
-
- TcpSocket::TcpSocket(TcpServer *tcpServer,struct bufferevent *bev,char *ip,u_int16_t port)
- {
- m_tcpServer=tcpServer;
- m_bev=bev;
- m_ip=ip;
- m_port=port;
- }
-
- //可读事件的回调函数
- void TcpSocket::readEventCb(struct bufferevent *,void *etc)
- {
- TcpSocket *s=(TcpSocket*)etc;
- m_tcpServer->readEvent(s);
- }
-
- //可写事件的回调函数
- void TcpSocket::writeEventCb(struct bufferevent *,void *etc)
- {
- TcpSocket *s=(TcpSocket*)etc;
- m_tcpServer->writeEvent(s);
- }
-
- //异常事件的回调函数
- void TcpSocket::closeEventCb(struct bufferevent *,short what,void *etc)
- {
- TcpSocket *s=(TcpSocket*)etc;
- m_tcpServer->closeEvent(s,what);
- delete s;
- }
-
- char *TcpSocket::getIp()
- {
- return m_ip;
- }
-
- u_int16_t TcpSocket::getPort()
- {
- return m_port;
- }
-
- //从客户端读数据
- int TcpSocket::readDate(void *data,int size)
- {
-
- return bufferevent_read(m_bev,data,size);
- }
-
- //向客户端写数据
- int TcpSocket::writeDate(const void *data,int size)
- {
- return bufferevent_write(m_bev,data,size);
- }
-
- void TcpSocket::setUserName(std::string name)
- {
- _userName=name;
- }
-
- std::string TcpSocket::getUserName()
- {
- return _userName;
- }
db.cpp
- #include "db.h"
-
- DB::DB(const char *host, const char *userName, const char *passwd, const char *dbName)
- {
- //初始化数据库句柄
- _mysql =mysql_init(NULL);
- if(_mysql==NULL)
- {
- spdlog::get("BrainStorm")->error("mysql_init error\n");
- exit(-1);
- }
-
- //连接数据库
- MYSQL *con=mysql_real_connect(_mysql,host,userName,passwd,dbName,0,NULL,0);
- if(con==NULL)
- {
- spdlog::get("BrainStorm")->error("连接数据库失败:{}",mysql_error(_mysql));
- exit(-1);
- }
- _mysql=con;
-
- //设置字符集
- int ret=mysql_query(_mysql,"set names utf8");//设置中文
- if(ret!=0)
- {
- spdlog::get("BrainStorm")->error("设置字符集失败:%s",mysql_error(_mysql));
- exit(-1);
- }
-
- }
-
- bool DB::db_exec(const char *sql)
- {
- std::unique_lock
loc(_mutex) ;//智能锁,数据库句柄上锁 - int ret=mysql_query(_mysql,sql);
- if(ret!=0)
- {
- spdlog::get("BrainStorm")->error("mysql_query error:%s",mysql_error(_mysql));
- return false;
- }
- return true;
- }
-
- bool DB::db_select(const char *sql,Json::Value &outJson)
- {
- std::unique_lock
loc(_mutex) ;//智能锁,数据库句柄上锁 - int ret=mysql_query(_mysql,sql);
- if(ret!=0)
- {
- spdlog::get("BrainStorm")->error("mysql_query error:%s",mysql_error(_mysql));
- return false;
- }
-
- //从mysql服务器下载查询结果
- MYSQL_RES *sql_res=mysql_store_result(_mysql);
- if(sql_res==NULL)
- {
- if(mysql_errno(_mysql)==0)
- {
- return true;
- }
- else
- {
- spdlog::get("BrainStorm")->error("mysql_store_result error:%s",mysql_error(_mysql));
- }
- }
-
- //看字段,先看有多少列,
- MYSQL_ROW row;//从结果集中一行一行获取
- unsigned int num_fields=mysql_num_fields(sql_res);//获取列数
- MYSQL_FIELD *fetch_field=mysql_fetch_field(sql_res);//获取表头(字段)
-
- //一行一行的获取数据结构
- while(row=mysql_fetch_row(sql_res))//然后就要填这个数据结构
- {
- for(unsigned int i=0;i
- {
- outJson[fetch_field[i].name].append(row[i]);
- }
- }
-
- //获取完把结构给删掉
- mysql_free_result(sql_res);
-
- return true;
- }
user.cpp
- #include "user.h"
-
- User::User(std::string n,std::string p,int rank,TcpSocket *s)
- :_userName(n),_passwd(p),_rank(rank),_s(s)
- {
-
- }
-
- TcpSocket *User::getSocket()
- {
- return _s;
- }
-
- const char *User::getName()
- {
- return _userName.c_str();
- }
-
- int User::getRank()
- {
- return _rank;
- }
-
- void User::setRank(int rank)
- {
- if(rank<=0)
- rank=0;
- _rank=rank;
- }
myserver.cpp
- #include "myserver.h"
-
- MyServer::MyServer()
- {
- //日志
- #ifdef DEBUG//向控制台写
- _log=spdlog::stdout_color_mt("console");
- #else
- _log=spdlog::rotating_logger_mt("BrainStorm","BrainStorm",1024*1024*5,3);
- _log->flush_on(spdlog::level::info);
- #endif
- //_log->info("11111111111");//写在控制台
-
- _db=new DB(NULL,"xiaowang","xiaowang","BrainStorm");
- initRankMap();
- }
-
- void MyServer::connectEvent(TcpSocket *s)
- {
- _log->info("有一个新的连接[{}:{}]\n",s->getIp(),s->getPort());
- //printf("客户端连接%s","端口连接%s",s->getIp(),s->getPort());
- }
-
- void MyServer::readEvent(TcpSocket *s)
- {
- char buf[1024]={0};
- while(1)
- {
- int len=0;
- s->readDate(&len,sizeof(len));
- if(len<=0)
- break;
- s->readDate(buf,len);
- //数据解析
- Json::Value root;
- Json::Reader reader;//json解析器
- if(!reader.parse(buf,root))
- {
- _log->error("json数据解析失败");
- return;
- }
-
- int cmd=root["cmd"].asInt();
- switch (cmd)
- {
- case REGISTER:
- Register(s,root);
- break;
- case LOGIN:
- Login(s,root);
- break;
- case SINGLE_QUESTION:
- get_SingleQuestion(s);
- break;
- case RANK:
- Rank(s);
- break;
- case ANSWER:
- rankAnswerOneQuestion(s,root);
- break;
- case RANKRESULT:
- rankResult(s,root);
- break;
- default:
- break;
- }
-
- }
- }
-
- void MyServer::writeEvent(TcpSocket *)
- {
-
- }
-
- void MyServer::closeEvent(TcpSocket *s,short)
- {
- //将用户从 等待 rank 的列表中删除
- {
- std::unique_lock
_lock(_rankLock); - int rank=_users[s->getUserName()]->getRank();
- auto it=_rankQueue.find(rank);//然后从队列里面去找他
- if(it != _rankQueue.end())
- _rankQueue.erase(it);
- }
-
- //printf("客户端退出,ip:%s,端口:%d\n",s->getIp(),s->getPort());
- //_log->error("用户{}[{}:{}] logout",userName,s->getIp(),s->getPort());
- std::unique_lock
_lock(_userLock); - std::map
::iterator it=_users.begin(); - while(it!=_users.end())
- {
- if(it->second->getSocket()==s)
- {
- _users.erase(it);
- _log->info("用户{}[{}:{}] logout",it->second->getName(),s->getIp(),s->getPort());
- break;
-
- //移除完之后释放User
- delete it->second;
- return;
- }
-
- it++;
- }
- _log->info("用户{}[{}:{}] logout",s->getIp(),s->getPort());
-
- }
-
- void MyServer::writeData(TcpSocket *s,const Json::Value &inJson)
- {
- std::string data=inJson.toStyledString();
- s->writeDate(data.c_str(),data.length());
- }
-
- void MyServer::Register(TcpSocket *s,const Json::Value &inJson)
- {
- std::string userName=inJson["userName"].asString();
- std::string passwd=inJson["passwd"].asString();
-
- //检测用户是否已经存在
- char sql[100]={0};
- sprintf(sql,"select *from user where name='%s' and passwd='%s'",userName.c_str(),passwd.c_str());
-
- int result=OK;
- Json::Value outJson;
- bool ret=_db->db_select(sql,outJson);
- if(!ret)
- {
- result=ERROR;
- _log->error("Register select user error");
- }
-
- if(outJson.isMember("name")) //用户存在,表明已经做过了
- result=USEREXIST;
- else
- {
- sprintf(sql,"insert into user(name,passwd,rank) values('%s','%s',0)",userName.c_str(),passwd.c_str());
- bool ret=_db->db_exec(sql);
- if(!ret)
- {
- result=ERROR;
- _log->error("Register insert user error");
- }
- else
- _log->info("Register user={} succeed",userName);
-
- }
-
- //最后整合数据
- Json::Value json;
- json ["cmd"]=REGISTER;
- json ["result"]=result;
-
- writeData(s,json);
-
- }
-
- void MyServer::Login(TcpSocket *s,const Json::Value &inJson)
- {
- std::string userName=inJson["userName"].asString();
- std::string passwd=inJson["passwd"].asString();
- int rank=0;
-
- //检测用户是否已经登录
-
- char sql[100]={0};
- sprintf(sql,"select *from user where name='%s' and passwd='%s'",userName.c_str(),passwd.c_str());
-
- int result=OK;
- Json::Value outJson;
- bool ret=_db->db_select(sql,outJson);
- if(!ret)
- {
- result=ERROR;
- _log->error("Login select user error");
- }
-
- if(outJson.isMember("name")) //用户存在,表明已经注册了
- {
- std::unique_lock
_lock(_userLock);//先上一把锁 - if(_users.find(userName)!=_users.end())//用户已经登录
- result=USERLOGIN;
- else
- {
- int i=0;
- rank=atoi(outJson["rank"][i].asString().c_str());
- User* user=new User(userName,passwd,rank,s);
- _users.insert(make_pair(userName,user));//用户创建完,把他放进列表里,user为指针
- _log->info("用户{}[{}:{}] login",userName,s->getIp(),s->getPort());
- s->setUserName(userName);
- }
- }
- else
- result=NAMEORPASSWD;
-
- //最后整合数据
- Json::Value json;
- json ["cmd"] =LOGIN;
- json ["result"] =result;
- json ["userName"]=userName;
- json ["rank"] =_rankMap[rank];
-
- writeData(s,json);
- }
-
- void MyServer::get_SingleQuestion(TcpSocket *s)
- {
- char sql[100]={0};
- sprintf(sql,"select * from question order by rand() limit %d",QUESTION_NUM);
-
- int result=OK;
- Json::Value outJson;
- bool ret=_db->db_select(sql,outJson);
- if(!ret || outJson["question"].size()!=QUESTION_NUM)
- {
- result=ERROR;
- _log->error("get_SingleQuestion select question error");
- }
-
- Json::Value json;
- json ["cmd"] =SINGLE_QUESTION;
- json ["result"] =result;
- json ["question"]=outJson;
-
- _log->info("用户{}[{}:{}] 获取题目: {}\n",s->getUserName(),s->getIp(),s->getPort(),json.toStyledString());
-
- //服务器把数据发送给客户端
- writeData(s,json);
- }
-
- void MyServer::startRank(TcpSocket *first,TcpSocket *second)
- {
- char sql[100]={0};
- sprintf(sql,"select * from question order by rand() limit %d",QUESTION_NUM);
-
- int result=OK;
- Json::Value outJson;
- bool ret=_db->db_select(sql,outJson);
- if(!ret || outJson["question"].size()!=QUESTION_NUM)
- {
- result=ERROR;
- _log->error("startRank select question error");
- }
-
- Json::Value json;
- json ["cmd"] =RANK;
- json ["result"] =result;
- json ["question"]=outJson;
-
- //first user
- json ["enemyName"] =second->getUserName();
- json ["enemyRank"] =_rankMap[_users[second->getUserName()]->getRank()];
- json ["enemyScore"]=0;
- writeData(first,json);
-
- //second user
- json ["enemyName"] =first->getUserName();
- json ["enemyRank"] =_rankMap[_users[first->getUserName()]->getRank()];
- writeData(second,json);
-
- _log->info(" 获取 rank 题目: {}\n",json.toStyledString());
- }
-
- void MyServer::Rank(TcpSocket *s)
- {
- TcpSocket *other=NULL;//对手
- int rank=_users[s->getUserName()]->getRank();//当前用户 rank 积分
-
- std::unique_lock
lock(_rankLock) ; - //查找同一段位的对手
- std::map<int,TcpSocket*>::iterator it=_rankQueue.find(rank);
- if(it!=_rankQueue.end())//找到了
- {
- other=it->second;
- _rankQueue.erase(it);
- }
- else
- {
- //查找其他段位的选手 积分差值的绝对值小于5的都可以进行对决
- for(int i=0;i<=5;i++)
- {
- it=_rankQueue.find(rank+i);
- if(it!=_rankQueue.end())
- {
- other=it->second;
- _rankQueue.erase(it);
- break;
- }
- it=_rankQueue.find(rank-i);
- if(it!=_rankQueue.end())
- {
- other=it->second;
- _rankQueue.erase(it);
- break;
- }
- }
- }
- _log->info("rank 分数:{}",rank);
- if(other==NULL)//没有匹配到用户
- {
- _rankQueue.insert(std::make_pair(rank,s));
- _log->info("当前等候 rank 人数:{}",_rankQueue.size());
-
- }
- else//找到
- {
- //开始对决
- startRank(s,other);
- }
- }
-
- void MyServer::rankAnswerOneQuestion(TcpSocket *s,const Json::Value &inJson)
- {
- std::string enemyName=inJson["enemyName"].asString();
- User *user=_users[enemyName];
-
- Json::Value json;
- json ["cmd"] =ANSWER;
- json ["enemyscore"] =inJson["score"].asInt();
- json ["enemyQuestionId"]=inJson["questionId"].asInt();
-
- writeData(user->getSocket(),json);
- }
-
- void MyServer::rankResult(TcpSocket *s,const Json::Value &inJson)
- {
- std::unique_lock
lock(_userLock) ; - User *user=_users[s->getUserName()];
-
- int score =inJson["score"].asInt();
- int enemyscore=inJson["enemyscore"].asInt();
-
- if(score
- user->setRank(user->getRank()-1);
- else if(score>enemyscore)
- user->setRank(user->getRank()+1);
-
- Json::Value json;
- json ["cmd"] =RANKRESULT;
- json ["newRank"] =_rankMap[user->getRank()];
-
- writeData(s,json);//发送给客户端
- }
-
- void MyServer::initRankMap()
- {
- char buf[100]={0};
- int rank=0;
- int num=0;
- for(int i=0;i<100;i++)
- {
- if(i<9)
- {
- rank=i/3;
- num=i%3;
- sprintf(buf,"青铜%d %d颗星",3-rank,num+1);
- }
- else if(9<=i && i<18)
- {
- rank=(i-9)/3;
- num=(i-9)%3;
- sprintf(buf,"白银%d %d颗星",3-rank,num+1);
- }
- else if(9<=i && i<18)
- {
- rank=(i-9)/4;
- num=(i-9)%4;
- sprintf(buf,"黄金%d %d颗星",4-rank,num+1);
- }
- else if(18<=i && i<34)
- {
- rank=(i-18)/4;
- num=(i-18)%4;
- sprintf(buf,"铂金%d %d颗星",4-rank,num+1);
- }
- else if(34<=i && i<50)
- {
- rank=(i-34)/5;
- num=(i-34)%5;
- sprintf(buf,"钻石%d %d颗星",5-rank,num+1);
- }
- else if(50<=i && i<75)
- {
- rank=(i-50)/5;
- num=(i-50)%5;
- sprintf(buf,"星曜%d %d颗星",5-rank,num+1);
- }
- _rankMap.insert(std::make_pair(i,buf));
- }
-
- /*
- for(int i=0;i<100;i++)
- {
- std::cout<
- }
- */
-
- }
main.cpp
- #include
- #include"thread.h"
- #include"tcpserver.h"
- #include"myserver.h"
-
- using namespace std;
-
- int main1()
- {
- Thread *pt1=new Thread;
- Thread *pt2=new Thread;
-
- pt1->start();
- pt2->start();
-
- while(1)
- {
- printf("1111\n");
- sleep(1);
- }
- return 0;
- }
-
- int main2()
- {
- TcpServer s;
- s.listen(9999);
- s.start();
- return 0;
- }
-
- int main()
- {
- MyServer s;
- s.listen(9999);
- s.start();
- return 0;
- }
Client客户端
Client.pro
补上需要的代码:
-
-
- QT += core gui network
-
register.h
- #ifndef REGISTER_H
- #define REGISTER_H
-
- #include
- #include
- #include"communicate.h"
- #include"../common.h"
-
- namespace Ui {
- class Register;
- }
-
- class Register : public QDialog
- {
- Q_OBJECT
-
- public:
- explicit Register(Communicate *com,QWidget *parent = 0);
- ~Register();
-
- private slots:
- void on_RegNButton_clicked();
-
- void on_BackButton_clicked();
-
- void rstResult(int);
-
- private:
- Ui::Register *ui;
- Communicate *_com;
- };
-
- #endif // REGISTER_H
login.h
- #ifndef WIDGET_H
- #define WIDGET_H
-
- #include
- #include"register.h"
- #include"communicate.h"
-
-
- namespace Ui {
- class Widget;
- }
-
- class Widget : public QWidget
- {
- Q_OBJECT
-
- public:
- explicit Widget(QWidget *parent = 0);
- ~Widget();
-
- private slots:
- void on_LogButton_clicked();
-
- void on_RegButton_clicked();
-
- void login(QJsonObject json);
-
- private:
- Ui::Widget *ui;
-
- Communicate *_com;//通信类指针,负责和服务器通信
- };
-
- #endif // WIDGET_H
communicate.h
- #ifndef COMMUNICATE_H
- #define COMMUNICATE_H
-
- #include
- #include
- #include
- #include
- #include"../common.h"
- #include
-
- class Communicate : public QObject
- {
- Q_OBJECT
- public:
- explicit Communicate(QObject *parent = nullptr);
- void writeData(const QJsonObject &json);
-
- signals:
- void rstResult(int );
- void login(QJsonObject json);
- void receiveSingleQuestion(QJsonObject json);
-
- void Rank(QJsonObject json);
-
- public slots:
- void readData();
-
-
- private:
- QTcpSocket s;
-
- };
-
- #endif // COMMUNICATE_H
brainstorm.h
- #ifndef BRAINSTORM_H
- #define BRAINSTORM_H
-
- #include
- #include"communicate.h"
- #include
- #include
-
- namespace Ui {
- class BrainStorm;
- }
-
- class BrainStorm : public QDialog
- {
- Q_OBJECT
-
- public:
- explicit BrainStorm(Communicate *_com,QJsonObject &json,QWidget *parent = 0);
- ~BrainStorm();
-
- private:
- //单人训练,从服务器获取题目
- void getSingleQuestion();
-
- //单人训练设置问题
- void SingleSetQuestion();
-
- //单人训练答题
- void SingleAnswerQuestion(int select);
-
- //设置得分
- void setEnemyScore();
- void setSelfScore();
-
- //--------------------------------------------------------
-
- //rank设置问题
- void rankSetQuestion();
-
- //rank结果
- void rankSetResult(QJsonObject &json);
-
- //rank答题
- void RankAnswerQuestion(int select);
-
- private slots:
- void on_RankButton_clicked();
-
- void on_SingleButton_clicked();
-
- void on_SingleBack_clicked();
-
- void on_SingleStart_clicked();
-
- //单人训练从服务器接收到题目
- void receiveSingleQuestion(QJsonObject json);
- //个人训练计时器
- void SingleTimerOut();
-
- void on_OverBack_clicked();
-
- void on_SingleButtonA_clicked();
-
- void on_SingleButtonB_clicked();
-
- void on_SingleButtonC_clicked();
-
- void on_SingleButtonD_clicked();
-
- //----------------------------------------------------------------------
-
- //接受排位
- void Rank(QJsonObject json);
-
- //排位计时器
- void RankTimerOut();
-
- void on_RankButtonA_clicked();
-
- void on_RankButtonB_clicked();
-
- void on_RankButtonC_clicked();
-
- void on_RankButtonD_clicked();
-
- void on_overButton_clicked();
-
- private:
- Ui::BrainStorm *ui;
- Communicate *_com; //通信类指针,负责和服务器通信
-
- QJsonObject _singleQuestion;
- int _currentSingleQuestion;//当前回答哪一个问题的下标
- QTimer _singleTimer; //个人训练定时器
- int _singleSec; //个人训练答题时间
- int _singleScore; //个人训练得分
-
- //----------------------Rank---------------------
- QJsonObject _rankQuestion; //rank的题
- QString _enemyName;//对手的名字
- QString _enemyRank;//对手的段位
- int _enemyScore; //对手的得分
-
- int _rankSec; //rank 答题计时
- int _myScore; //自己的得分
-
- QString _userName;//自己的名字
- QString _userRank;//自己的段位
-
- int _currentRankQuestion;//当前回答哪一个问题的下标
-
- int _enemyRankQuestion;//对手当前回答问题的下标
-
- QTimer _rankTimer; //排位定时器
-
- };
-
- #endif // BRAINSTORM_H
---------------------------------------------------------------------------------------------------------------------------------
register.cpp
- #include "register.h"
- #include "ui_register.h"
- #include
-
- Register::Register(Communicate *com,QWidget *parent) :
- QDialog(parent),
- ui(new Ui::Register)
- {
- ui->setupUi(this);
- _com=com;
-
- connect(_com,SIGNAL(rstResult(int)),this,SLOT(rstResult(int)));
- }
-
- Register::~Register()
- {
- delete ui;
- }
-
- void Register::on_RegNButton_clicked()
- {
- QString userName=ui->UserlineEdit->text();
- QString passwd=ui->PasswdlineEdit->text();
-
- //发送注册信息
- QJsonObject json;
- json["cmd"]=REGISTER;
- json["userName"]=userName;
- json["passwd"]=passwd;
-
- //给服务器发送数据
- _com->writeData(json);
- }
-
- void Register::rstResult(int ret)
- {
- switch (ret)
- {
- case OK:
- QMessageBox::information(this,"注册","注册成功");
- break;
- case ERROR:
- QMessageBox::critical(this,"注册","注册失败,未知错误");
- break;
- case USEREXIST:
- QMessageBox::critical(this,"注册","注册失败,用户存在");
- break;
- default:
- break;
- }
- }
-
- void Register::on_BackButton_clicked()
- {
- close();
- }
login.cpp
- #include "login.h"
- #include "ui_widget.h"
- #include"register.h"
- #include
- #include"brainstorm.h"
- #include"../common.h"
-
- Widget::Widget(QWidget *parent) :
- QWidget(parent),
- ui(new Ui::Widget)
- {
- ui->setupUi(this);
- _com=new Communicate();
-
- connect(_com,SIGNAL(login(QJsonObject)),this,SLOT(login(QJsonObject)));
- }
-
- Widget::~Widget()
- {
- delete ui;
- }
-
- void Widget::on_LogButton_clicked()
- {
- QString userName=ui->UserlineEdit->text();
- QString passwd=ui->PasswdlineEdit->text();
-
- //将登录信息发送给服务器
- QJsonObject json;
- json["cmd"]=LOGIN;
- json["userName"]=userName;
- json["passwd"]=passwd;
-
- //给服务器发送数据
- _com->writeData(json);
-
-
- }
-
- void Widget::login(QJsonObject json)
- {
- int result=json["result"].toInt();
- switch (result)
- {
- case OK:
- {
- this->hide();
- BrainStorm *dlg=new BrainStorm(_com,json);
- dlg->show();
- dlg->setAttribute(Qt::WA_DeleteOnClose);//属性,把new出来的自己销毁
- break;
- }
- case ERROR:
- QMessageBox::critical(this,"登录","登录失败,未知错误");
- break;
- case USERLOGIN:
- QMessageBox::critical(this,"登录","登录失败,不允许重复登录");
- break;
- case NAMEORPASSWD:
- QMessageBox::critical(this,"登录","用户名或密码错误");
- break;
- default:
- break;
- }
- }
-
- void Widget::on_RegButton_clicked()
- {
- this->hide();
- Register reg(_com);
- reg.exec();
- this->show();
- }
communicate.cpp
- #include "communicate.h"
- #include
-
- Communicate::Communicate(QObject *parent) : QObject(parent)
- {
- //连接服务器
- s.connectToHost(QHostAddress("***.***.***.***"),****);
-
- connect(&s,SIGNAL(readyRead()),this,SLOT(readData()));
- }
-
- void Communicate::readData()
- {
- QByteArray data;
- while(s.bytesAvailable())
- {
- data +=s.readAll();//读完
- }
-
- //数据解析
- QJsonDocument dt=QJsonDocument::fromJson(data);//通过QJsonDocument转换成json字符串
- if(dt.isNull())//没有读到数据
- {
- return;
- }
-
- QJsonObject root=dt.object();//拿到json这样的一个对象
-
- //具体的逻辑处理
- int cmd=root["cmd"].toInt();
- switch (cmd)
- {
- case REGISTER:
- emit rstResult(root["result"].toInt());//发给注册那一端
- break;
- case LOGIN:
- emit login(root);//发给注册那一端
- break;
- case SINGLE_QUESTION:
- emit receiveSingleQuestion(root["question"].toObject());
- break;
- case RANK:
- emit Rank(root);
- break;
- case ANSWER:
- emit Rank(root);
- break;
- case RANKRESULT:
- emit Rank(root);
- break;
- default:
- break;
- }
- }
-
- void Communicate::writeData(const QJsonObject &json)
- {
- QJsonDocument d(json);
- QByteArray sendData=d.toJson();
- int len=sendData.size();
-
- s.write((char *)&len,sizeof(int));//发送数据长度
- s.write(sendData);//发送数据
- }
brainstorm.cpp
- #include "brainstorm.h"
- #include "ui_brainstorm.h"
-
- BrainStorm::BrainStorm(Communicate *com, QJsonObject &json, QWidget *parent) :
- QDialog(parent),
- ui(new Ui::BrainStorm)
- {
- ui->setupUi(this);
- _com=com;
-
- _userName=json["userName"].toString();
- _userRank=json["rank"].toString();
-
- connect(&_singleTimer,SIGNAL(timeout()),this,SLOT(SingleTimerOut()));
- connect(&_rankTimer,SIGNAL(timeout()),this,SLOT(RankTimerOut()));
-
- connect(_com,SIGNAL(receiveSingleQuestion(QJsonObject)),this,SLOT(receiveSingleQuestion(QJsonObject)));
- connect(_com,SIGNAL(Rank(QJsonObject)),this,SLOT(Rank(QJsonObject)));
-
- }
-
- BrainStorm::~BrainStorm()
- {
- delete ui;
- }
-
- //进入个人训练赛
- void BrainStorm::on_SingleButton_clicked()
- {
- ui->stackedWidget->setCurrentWidget(ui->SingleMenu);
- }
-
- //个人训练计时器
- void BrainStorm::SingleTimerOut()
- {
- --_singleSec;
- if(_singleSec==0)
- {
- ui->Singleresult->setText("回答错误");
- QString str=QString("本次得分:%1").arg(_singleScore);
- ui->Singlescore->setText(str);
- _singleTimer.stop();
- ui->stackedWidget->setCurrentWidget(ui->SingleScore);
- }
- ui->lcdNumber->display(_singleSec);
-
- }
-
- //单人训练,从服务器获取题目
- void BrainStorm::getSingleQuestion()
- {
- QJsonObject json;
- json["cmd"]=SINGLE_QUESTION;
-
- _com->writeData(json);
-
- }
-
- //单人训练设置问题
- void BrainStorm::SingleSetQuestion()
- {
- //题目结束
- if(_currentSingleQuestion==QUESTION_NUM)
- {
- ui->Singleresult->setText("恭喜全部答对");
- QString str=QString("本次得分:%1").arg(_singleScore);
- ui->Singlescore->setText(str);
- ui->stackedWidget->setCurrentWidget(ui->SingleScore);
- _singleTimer.stop();
- return;
- }
- ui->SingleQuestion->setText(_singleQuestion["question"].toArray().at(_currentSingleQuestion).toString());
- ui->SingleButtonA->setText(_singleQuestion["selectionA"].toArray().at(_currentSingleQuestion).toString());
- ui->SingleButtonB->setText(_singleQuestion["selectionB"].toArray().at(_currentSingleQuestion).toString());
- ui->SingleButtonC->setText(_singleQuestion["selectionC"].toArray().at(_currentSingleQuestion).toString());
- ui->SingleButtonD->setText(_singleQuestion["selectionD"].toArray().at(_currentSingleQuestion).toString());
- }
-
- //单人训练答题
- void BrainStorm::SingleAnswerQuestion(int select)
- {
- //回答正确
- if(select==_singleQuestion["answer"].toArray().at(_currentSingleQuestion).toString().toInt())
- {
- _singleScore +=20*_singleSec;
- _currentSingleQuestion++;
- SingleSetQuestion(); //设置下一题
- _singleSec=10;
- _singleTimer.stop();
- ui->lcdNumber->display(_singleSec);
- _singleTimer.start(1000);
- }
- else//回答错误
- {
- ui->Singleresult->setText("回答错误");
- QString str=QString("本次得分:%1").arg(_singleScore);
- ui->Singlescore->setText(str);
- ui->stackedWidget->setCurrentWidget(ui->SingleScore);
- _singleTimer.stop();
- }
- }
-
- //单人训练从服务器接收到题目
- void BrainStorm::receiveSingleQuestion(QJsonObject json)
- {
- _singleQuestion=json;
- _singleSec=10;
- _currentSingleQuestion=0;
- _singleScore=0;
-
- ui->lcdNumber->display(_singleSec);
- SingleSetQuestion();
-
- //开启定时器
- _singleTimer.start(1000);
-
- ui->stackedWidget->setCurrentWidget(ui->SingleRuning);
- }
-
- //从个人训练返回
- void BrainStorm::on_SingleBack_clicked()
- {
- ui->stackedWidget->setCurrentWidget(ui->MainMenu);
- }
-
- //个人训练赛开始答题
- void BrainStorm::on_SingleStart_clicked()
- {
- getSingleQuestion();
- }
-
- void BrainStorm::on_OverBack_clicked()
- {
- ui->stackedWidget->setCurrentWidget(ui->MainMenu);
- }
-
- void BrainStorm::on_SingleButtonA_clicked()
- {
- SingleAnswerQuestion(1);
- }
-
- void BrainStorm::on_SingleButtonB_clicked()
- {
- SingleAnswerQuestion(2);
- }
-
- void BrainStorm::on_SingleButtonC_clicked()
- {
- SingleAnswerQuestion(3);
- }
-
- void BrainStorm::on_SingleButtonD_clicked()
- {
- SingleAnswerQuestion(4);
- }
-
- //--------------------------------------rank------------------------------------------
-
- //排位赛
- void BrainStorm::on_RankButton_clicked()
- {
- QJsonObject json;
- json["cmd"]=RANK;
-
- _com->writeData(json);
-
- //跳到等待页面
- ui->stackedWidget->setCurrentWidget(ui->RankWait);
- }
-
- void BrainStorm::RankTimerOut()
- {
- _rankSec--;
- if(_rankSec==0)
- {
- if(ui->RankButtonA->isEnabled())//判断随便一个按钮状态
- {
- _currentRankQuestion++;
- }
- rankSetQuestion();
- _rankSec=10;
- }
- ui->lcdNumber_2->display(_rankSec);
- }
-
- void BrainStorm::setEnemyScore()
- {
- QString str=QString("%1(%2):%3").arg(_enemyName,-5).arg(_enemyRank).arg(_enemyScore);
- ui->enemyStatus->setText(str);
- }
-
- void BrainStorm::setSelfScore()
- {
- QString str=QString("%1(%2):%3").arg(_userName,-5).arg(_userRank).arg(_myScore);
- ui->selfStatus->setText(str);
- }
-
- void BrainStorm::rankSetQuestion()
- {
- ui->RankQuestion->setText(_rankQuestion["question"].toArray().at(_currentRankQuestion).toString());
- ui->RankButtonA->setText(_rankQuestion["selectionA"].toArray().at(_currentRankQuestion).toString());
- ui->RankButtonB->setText(_rankQuestion["selectionB"].toArray().at(_currentRankQuestion).toString());
- ui->RankButtonC->setText(_rankQuestion["selectionC"].toArray().at(_currentRankQuestion).toString());
- ui->RankButtonD->setText(_rankQuestion["selectionD"].toArray().at(_currentRankQuestion).toString());
-
- ui->RankButtonA->setEnabled(true);
- ui->RankButtonB->setEnabled(true);
- ui->RankButtonC->setEnabled(true);
- ui->RankButtonD->setEnabled(true);
-
- ui->RankButtonA->setStyleSheet("");
- ui->RankButtonB->setStyleSheet("");
- ui->RankButtonC->setStyleSheet("");
- ui->RankButtonD->setStyleSheet("");
-
- if(_currentRankQuestion==QUESTION_NUM)
- {
- _rankTimer.stop();
- //将结果发给服务器
- QJsonObject json;
- json["cmd"] =RANKRESULT;
- json["score"] =_myScore;
- json["enemyName"] =_enemyName;
- json["enemyScore"]=_enemyScore;
-
- _com->writeData(json);
- }
- }
-
- void BrainStorm::rankSetResult(QJsonObject &json)
- {
- QString newRank=json["newRank"].toString();
- if(_myScore==_enemyScore)
- ui->rankResult->setText("平局");
- else if(_myScore<_enemyScore)
- ui->rankResult->setText("失败");
- else if(_myScore>_enemyScore)
- ui->rankResult->setText("成功");
-
- QString str=QString("%1 ---> %2").arg(_userRank).arg(newRank);
- ui->newRank->setText(str);
- _userRank=newRank;
-
- ui->stackedWidget->setCurrentWidget(ui->RankResult);
- }
-
- void BrainStorm::Rank(QJsonObject json)
- {
- int cmd=json["cmd"].toInt();
- if(cmd==RANK)
- {
- _rankQuestion=json["question"].toObject();
- _enemyName =json["enemyName"].toString();
- _enemyRank =json["enemyRank"].toString();
- _enemyScore =json["enemyScore"].toInt();
-
- _rankSec=10;
- _myScore=0;
- ui->lcdNumber_2->display(_rankSec);
-
- _currentRankQuestion=0;
- _enemyRankQuestion =0;
-
- setEnemyScore();
- setSelfScore();
- rankSetQuestion();
-
- _rankTimer.start(1000);
-
- ui->stackedWidget->setCurrentWidget(ui->RankRunning);
- }
- else if(cmd==ANSWER)//同步答题
- {
- _enemyScore =json["enemyscore"].toInt();
- _enemyRankQuestion=json["enemyQuestionId"].toInt();
- setEnemyScore();
-
- if(_currentRankQuestion==_enemyRankQuestion)
- {
- _rankSec=10;
- _rankTimer.stop();
- ui->lcdNumber_2->display(_rankSec);
- _rankTimer.start(1000);
- rankSetQuestion();
- }
- }
- else if(cmd==RANKRESULT)
- {
- rankSetResult(json);
- }
- }
-
- void BrainStorm::RankAnswerQuestion(int select)
- {
- //计算得分
- if(select==_rankQuestion["answer"].toArray().at(_currentRankQuestion).toString().toInt())
- _myScore +=20*_rankSec;
- setSelfScore();
- _currentRankQuestion++;
- //判断是否跳到下一题
- if(_currentRankQuestion==_enemyRankQuestion)
- {
- _rankSec=10;
- _rankTimer.stop();
- ui->lcdNumber_2->display(_rankSec);
- _rankTimer.start(1000);
- rankSetQuestion();
- }
-
- QJsonObject json;
- json["cmd"] =ANSWER;
- json["enemyName"]=_enemyName;
- json["score"] =_myScore;
- json["questionId"] =_currentRankQuestion;
-
- _com->writeData(json);//发送给服务器
- }
-
- void BrainStorm::on_RankButtonA_clicked()
- {
- ui->RankButtonA->setStyleSheet("background-color:rgb(255, 0, 0)");
- ui->RankButtonA->setEnabled(false);
- ui->RankButtonB->setEnabled(false);
- ui->RankButtonC->setEnabled(false);
- ui->RankButtonD->setEnabled(false);
- RankAnswerQuestion(1);
- }
-
- void BrainStorm::on_RankButtonB_clicked()
- {
- ui->RankButtonB->setStyleSheet("background-color:rgb(255, 0, 0)");
- ui->RankButtonA->setEnabled(false);
- ui->RankButtonB->setEnabled(false);
- ui->RankButtonC->setEnabled(false);
- ui->RankButtonD->setEnabled(false);
- RankAnswerQuestion(2);
- }
-
- void BrainStorm::on_RankButtonC_clicked()
- {
- ui->RankButtonC->setStyleSheet("background-color:rgb(255, 0, 0)");
- ui->RankButtonA->setEnabled(false);
- ui->RankButtonB->setEnabled(false);
- ui->RankButtonC->setEnabled(false);
- ui->RankButtonD->setEnabled(false);
- RankAnswerQuestion(3);
- }
-
- void BrainStorm::on_RankButtonD_clicked()
- {
- ui->RankButtonD->setStyleSheet("background-color:rgb(255, 0, 0)");
- ui->RankButtonA->setEnabled(false);
- ui->RankButtonB->setEnabled(false);
- ui->RankButtonC->setEnabled(false);
- ui->RankButtonD->setEnabled(false);
- RankAnswerQuestion(4);
- }
-
- void BrainStorm::on_overButton_clicked()
- {
- ui->stackedWidget->setCurrentWidget(ui->MainMenu);
- }
main.cpp
- #include "login.h"
- #include
-
- int main(int argc, char *argv[])
- {
- QApplication a(argc, argv);
- Widget w;
- w.show();
-
- return a.exec();
- }
-
相关阅读:
Laravel框架 - IOC容器详解
【STM32 CubeMX】移植u8g2(一次成功)
fluke dtx-1800测试精度有必要进行原厂校准吗?
Python接口自动化测试数据驱动DDT使用实战
架构师之路3. 富士康 - 再也不见
MySQL性能分析工具的使用
Hadoop和关系型数据库间的数据传输工具——Sqoop
中秋节祝福程序源代码分享:土地分类数据阈值筛选和重投影分类
怎样将例化的uvn test包含在verdi的instance中,并将其中变量加入到dump的波形中(方便verdi追test以及debug)
SpringBootWeb 篇-入门了解 Apache POI 使用方法
-
原文地址:https://blog.csdn.net/xaf21/article/details/126525122