C#聊天室客户端完整③

窗体

进入聊天室界面(panel里面,label,textbox,button):

聊天界面(flowLayoutPanel(聊天面板)):

文档大纲(panel设置顶层(登录界面),聊天界面在底层)

步骤:设置进入聊天室→输入聊天→右边自己发送的消息→左边别人发的消息

MyClient.cs(进入聊天室类)

internal class MyClient
{// 定义委托类型public delegate void UpdatLabelHandle(string str = "");// 声明委托变量public UpdatLabelHandle LabelInfo;// 接受和发送消息 创建连接对象写在异步里面Thread thConnect; // 连接服务器的线程TcpClient client;  // 全局客户端对象public bool IsConnect;// 是否连接成功Thread receiveThread;// 接收消息的线程Thread sendThread;// 发送消息的线程Thread updateChatThread;// 更新聊天室ui的线程public MyClient() {thConnect = new Thread(ConnetServer);thConnect.Start();}public void ConnetServer(){client = new TcpClient();// 开启一个异步的连接// 参数1 ip地址// 2 端口号// 3 回调函数 看一判断是否连接成功// 4 传递回调函数的参数client.BeginConnect(IPAddress.Parse("192.168.107.72"),3333,requestCallBack,client);float num = 0;while (IsConnect == false){// 证明没有连接成功num += 0.1f;if (LabelInfo != null) LabelInfo(); // 不传参数的目的if (num >= 10f){return;//超时连接 10s连接不上就连接失败}Thread.Sleep(100);}if (IsConnect==true)// {NetworkStream stream = client.GetStream();// 在此处开启分线程接收发送消息,更新uisendThread = new Thread(sendHandle);sendThread.Start(stream);receiveThread = new Thread(receiveHandle);receiveThread.Start(stream);updateChatThread = new Thread(updateHandle);updateChatThread.Start();}}// 把消息保存队列中// 可以存储数据结合,先进先出的特点,如果先添加一个你好,你好可以通过方法先取出来// Queue 队列 先进先出例如买饭// 数组 先进后出的 进电梯public Queue<string> SendQueue = new Queue<string>();// 发消息public void sendHandle(object obj){NetworkStream stream = obj as NetworkStream;try{while (IsConnect){if (SendQueue.Count>0)// 发短消息不为空 如果把窗体里面发消息文本内容取到此处{string msg = SendQueue.Dequeue();// 取出先放进去的数据byte[] bs = Encoding.UTF8.GetBytes(msg);stream.Write(bs,0,bs.Length);}}}catch(Exception ex){Console.WriteLine("send"+ex.Message);}}public Queue<string> receiveQueue = new Queue<string>();// 接受消息public void receiveHandle(object obj){NetworkStream stream = obj as NetworkStream;try{while (IsConnect){byte[] bs = new byte[1024];int length = stream.Read(bs, 0, bs.Length);string s = Encoding.UTF8.GetString(bs, 0, length);receiveQueue.Enqueue(s);}}catch (Exception e){Console.WriteLine("receive"+e.Message);}}// 定义委托类型 接受UpdateChatUI方法public delegate void updateChatHandle(string s, bool a = false);// 定义委托变脸public updateChatHandle F1;// 更新uipublic void updateHandle(){while (true){if (F1!=null&& receiveQueue.Count>0){F1(receiveQueue.Dequeue(), false);}}}// IAsyncResult 异步结果的类// BeginConnect 的回调函数 不管成功与否都执行public void requestCallBack(IAsyncResult ar){TcpClient t = ar.AsyncState as TcpClient;// 通过AsyncState异步状态属性获取参数if (t.Connected) // 如果连接成功了{IsConnect = true;LabelInfo("连接成功");t.EndConnect(ar); // 结束挂起的状态 }else{//  连接失败 LabelInfo("连接失败");}LabelInfo = null;}public void Stop(){if (IsConnect){IsConnect = false;if (client!=null){client.Close();client = null;}// 把线程终端if (thConnect!=null){thConnect.Abort();// 终止线程}if (sendThread != null){sendThread.Abort();}if (receiveThread != null){receiveThread.Abort();}if (updateChatThread!= null){updateChatThread.Abort();}}}
}

ItemRight.cs(右边信息类)

public class ItemLeft:Panel
{// 聊天气泡 label和圆形的头像// 消息内容 和父窗体的宽度public ItemLeft(string msg, int parentWidth){this.Font = new Font("楷体", 18);// 设置气泡宽度this.Width = parentWidth - 20 - 6;PictureBox pic = new PictureBox();pic.Image = Image.FromFile("D:\\李克课件\\Csharp\\网络通信\\6.13聊天室服务器\\02 聊天室客户端\\大爱仙尊.jpg");pic.Width = 60;pic.Height = 60;pic.SizeMode = PictureBoxSizeMode.StretchImage;// 把图片压缩以适应盒子大小pic.Location = new Point(10, 10);// 右边头像的位置// 设置头像圆形 通过绘制绘制圆形GraphicsPath gp = new GraphicsPath();// 创建一个绘制线对象gp.AddEllipse(pic.ClientRectangle);Region re = new Region(gp);// 绘制的椭圆生成一个区域图片pic.Region = re;// 把区域图片赋值给picthis.Controls.Add(pic);// 绘制label// 计算msg宽度和高度Graphics g = this.CreateGraphics();// 创建绘制对象int exceptWidth = this.Width - 200; // 期望宽度// MeasureString 测量指定这个字符串的长度或者宽度// 参数1 测量的字符串// 2 指定字符串// 3 一行盼望的宽度float width = g.MeasureString(msg, this.Font, exceptWidth).Width;float height = g.MeasureString(msg, this.Font, exceptWidth).Height;Label l = new Label();l.Text = msg;l.BackColor = Color.Green;l.Location = new Point(80, 10);l.Width = (int)width;l.Height = (int)height;this.Controls.Add(l);// 更新panel的高度if ((int)height + 20 < 80){this.Height = 80;}else{this.Height = (int)height + 20;}//re.Dispose();// 释放资源//gp.Dispose();}   
}

ItemRight.cs(左边聊天框)

    // 聊天气泡 label和圆形的头像// 消息内容 和父窗体的宽度public ItemLeft(string msg, int parentWidth){this.Font = new Font("楷体", 18);// 设置气泡宽度this.Width = parentWidth - 20 - 6;PictureBox pic = new PictureBox();pic.Image = Image.FromFile("D:\\李克课件\\Csharp\\网络通信\\6.13聊天室服务器\\02 聊天室客户端\\大爱仙尊.jpg");pic.Width = 60;pic.Height = 60;pic.SizeMode = PictureBoxSizeMode.StretchImage;// 把图片压缩以适应盒子大小pic.Location = new Point(10, 10);// 右边头像的位置// 设置头像圆形 通过绘制绘制圆形GraphicsPath gp = new GraphicsPath();// 创建一个绘制线对象gp.AddEllipse(pic.ClientRectangle);Region re = new Region(gp);// 绘制的椭圆生成一个区域图片pic.Region = re;// 把区域图片赋值给picthis.Controls.Add(pic);// 绘制label// 计算msg宽度和高度Graphics g = this.CreateGraphics();// 创建绘制对象int exceptWidth = this.Width - 200; // 期望宽度// MeasureString 测量指定这个字符串的长度或者宽度// 参数1 测量的字符串// 2 指定字符串// 3 一行盼望的宽度float width = g.MeasureString(msg, this.Font, exceptWidth).Width;float height = g.MeasureString(msg, this.Font, exceptWidth).Height;Label l = new Label();l.Text = msg;l.BackColor = Color.Green;l.Location = new Point(80, 10);l.Width = (int)width;l.Height = (int)height;this.Controls.Add(l);// 更新panel的高度if ((int)height + 20 < 80){this.Height = 80;}else{this.Height = (int)height + 20;}//re.Dispose();// 释放资源//gp.Dispose();}   
}

窗体代码

public partial class Form1 : Form
{Timer timer;// 定时器bool isRunning = false;// 开关MyClient client;public Form1(){InitializeComponent();this.flowLayoutPanel1.AutoScroll = true;timer = new Timer(){Interval = 100, // 时间间隔};timer.Tick += (send, arg) =>{isRunning = false;timer.Stop();};}// 进入聊天室按钮方法private void button1_Click(object sender, EventArgs e){if (!string.IsNullOrEmpty(textBox1.Text)){// 开始连接服务器 封装一个自定义客户端类client = new MyClient(); // 给client委托赋值updateLabelclient.LabelInfo = updateLabel;client.F1 = UpdateChatUI;// 把方法赋值给f1变量}else{MessageBox.Show("请输入你的名字");}}public List<string> list1 = new List<string>() { "拼命加载中", "拼命加载中.", "拼命加载中..", "拼命加载中..." };int index = 0;// 封装一个更新label的方法public void updateLabel(string str){this.Invoke((Action)(() =>{if (string.IsNullOrEmpty(str))// 正在连接中{label1.Text = list1[index];index++;if (index == list1.Count) index = 0;}else // 证明连接有结果时候{this.label1.Text = str;// 需要判断如果连接成功了 需要进入聊天室if (client.IsConnect){// 登录成功 现实聊天界面nullthis.Controls.Remove(this.panel1);this.Text = this.textBox1.Text;// 修改窗体标题}}}));}// 发送消息的按钮的方法// 1 给服务器发送消息,封装MyClient.cs文件中// 2 更新聊天界面,封装到form1.cs文件中,如果MyClient.cs需要使用把封装更新UI传递过去// 使用委托// 3 聊天界面 自定义控件区分到底是谁的消息private void button2_Click(object sender, EventArgs e){if (isRunning){return;}isRunning = true;timer.Start();Console.WriteLine("111");string msg = this.textBox2.Text.Trim();if (msg.Length != 0){// 开始服务器发送消息 封装MyClient.cs文件中msg = this.Text + "说:" + msg;// 把msg发送队列client.SendQueue.Enqueue(msg);//添加数据到队列里面// 更新UIUpdateChatUI(msg,true);// 再次输入this.textBox2.Text = "";}}// 展示聊天室// 参数1 是消息内容// 参数2 是否是自己发的消息public void UpdateChatUI(string msg,bool isSelf){this.Invoke((Action)(() =>{Panel item = null;if (isSelf) // 显示在右边{item = new ItemRight(msg, flowLayoutPanel1.Width);}else // 别人发的消息 显示左边{item = new ItemLeft(msg, flowLayoutPanel1.Width);}// 显示在flowlayoutpanel上,this.flowLayoutPanel1.Controls.Add(item);// 让flowLayoutPanel1 滚动到最下面this.flowLayoutPanel1.VerticalScroll.Value = this.flowLayoutPanel1.VerticalScroll.Maximum;}));}private void Form1_FormClosing(object sender, FormClosingEventArgs e){if (client != null){client.Stop();client = null;}}// 进入聊天室private void textBox1_KeyDown(object sender, KeyEventArgs e){if (e.KeyCode ==Keys.Enter){// 点击了Ennter键button1_Click(null, null);}}private void textBox2_KeyDown(object sender, KeyEventArgs e){if (e.KeyCode == Keys.Enter){// 点击了Ennter键button2_Click(null, null);}}
}

天才是百分之九十九的汗水加百分之一的灵感

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/29054.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何利用TikTok矩阵源码实现自动定时发布和高效多账号管理

在如今社交媒体的盛行下&#xff0c;TikTok已成为全球范围内最受欢迎的短视频平台之一。对于那些希望提高效率的内容创作者而言&#xff0c;手动发布和管理多个TikTok账号可能会是一项繁琐且耗时的任务。幸运的是&#xff0c;通过利用TikTok矩阵源码&#xff0c;我们可以实现自…

Linux C语言:字符串处理函数

一、字符串函数 1、C库中实现了很多字符串处理函数 #include <string.h> ① 求字符串长度的函数strlen② 字符串拷贝函数strcpy③ 字符串连接函数strcat④ 字符串比较函数strcmp 2、字符串长度函数strlen 格式&#xff1a;strlen(字符数组)功能&#xff1a;计算字符串…

【Python】已解决报错:AttributeError: module ‘json‘ has no attribute ‘loads‘解决办法

&#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主。 &#x1f913; 同时欢迎大家关注其他专栏&#xff0c;我将分享Web前后端开发、人工智能、机器学习、深…

1)Java项目笔记搭建系统梳理相关知识

目录 前言项目结构Java部分Spring整合部分SpringBoot整合部分 模块说明规划 小结javarabbitmqmybatisspring最后推荐几本工具书 前言 工作有年头了&#xff0c;学到了很多技术&#xff0c;收获了很多。但是对与工作相关的专业技能知识的掌握杂而乱&#xff0c;不够全面系统。因…

Web应用安全测试-综合利用(一)

Web应用安全测试-综合利用&#xff08;一&#xff09; 文章目录 Web应用安全测试-综合利用&#xff08;一&#xff09;1.跨站脚本攻击&#xff08;XSS&#xff09;漏洞描述测试方法GET方式跨站脚本Post方式跨站脚本 风险分析风险等级修复方案总体修复方式对于java进行的web业务…

21.FuturePromise

在异步处理时,经常用到两个接口Future 和 Promise。 说明:Netty中的Future与jdk中的Future同名,但是是两个接口,netty的Future继承了jdk的Future,而Promise又对Netty的Future进行了扩展。 JDK的Future只能同步等待任务结束(成功、失败)才能得到结果。FutureTask.get()方…

ROS中使用超声波传感器(附代码)

在ROS中使用超声波传感器通常涉及到订阅或发布sensor_msgs/Range类型的消息。下面是一个简单的示例&#xff0c;展示了如何使用C在ROS中编写一个超声波传感器的驱动程序。这个例子假设你有一个超声波传感器连接到了Arduino或者其他微控制器&#xff0c;并且该微控制器已经通过串…

SpringBoot三层架构

目录 一、传统方式 二、三层架构 三、代码拆分 1、dao层 2、service层 3、control层 四、运行结果 一、传统方式 上述代码存在一定的弊端&#xff0c;在进行软件设计和软件开发中提倡单一责任原则&#xff0c;使代码的可读性更强&#xff0c;复杂性更低&#xff0c;可扩展性…

QT day03

思维导图 QT设计 升级优化自己应用程序的登录界面。 要求&#xff1a; 1. qss实现 2. 需要有图层的叠加 &#xff08;QFrame&#xff09; 3. 设置纯净窗口后&#xff0c;有关闭等窗口功能。 4. 如果账号密码正确&#xff0c;则实现登录界面关闭&#xff0c;另一个应用界面…

HarmonyOS(37) APP crash崩溃日志收集插件@hw-agconnect使用指南

hw-agconnect使用指南 添加配置文件配置SDK依赖初始化SDK参考资料 添加配置文件 获取agconnect-services.json文件。将“agconnect-services.json”文件拷贝到DevEco Studio项目的“AppScope/resources/rawfile”目录下。 配置SDK依赖 在“oh-package.json5”文件的“depende…

【数据初步变现】论自助BI在数字化转型中如何赋能业务

引言&#xff1a;数字化转型要求企业更加依赖数据来指导业务决策。自助BI作为数据分析的重要工具&#xff0c;能够迅速、准确地从海量数据中提取有价值的信息&#xff0c;为企业的战略规划和业务执行提供有力支持。在数字化时代&#xff0c;企业需要快速响应市场变化并优化业务…

标准立项 | 膜曝气生物膜反应器(MABR)平板曝气膜

立项单位&#xff1a;天津市华宇膜技术有限公司、中国市政工程中南设计研究总院有限公司、中建生态环境集团有限公司、富朗世水务技术(江苏)有限公司、常州宣清环境科技有限公司 膜组件开发 膜腔内部支撑结构-一在膜腔内部设置支撑结构以防止膜腔在水压下压实&#xff0c;同时…

五、路由协议

目录 一、为何划分子网&#xff1f; 二、静态路由 三、OSPF 3.1、OSPF原理 3.1.1、ospf四步过程 3.2、OSPF区域划分 3.2.1、为什么划区域&#xff1f; 3.2.2、划分规则 3.3、OSPF参数 3.4、五种报文 3.4.1、hello报文 3.4.2、DD报文 3.4.2、LSR、LSU、LSAck报文 3…

“深入探讨Redis主从复制:原理、配置与优化“

目录 # 概念 1. 配置主从同步步骤 1.1 创建文件夹 1.2 复制配置文件 1.3 配置文件关闭 1.4 查看端口号&#xff0c;发现端口号存在 1.5 连接三个端口号 1.6 查看主机运行情况 1.7 让服务器变成&#xff08;主机&#xff09;或&#xff08;从机&#xff09; 1.8 实现效…

【达梦数据库】typeorm+node.js+达梦数据库返回自增列值

1.配置环境&#xff0c;下载依赖包 typeorm init --name test22 --database mysql typeorm-dm&#xff0c;uuid,typeorm2,修改连接信息 修改src/ data-source.ts 文件 连接dm&#xff0c;可参考刚刚安装typeorm-dm 模块中的 README.md 3.修改自增信息 /* 修改前*/PrimaryGen…

【数据结构与算法 刷题系列】判断链表是否有环(图文详解)

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《数据结构与算法 经典例题》C语言 期待您的关注 ​ ​ 目录 一、问题描述 二、解题思路 1.解题思路: 2.快慢指针的移动分三个…

✅生产问题之Emoji表情如何操作存储,MySQL是否支持

针对 Emoji 表情 MySQL 存储是否支持的问题&#xff0c;结论是&#xff1a; MySQL 中可以存储 emoji 表情&#xff0c;但需要使用 UTF8MB4 字符编码。如果使用 UTF8MB3&#xff0c;存储这些扩展字符会导致解析错误。 课外补充 MySQL 对 Unicode 的支持 Unicode 字符集已成为…

6.17作业

升级优化自己应用程序的登录界面。 要求&#xff1a; 1. qss实现 2. 需要有图层的叠加 &#xff08;QFrame&#xff09; 3. 设置纯净窗口后&#xff0c;有关闭等窗口功能。 4. 如果账号密码正确&#xff0c;则实现登录界面关闭&#xff0c;另一个应用界面显示。 //发送端头文件…

AI训练Checkpoint对存储的影响

检查点&#xff08;Checkpoints&#xff09;是机器学习和深度学习训练过程中的一个重要机制&#xff0c;旨在定期保存训练状态&#xff0c;以便在训练过程中遇到失败或中断时能够从中断处恢复训练&#xff0c;而无需从头开始。 随着模型参数量的剧增&#xff0c;Checkpoint文件…

经历的分享

我是三本计算机科学技术跨考上岸的学生&#xff0c;本科阶段技术能力并没有掌握多少&#xff0c;在选择导师时屡屡碰壁&#xff0c;我当时向许多计算机方向的导师&#xff0c;比如大数据方向,计算机视觉 迁移学习和图像处理方向的导师全都拒绝了我&#xff0c;最终学校给我分配…