目前可以聊天啦。。下面是截图
动手锻炼锻炼。。学习到了数据库、网络编程、多线程方面的知识。。感觉还是蛮好的。。等待进一步优化添加功能吧。。
下面贴上服务端和客户端的头文件。
#ifndef CLIENTCONTROLLER_H
#define CLIENTCONTROLLER_H
class ClientSocket;
class Client_UI;
class login;
#include
class ClientController :public QObject
{
Q_OBJECT
public:
ClientController();
private:
ClientSocket* clientSocket;
Client_UI* clientUI;
login* loginUI;
private slots:
void OnTryLogin(QString account, QString password);
void OnPermitLogin(quint32 ID, QString &name, QString &sign, quint32 picNumber);
void OnRefuseLogin();
// void OnReceiveFriendMessage(quint32 ID,QString& Message);
// void OnSendMessage(quint32 ID, QString& Message);
};
#endif // CLIENTCONTROLLER_H
#ifndef CLIENTSOCKET_H
#define CLIENTSOCKET_H
#include
class ClientSocket : public QTcpSocket
{
Q_OBJECT
public:
ClientSocket(const QString& hostAddress,
const QString& port,
const QString& account,
const QString& password,
QObject* parent =0 );
enum Client_msgType{msg_login,msg_offLine,msg_SendMessage,msg_SearchFriend,msg_AddFriend};//枚举消息类型
enum Server_msgType{msg_permitLogin,
msg_refuseLogin,
msg_FriendMessage,
msg_systemMessage,
msg_ContactorInformation = 10,
msg_CreateList,
msg_FriendOnline,
msg_FriendOffline};//枚举服务端发送来的消息类型
private:
QString account;
QString password;
quint16 blockSize;
private slots:
void Translate_Message();//解析服务端发送来的消息
void tryLogin();//尝试登录
void OnReceiveMessage();
void SendMessage(quint32 ID, QString &Message);
void OnSocketError(QAbstractSocket::SocketError socketError);
// void offLine(); //下线
// void SendMessage(quint32 ID,QString& message); //发送消息给好友
// void SearchFriend(QString& cmd);//查找好友
// void AddFriend(quint32 ID);//添加好友
// void OnPermitLogin();//允许登录
// void OnRefuseLogin();//拒绝登录
// void OnCreateList(QString& GroupName);//创建列表
// void OnReceiveContactorInformation(quint32 ID,
// QString& groupName,
// QString& name,
// quint32& picNumber,
// QString& sign,
// bool online);//获得好友信息
// void OnReceiveFriendMessage(quint32 ID,QString& message);//收到来自好友的消息
// void OnReceiveSystemMessage(QString& message);//收到系统消息
signals:
void permitLogin(quint32 ID,QString& name,QString& sign,quint32 picnNumber);//允许登录
void refuseLogin();//拒绝登录
void ReceiveContactorInformation(QString& groupName,
quint32 ID,
QString& name,
QString& sign,
quint32 picNumber,
bool online);//获得好友信息
void ReceiveFriendMessage(quint32 ID,QString& message);//收到来自好友的消息
// void ReceiveSystemMessage(QString& message);//收到系统消息
void CreateList(QString& GroupName);//创建列表
};
#endif // CLIENTSOCKET_H
#ifndef LOGIN_H
#define LOGIN_H
#include
#include
namespace Ui {
class login;
}
class login : public QWidget
{
Q_OBJECT
public:
explicit login(QWidget *parent = 0);
~login();
private:
Ui::login *ui;
protected:
void mousePressEvent(QMouseEvent *);
void mouseMoveEvent(QMouseEvent *);
void paintEvent(QPaintEvent*);
private:
QPoint dragPosition;
QPixmap pic;
// QSqlDatabase database;
private slots:
void OnLoginButtonPressed();
void OnRefuseLogin();
signals:
void login_request(QString account,QString password);
};
#endif // LOGIN_H
#ifndef UITREEWIDGETITEM_H
#define UITREEWIDGETITEM_H
#include
class uiTreeWidgetItem :public QTreeWidgetItem { private: quint32 Id; QString Name; QString Sign; quint32 PicNumber; public: uiTreeWidgetItem(quint32 ID,QString& name,QString&sign,quint32 picNumber); quint32 ID(); QString name(); QString sign(); quint32 picNumber(); bool hasReceiveMessage; }; #endif // UITREEWIDGETITEM_H #include "client_ui.h" #include "ui_client_ui.h" #include
#include
#include
#include"../TreeWidgetTest/mytreewidgetitem.h" #include"../MusicPlayer/no_focus_delegate.h" #include
#include
#include"../QChat_Dialog/dialog.h" #include"uitreewidgetitem.h" #include
#include
Client_UI::Client_UI(quint32 ID, QString &name, QString sign, quint32 picNumber, QWidget *parent) : QWidget(parent), ui(new Ui::Client_UI) { ui->setupUi(this); setWindowFlags(Qt::FramelessWindowHint);//设置窗体无边框 //setAttribute(Qt::WA_TranslucentBackground);//设置背景透明 initButton(); initContactorWiget(); ui->sign_label->setText(sign); ui->ID_label->setText(name+"("+QVariant(ID).toString()+")"); QPixmap pic("./head/"+QVariant(picNumber).toString()+".png"); ui->personal_iamge->setPixmap(pic); dialog = new Dialog; connect(dialog,SIGNAL(SendMessage(quint32,QString&)),this,SLOT(DispSendMessage(quint32,QString&))); connect(ui->close_button,SIGNAL(clicked(bool)),SLOT(close())); connect(ui->minimize_button,SIGNAL(clicked(bool)),this,SLOT(showMinimized())); connect(ui->contactor_widget,SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this,SLOT(OnTreeWidgetItemDobuleClick(QTreeWidgetItem*,int))); connect(dialog,SIGNAL(ChatDialogClose()),SLOT(OnChatDialogClose())); connect(dialog,SIGNAL(CurrentChatClose(quint32)),SLOT(OnCurrentChatClose(quint32))); } Client_UI::~Client_UI() { delete ui; } void Client_UI::mousePressEvent(QMouseEvent * event) { if (event->button() == Qt::LeftButton) { dragPosition = event->globalPos() - frameGeometry().topLeft(); event->accept(); } } void Client_UI::mouseMoveEvent(QMouseEvent * event) { if (event->buttons() & Qt::LeftButton) { move(event->globalPos() - dragPosition); event->accept(); } } void Client_UI::initButton() { //minimize and close buttons QString minimize_button_style = QString("QPushButton#minimize_button{\ border-image: url(:/image/client_ui/images/client_ui/client_minimize_button.png)}\ QPushButton#minimize_button:hover{\ border-image: url(:/image/client_ui/images/client_ui/client_minimize_button_hover.png)}" ); QString close_button_style = QString("QPushButton#close_button{\ border-image: url(:/image/client_ui/images/client_ui/client_close_button.png)}\ QPushButton#close_button:hover{\ border-image: url(:/image/client_ui/images/client_ui/client_close_button_hover.png)}"); ui->minimize_button->setStyleSheet(minimize_button_style); ui->close_button->setStyleSheet(close_button_style); //contactor button QString contactor_button_style = QString("QPushButton#contactor_button{\ border-image: url(:/image/client_ui/images/client_ui/contactor.png)}\ QPushButton#contactor_button:hover{\ border-image: url(:/image/client_ui/images/client_ui/contactor_hover.png)}\ QPushButton#contactor_button:pressed{\ border-image: url(:/image/client_ui/images/client_ui/contactor_pressed.png)}" ); \ ui->contactor_button->setStyleSheet(contactor_button_style); //group button QString group_button_style = QString("QPushButton#group_button{\ border-image: url(:/image/client_ui/images/client_ui/group.png)}\ QPushButton#group_button:hover{\ border-image: url(:/image/client_ui/images/client_ui/group_hover.png)}\ QPushButton#group_button:pressed{\ border-image: url(:/image/client_ui/images/client_ui/group_pressed.png)}" ); \ ui->group_button->setStyleSheet(group_button_style); //search button QString search_button_style = QString("QPushButton#search_button{\ border-image: url(:/image/client_ui/images/client_ui/search_button.png)}\ QPushButton#search_button:hover{\ border-image: url(:/image/client_ui/images/client_ui/search_button_hover.png)}" ); \ ui->search_button->setStyleSheet(search_button_style); } void Client_UI::initContactorWiget() { QTreeWidget* tree=ui->contactor_widget; tree->setColumnCount(1); tree->setIndentation(10); tree->setHeaderHidden(true); // tree->setRootIsDecorated(false); tree->setColumnWidth(0,200); /* for(int i=0;i<3;++i){ tree->addTopLevelItem(new QTreeWidgetItem(QStringList(tr("item%1").arg(i)))); for(int j=0;j<3;++j){ myTreeWidgetItem* item=new myTreeWidgetItem; tree->topLevelItem(i)->addChild(new QTreeWidgetItem); tree->topLevelItem(i)->child(j)->setSizeHint(0,item->size()); tree->setItemWidget(tree->topLevelItem(i)->child(j),0,item); } } */ tree->horizontalScrollBar()->hide(); QFile file(":/QSS/my_scrollBar.qss"); file.open(QFile::ReadOnly); tree->verticalScrollBar()->setStyleSheet(file.readAll()); file.close(); file.setFileName(":/QSS/my_treeview.qss"); file.open(QFile::ReadOnly); tree->setStyleSheet(file.readAll()); file.close(); QFont font=tree->font(); font.setPixelSize(15); tree->setFont(font); tree->resizeColumnToContents(0); // tree->setItemDelegate(new NoFocusDelegate); } void Client_UI::create_list(QString& groupname) //创建列表 { ui->contactor_widget->addTopLevelItem(new QTreeWidgetItem(QStringList(groupname))); //listname_index<<(list_name+QVariant(listname_index.size()).toString()); } void Client_UI::add2list(QString& groupname, //分组名 quint32 ID, QString& name, //昵称 QString& sign, //个性签名 quint32 picNumber, //图片 bool online) //是否在线 { QPixmap pic("./head/"+QVariant(picNumber).toString()+".png"); myTreeWidgetItem* item = new myTreeWidgetItem(name,ID,sign,pic,online); QTreeWidget* tree = ui->contactor_widget; QTreeWidgetItem* toplevelItem; int i=0; while(i
topLevelItemCount()){ toplevelItem = ui->contactor_widget->topLevelItem(i); if(toplevelItem->text(0)== groupname){ //找到列表 break; } ++i; } if(i == tree->topLevelItemCount()){ //列表不存在,插入列表 create_list(groupname); toplevelItem = ui->contactor_widget->topLevelItem(i); } //插入信息 int childIndex = toplevelItem->childCount(); //下一个child的index toplevelItem->addChild(new uiTreeWidgetItem(ID,name,sign,picNumber)); toplevelItem->child(childIndex)->setSizeHint(0,item->size()); //调整item的大小 tree->setItemWidget(toplevelItem->child(childIndex),0,item); } void Client_UI::DispReceiveMessage(quint32 ID, QString &Message) { QTreeWidget* tree = ui->contactor_widget; //这不仅是建立会话的逻辑,也是图标闪烁的逻辑 for(int i=0;i
topLevelItemCount();++i){ for(int j=0;j
topLevelItem(i)->childCount();++j){ uiTreeWidgetItem* temp = (uiTreeWidgetItem*)(tree->topLevelItem(i)->child(j)); if(temp->ID() == ID){ QString tempstring =temp->name()+"("+QVariant(ID).toString()+")" +" "+QTime::currentTime().toString(); if(temp->hasReceiveMessage == false){ //如果还没建立对话 QPixmap pic("./head/"+QVariant(temp->picNumber()).toString()+".png"); dialog->addConversation(pic,ID,temp->name(),temp->sign()); temp->hasReceiveMessage = true; dialog->show(); dialog->AppendMessage(tempstring); dialog->AppendMessage(Message); QString space("\n"); dialog->AppendMessage(space); qDebug()<<"来新对话了"; } else{ //已经建立对话了 dialog->AppendMessage(tempstring,ID); dialog->AppendMessage(Message,ID); QString space("\n"); dialog->AppendMessage(space,ID); qDebug()<<"来消息了"; } return; } } } } void Client_UI::DispSendMessage(quint32 ID,QString& Message) { QString temp = ui->ID_label->text()+" "+QTime::currentTime().toString(); dialog->AppendMessage(temp); dialog->AppendMessage(Message); QString space("\n"); dialog->AppendMessage(space); emit SendMessage(ID,Message); } void Client_UI::OnTreeWidgetItemDobuleClick(QTreeWidgetItem *item, int column) { for(int i=0;i
contactor_widget->topLevelItemCount();++i){ if(item == ui->contactor_widget->topLevelItem(i)){ return; } } dialog->show(); uiTreeWidgetItem* temp = (uiTreeWidgetItem*)(item); if(temp->hasReceiveMessage) return; QPixmap pic("./head/"+QVariant(temp->picNumber()).toString()+".png"); dialog->addConversation(pic,temp->ID(),temp->name(),temp->sign()); temp->hasReceiveMessage = true; } void Client_UI::OnChatDialogClose() { QTreeWidget* tree = ui->contactor_widget; for(int i=0;i
topLevelItemCount();++i){ for(int j=0;j
topLevelItem(i)->childCount();++j){ uiTreeWidgetItem* temp = (uiTreeWidgetItem*)(tree->topLevelItem(i)->child(j)); if(temp->hasReceiveMessage) temp->hasReceiveMessage = false; } } } void Client_UI::OnCurrentChatClose(quint32 ID) { QTreeWidget* tree = ui->contactor_widget; for(int i=0;i
topLevelItemCount();++i){ for(int j=0;j
topLevelItem(i)->childCount();++j){ uiTreeWidgetItem* temp = (uiTreeWidgetItem*)(tree->topLevelItem(i)->child(j)); if(temp->ID() == ID){ temp->hasReceiveMessage = false; return; } } } }
#ifndef SENDCONTACTORTHREAD_H
#define SENDCONTACTORTHREAD_H
#include
#include
#include
#include
#include
#include"dboperation.h" //这是一个发送联系人列表的线程 class SendContactorThread:public QThread { Q_OBJECT public: SendContactorThread(quint32 ID); enum msgType{msg_memberinfomation=10,msg_createList}; QList
data; //用来存储待发送的消息 // QThread interface protected: void run() Q_DECL_OVERRIDE; private: // QStringList grouplist; //分组名 quint32 ID; //ID号 quint32 index; qintptr socketDescriptor; //套接字 static QList
vcuumNumberList;//维护一个可用连接名的列表 static int usedNumberCount; //总个数,包括已经消失的连接 signals: void DataReadyRead(QList
); private slots: void OnFinished(); }; #endif // SENDCONTACTORTHREAD_H #ifndef SERVER_H #define SERVER_H #include
#include
class DbOperation; class sendAddressThread; class Server:public QTcpServer { Q_OBJECT public: Server(QObject* parent=0); private: sendAddressThread* thread; QList
clientlist;//维护一张客户端socket列表 QList
vacuumIndex;//维护当前空白的序号列表 DbOperation* dboperation;//数据库操作 protected: void incomingConnection(qintptr socketDescriptor) Q_DECL_OVERRIDE; // void addPendingConnection(TcpClientSocket* tcpsocket) Q_DECL_OVERRIDE; ~Server(); private slots: void OnLoginRequest(QString& account,QString& password,TcpClientSocket* socket); void OnClientDisconnected(TcpClientSocket* socket); void OnSendMessage(quint32 ID,QString& message,TcpClientSocket* socket); public: enum Server_msgType{msg_permitLogin,msg_refuseLogin,msg_FriendMessage,msg_systemMessage};//枚举消息类型 }; #endif // SERVER_H #ifndef SOCKETTHREAD_H #define SOCKETTHREAD_H #include
#include
class QMutex; class SocketThread:public QThread { Q_OBJECT public: SocketThread(qintptr socketDescriptor,QObject* parent=0); void run() Q_DECL_OVERRIDE; private: qintptr socketDescriptor; signals: void error(QTcpSocket::SocketError socketError); }; #endif // SOCKETTHREAD_H #ifndef TCPCLIENTSOCKET_H #define TCPCLIENTSOCKET_H #include
class TcpClientSocket:public QTcpSocket { Q_OBJECT public: explicit TcpClientSocket(QObject* parent=0); enum Client_msgType{msg_login,msg_offLine,msg_SendMessage,msg_SearchFriend,msg_AddFriend};//枚举消息类型 quint32 id(); signals: void loginRequest(QString& account,QString& password,TcpClientSocket* socket); //登录请求 void offLine(); //下线 void SendMessage(quint32 ID,QString& message,TcpClientSocket* socket); //发送消息 void SearchFriend(QString& cmd,TcpClientSocket* socket);//查找好友 void AddFriend(QString& account,TcpClientSocket* socket);//添加好友 void SocketDisconnect(TcpClientSocket* socket); private: qint16 blockSize; //数据块大小 QString account; //账号 quint32 ID; //数字ID void TranslateMessage(); public: quint32 index; //在LIST中的编号 void SetID(quint32 id); private slots: void OnReceiveMessage(); void OnDisConnected(); void OnDataReadyRead(QList
Datalist); }; #endif // TCPCLIENTSOCKET_H #ifndef DBOPERATION_H #define DBOPERATION_H #include
#include
//数据库操作类 class DbOperation :public QObject { Q_OBJECT public: explicit DbOperation(const QString& name,const QString& connectionName);//打开数据库 bool comparePassword(const QString& account, const QString& password, QSqlRecord *&record);//比较账号密码 void GetContactors(quint32 ID, QStringList* GroupList, QList
*friendid);//获取联系人列表和成员 QSqlRecord GetUserInformation(quint32 ID);//获取用户信息 bool AddRecord(quint32 ID, const QString& account, const QString& password, bool online, const QString& Login_ip, const QString& name, const QString& sign, quint32 picNumber);//插入一条记录 bool changePassword(quint32 ID,const QString& password); //修改密码 bool changePic(quint32 ID,quint32 picNmuber);//修改图片 void setOnline(quint32 ID);//上线 void setOffline(quint32 ID);//下线 ~DbOperation(); private: QSqlDatabase db; signals: void OpenDataBaseError();//打开数据库错误 }; #endif // DBOPERATION_H