zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    使用ConfigFilter
    读取特定文件,替换第一行内容
    sqlserver,oracle,mysql等的driver驱动,url怎么写
    Excel 数字处理
    ResultMap详解
    正则表达式
    Tomasulo algorithm
    scoreboarding
    data hazard in CPU pipeline
    差分绕线间距对阻抗的影响
  • 原文地址:https://www.cnblogs.com/bincoding/p/7877568.html
Copyright © 2011-2022 走看看