Winform仿制QQ微信聊天窗口气泡

因为公司业务原因,不能上传原始项目,这是简化版本。

临时设计的窗体和气泡样式,有需要可以重新设计。效果如下:

主要原理:一个TextBlock + 一个三角形 

 

项目结构:

-- Form1 窗体类

-- Item 控件类(气泡)

Form1前端代码:

#region Windows 窗体设计器生成的代码

        /// <summary>
        /// 设计器支持所需的方法 - 不要
        /// 使用代码编辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            this.panel1 = new System.Windows.Forms.Panel();
            this.textBox1 = new System.Windows.Forms.TextBox();
            this.button1 = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // panel1
            // 
            this.panel1.AutoScroll = true;
            this.panel1.Location = new System.Drawing.Point(0, 0);
            this.panel1.Name = "panel1";
            this.panel1.Size = new System.Drawing.Size(377, 404);
            this.panel1.TabIndex = 0;

            // 
            // textBox1
            // 
            this.textBox1.Location = new System.Drawing.Point(0, 406);
            this.textBox1.Multiline = true;
            this.textBox1.Name = "textBox1";
            this.textBox1.Size = new System.Drawing.Size(377, 65);
            this.textBox1.TabIndex = 1;

            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(302, 477);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(75, 23);
            this.button1.TabIndex = 2;
            this.button1.Text = "Send";
            this.button1.UseVisualStyleBackColor = true;
            this.button1.Click += new System.EventHandler(this.button1_Click);

            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(380, 504);
            this.Controls.Add(this.button1);
            this.Controls.Add(this.textBox1);
            this.Controls.Add(this.panel1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);
            this.PerformLayout();


        }

        #endregion

        private System.Windows.Forms.Panel panel1;
        private System.Windows.Forms.TextBox textBox1;
        private System.Windows.Forms.Button button1;
View Code

 

Form类后台代码:

/// <summary>
        /// 当前消息气泡起始位置
        /// </summary>
        private int top = 0;

        /// <summary>
        /// 当前消息气泡高度
        /// </summary>
        private int height = 0;

 

private void button1_Click(object sender, EventArgs e)
        {
            AddSendMessage(textBox1.Text);
            AddReceiveMessage(textBox1.Text);
        }

/// <summary>
        /// 显示接收消息
        /// </summary>
        /// <param name="model"></param>
        private void AddReceiveMessage(string content)
        {
            Item item = new Item();
            item.messageType = WindowsFormsApplication2.Item.MessageType.receive;
            item.SetWeChatContent(content);

//计算高度
            item.Top = top + height;
            top = item.Top;
            height = item.HEIGHT;

            //滚动条移动最上方,重新计算气泡在panel的位置
            panel1.AutoScrollPosition = new Point(0, 0);
            panel1.Controls.Add(item);
        }

// <summary>
        /// 更新界面,显示发送消息
        /// </summary>
        private void AddSendMessage(string content)
        {
            Item item = new Item();
            item.messageType = WindowsFormsApplication2.Item.MessageType.send;
            item.SetWeChatContent(content);
            item.Top = top + height;
            item.Left = 370 - item.WIDTH;

top = item.Top;
            height = item.HEIGHT;
            panel1.AutoScrollPosition = new Point(0, 0);
            panel1.Controls.Add(item);
        }
View Code

 

Item类前端代码:

#region 组件设计器生成的代码

        /// <summary> 
        /// 设计器支持所需的方法 - 不要
        /// 使用代码编辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {

this.panel1 = new System.Windows.Forms.Panel();
            this.lblContent = new System.Windows.Forms.Label();
            this.panel1.SuspendLayout();
            this.SuspendLayout();
            // 
            // panel1
            //

this.panel1.AutoSize = true;
            this.panel1.BackColor = System.Drawing.Color.LightGray;
            this.panel1.Controls.Add(this.lblContent);
            this.panel1.Location = new System.Drawing.Point(20, 10);
            this.panel1.MaximumSize = new System.Drawing.Size(370, 400);
            this.panel1.Name = "panel1";
            this.panel1.Padding = new System.Windows.Forms.Padding(10, 10, 5, 10);
            this.panel1.Size = new System.Drawing.Size(26, 36);
 this.panel1.TabIndex = 0;
            // 
            // lblContent
            // 
            this.lblContent.AutoSize = true;
            this.lblContent.Font = new System.Drawing.Font("宋体", 16F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Pixel);
            this.lblContent.ForeColor = System.Drawing.Color.White;
            this.lblContent.ImeMode = System.Windows.Forms.ImeMode.NoControl;

this.lblContent.Location = new System.Drawing.Point(5, 10);
            this.lblContent.Margin = new System.Windows.Forms.Padding(0);
            this.lblContent.MaximumSize = new System.Drawing.Size(280, 1000);
            this.lblContent.Name = "lblContent";
            this.lblContent.Size = new System.Drawing.Size(16, 16);
            this.lblContent.TabIndex = 5;
            this.lblContent.Text = " ";
            this.lblContent.Visible = false;

// 
            // Item
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.AutoSize = true;
            this.Controls.Add(this.panel1);
            this.Name = "Item";

this.Padding = new System.Windows.Forms.Padding(20, 10, 10, 5);
            this.Size = new System.Drawing.Size(59, 54);
            this.panel1.ResumeLayout(false);
            this.panel1.PerformLayout();
            this.ResumeLayout(false);
            this.PerformLayout();

}

        #endregion

        private System.Windows.Forms.Panel panel1;
        private System.Windows.Forms.Label lblContent;
View Code

 

 Item 类后台代码:

/// <summary>
        /// 本窗体总高度
        /// </summary>
        public int HEIGHT = 40;
        /// <summary>
        /// 本窗体总宽度
        /// </summary>
        public int WIDTH = 45;
        /// <summary>
        /// 消息类型
        /// </summary>
        public MessageType messageType;      

   

public Item()
        {
            ///设置控件样式
            SetStyle(
                    ControlStyles.AllPaintingInWmPaint | //不闪烁
                    ControlStyles.OptimizedDoubleBuffer //支持双缓存
                    , true);
            InitializeComponent();
            this.Paint += Item_Paint;
        }

 #region 界面重绘

        /// <summary>
        /// 绘制气泡左上角小箭头
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Item_Paint(object sender, PaintEventArgs e)
        {
            //自己发送的消息箭头在右上角
            if (messageType == MessageType.send)
            {

Color color = System.Drawing.Color.LightGray;
                panel1.BackColor = color;
                Brush brushes = new SolidBrush(color);
                Point[] point = new Point[3];
                point[0] = new Point(WIDTH - 5, 10);
                point[1] = new Point(WIDTH - 15, 10);
                point[2] = new Point(WIDTH - 15, 20);
                e.Graphics.FillPolygon(brushes, point);
            }
            else
            {

Color color = System.Drawing.Color.LightGray;
                Brush brushes = new SolidBrush(color);
                Point[] point = new Point[3];
                point[0] = new Point(10, 10);
                point[1] = new Point(20, 10);
                point[2] = new Point(20, 20);
                e.Graphics.FillPolygon(brushes, point);
            }
        }
        #endregion

#region 功能操作

        /// <summary>
        /// 设置气泡内容
        /// </summary>
        /// <param name="type">消息类型</param>
        /// <param name="content">消息内容</param>
        public void SetWeChatContent(string content)
        {

lblContent.Text = content;
            lblContent.Visible = true;
            HEIGHT += lblContent.Height;
            WIDTH += lblContent.Width;
        }

        #endregion

        /// <summary>
        /// 内部类
        /// </summary>

class MessageItem
        {
            public string RESPATH { get; set; }
            public string RESTYPE { get; set; }
        }
        /// <summary>
        /// 消息类型
        /// </summary>
        public enum MessageType
        {
            send,
            receive
        }
View Code

 

项目中的一些坑:

1. panel控件出现滚动条后,添加控件时需要重新计算相对位置,不然每个气泡间的间距会变大。比较简单的解决方法:每次添加控件前将滚动条移到最上方,添加完控件后再将滚动条移到最下方。

2. 设置双缓冲和不闪烁

3. 计算气泡位置和绘制小箭头,这个不难但是需要时间,不知道为什么按设计稿设置位置一直出错,对winform理解不够,wpf可能会更自由一点

 Github:

https://github.com/haibincoder/WinformBubble

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值