根据之前的框架添加新的功能
登录
点击相关按钮
// 登录按钮的响应
void CMainDialog::OnBnClickedLogin()
{
// 1. 获取用户输入的数据
UpdateData(TRUE);
// 2. 判断输入的数据是否为空
if (m_UserName.IsEmpty() || m_PassWord.IsEmpty())
{
MessageBox(L"请输入用户名和密码");
return;
}
// 3. 填充需要发送的数据内容
SEND_INFO SendInfo = { TYPE::LOGIN, GetSafeHwnd() };
memcpy(SendInfo.LoginInfo.UserName, m_UserName.GetBuffer(), m_UserName.GetLength() * 2);
memcpy(SendInfo.LoginInfo.PassWord, m_PassWord.GetBuffer(), m_PassWord.GetLength() * 2);
// 4. 将数据通过自定义消息发送到服务器
SendMessage(UM_SEND_MSG, (WPARAM)& SendInfo, sizeof(SEND_INFO));
}
发送的结构体
// 1. 登录使用的的结构体
using LOGIN_INFO = _REGISTER_INFO;
using PLOGIN_INFO = _REGISTER_INFO*;
python接收到后处理的方法
客户端接接受到服务端发来的消息做的反应
主窗口响应,转发
// 响应登录
case TYPE::LOGIN:
{
// 对于注册是否成功的消息,wParam 没有用,lParam 指向 RECV_STATE
::SendMessage(RecvInfo->hWnd, UM_RECV_LOGIN, NULL, (LPARAM)& RecvInfo->RecvState);
break;
}
转发到的地方响应
// 是否登录成功
afx_msg LRESULT CMainDialog::OnUmRecvLogin(WPARAM wParam, LPARAM lParam)
{
// 将 lParam 转换成对应的的结构
PRECV_STATE RecvState = (PRECV_STATE)lParam;
// 判断是否登录成功
if (RecvState->IsSuccess)
{
// 弹出用户话框(好友、群组)
CUserDialog* dialog = new CUserDialog;
dialog->Create(IDD_USERDIALOG, this);
// [ 对话框必须是非模态的,否则会导致消息的阻塞 ]
// [ 对话框必须是保存在堆空间中,否则离开作用域会销毁 ]
return dialog->ShowWindow(SW_SHOWNORMAL);
}
// 不成功执行这里
MessageBox(RecvState->MsgInfo);
}
登录之后进到一个新的界面
获取父窗口句柄
//构造函数内设置主窗口
CUserDialog::CUserDialog(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_USERDIALOG, pParent)
, m_AddEdit(_T(""))
{
// 保存父窗口
MainDialog = (CMainDialog*)AfxGetMainWnd();
}
设置标题
初始化树控件
// 初始化对话框(获取用户和群组)
BOOL CUserDialog::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 隐藏父窗口
MainDialog->ShowWindow(SW_HIDE);
SetWindowText(MainDialog->m_UserName + L"主窗口");
// 添加好友分组和群组的节点
m_FrdNode = m_TreeCtrl.InsertItem(L"好友列表");
m_GrpNode = m_TreeCtrl.InsertItem(L"群组列表");
return TRUE;
}
C++客户端添加好友功能
客户端向服务器发送要添加的消息
获取要添加的名字
打包发送给服务器
/ 添加好友按钮的响应
void CUserDialog::OnBnClickedAddfrd()
{
// 1. 获取自己的名字和目标名称
UpdateData(TRUE);
CString MyName = MainDialog->m_UserName;
// 2. 自己不能添加自己为好友
if (MyName == m_AddEdit)
{
MessageBox(L"无法添加自己为好友!");
return;
}
// 3. 组合消息
SEND_INFO SendInfo = { TYPE::ADDFRD, GetSafeHwnd() };
memcpy(SendInfo.AddFrdInfo.User1, MyName.GetBuffer(), MyName.GetLength() * 2);
memcpy(SendInfo.AddFrdInfo.User2, m_AddEdit.GetBuffer(), m_AddEdit.GetLength() * 2);
// 4. 通过主窗口发送消息
::SendMessage(MainDialog->GetSafeHwnd(), UM_SEND_MSG, (WPARAM)& SendInfo, sizeof(SendInfo));
}
打包前得先弄信息结构体
// 2. 添加好友的消息
typedef struct _ADDFRD_INFO
{
WCHAR User1[32];
WCHAR User2[32];
} ADDFRD_INFO, * PADDFRD_INFO;
服务端接收到消息之后的处理
添加类型
添加方法
定义方法
添加新的表单friend_table
user1
user2
发送回客户端
客户端接收到服务器的反馈的反应
要用非模态的对话框,否则信息会堵塞
主窗口响应,转发
// 响应加好友
case TYPE::ADDFRD:
{
// 对于注册是否成功的消息,wParam 没有用,lParam 指向 RECV_STATE
::SendMessage(RecvInfo->hWnd, UM_RECV_ADDFRD, NULL, (LPARAM)& RecvInfo->RecvState);
break;
}
转发到的地方
// 查看是否成功
afx_msg LRESULT CUserDialog::OnUmRecvAddfrd(WPARAM wParam, LPARAM lParam)
{
// 将 lParam 转换成对应的的结构
PRECV_STATE RecvState = (PRECV_STATE)lParam;
// 判断是否添加成功
if (RecvState->IsSuccess)
{
// 如果成功执行直接添加到列表
m_TreeCtrl.InsertItem(RecvState->MsgInfo, m_FrdNode);
return 0;
}
// 不成功执行这里
MessageBox(RecvState->MsgInfo);
return 0;
}
更新好友列表
打开好友的时候会自动更新好友列表
初始化的时候发送请求
// 发消息给服务器更新好友列表
SEND_INFO SendInfo = { TYPE::UPDATEFRD, GetSafeHwnd() };
memcpy(SendInfo.UpdateFrdInfo.User, MainDialog->m_UserName.GetBuffer(),
MainDialog->m_UserName.GetLength() * 2);
// 通过主窗口向服务器发送消息
::SendMessage(MainDialog->GetSafeHwnd(), UM_SEND_MSG, (WPARAM)& SendInfo, sizeof(SendInfo));
相关的结构体
// 3. 更新好友列表
typedef struct _UPDATEFRD_INFO
{
WCHAR User[32];
} UPDATEFRD_INFO, * PUPDATEFRD_INFO;
服务器接收到处理之后发回来
客户端接受到消息之后处理
主窗口响应,转发
// 响应更新好友
case TYPE::UPDATEFRD:
{
// 对于注册是否成功的消息,wParam 没有用,lParam 指向 RECV_STATE
::SendMessage(RecvInfo->hWnd, UM_RECV_UPDATEFRD, NULL, (LPARAM)& RecvInfo->RecvState);
break;
}
转发到的地方
// 响应更新好友的消息
afx_msg LRESULT CUserDialog::OnUmRecvUpdatefrd(WPARAM wParam, LPARAM lParam)
{
// 转换成对应的结构体
PUPDATEFRD_INFO UserInfo = (PUPDATEFRD_INFO)lParam;
// 【添加到树控件的好友节点中,收到的消息前两个字节会是 ff fe】
m_TreeCtrl.InsertItem(&UserInfo->User[1], m_FrdNode);
return 0;
}
好友私聊
私聊窗口的界面
客户端的话,双击树控件的好友的时候要能弹出聊天窗口,
所以需要响应树控件按钮
字典#include<map>
using namespace std:
判断是不是好友窗口,群窗口同理
窗口可以双击打开,
// 响应窗口聊天
void CUserDialog::OnDblclkTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
// 1. 获取当前点击的这一个子节点的内容
HTREEITEM CurrentNode = m_TreeCtrl.GetSelectedItem();
CString Name = m_TreeCtrl.GetItemText(CurrentNode);
// 2. 判断节点是不是[好友列表]或者[群组列表]
if (Name.Compare(L"好友列表") && Name.Compare(L"群组列表"))
{
// 3.1 判断窗口是否已经存在
if (MainDialog->WindowsMap.find(Name) != MainDialog->WindowsMap.end())
{
// 存在则显示,确保一个窗口只会被打开一次
MainDialog->WindowsMap[Name]->ShowWindow(SW_SHOWNORMAL);
}
// 3.2 判断是不是好友聊天窗口
else if (m_TreeCtrl.GetParentItem(CurrentNode) == m_FrdNode)
{
// 3.2.1 创建用户聊天窗口
CFrdDialog* dialog = new CFrdDialog(Name);
dialog->Create(IDD_DIALOG2, this);
// 3.2.2 设置用户聊天窗口的窗口名为点击的文字
dialog->SetWindowText(Name);
dialog->ShowWindow(SW_SHOWNORMAL);
// 3.2.3 将新创建的窗口添加到字典中
MainDialog->WindowsMap[Name] = dialog;
}
// 3.3 判断是不是群组聊天窗口
else if (m_TreeCtrl.GetParentItem(CurrentNode) == m_GrpNode)
{
// 3.3.1 创建群组聊天窗口
CGrpDialog* dialog = new CGrpDialog(Name);
dialog->Create(IDD_DIALOG3, this);
// 3.3.2 设置群组聊天窗口的窗口名为点击的文字
dialog->SetWindowText(Name);
dialog->ShowWindow(SW_SHOWNORMAL);
// 3.3.3 将新创建的窗口添加到字典中
MainDialog->