带有图形的透明 RichTextBox 不显示文本

问题描述 投票:0回答:2

我有以下代码正在运行,并注释掉了绘制到控件上的文本,因为我开始将其用作仅图形控件。接下来,我已将控件切换为

RichTextBox
而不是
Control
,这样我就可以拥有它附带的所有好处,例如可点击的超链接、可选择的文本等。

我面临的问题是,可以选择文本,甚至可以复制文本,但它是不可见的,并且也没有准确定位在我想要的位置(取消注释

Messages.OnPaint()
方法中的文本打印行,看看我希望如何要出现的文字)

问题的漂亮图片 enter image description here

我正在努力实现的目标的漂亮图片 enter image description here

带有未注释的文本打印代码的漂亮图片 enter image description here

代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Runtime.InteropServices;

using System.Diagnostics;

public class MessageControl : ScrollableControl {

    public List<Message> Messages { get; private set; }

    private Color _LeftBubbleColor=Color.FromArgb(217,217,217);
    private Color _RightBubbleColor=Color.FromArgb(192,206,215);
    private Color _LeftBubbleTextColor=Color.FromArgb(52,52,52);
    private Color _RightBubbleTextColor=Color.FromArgb( 52, 52, 52 );
    private bool _DrawArrow=true;
    private int _BubbleIndent=40;
    private int _BubbleSpacing=10;

    private int _TruncateHistory=0;

    public enum BubblePositionEnum { Left, Right }

    public Color LeftBubbleColor { get { return _LeftBubbleColor; } set {_LeftBubbleColor = value; } }
    public Color RightBubbleColor { get { return _RightBubbleColor; } set { _RightBubbleColor=value; } }
    public Color LeftBubbleTextColor { get { return _LeftBubbleTextColor; } set { _LeftBubbleTextColor=value; } }
    public Color RightBubbleTextColor { get { return _RightBubbleTextColor; } set { _RightBubbleTextColor=value; } }
    public int BubbleIndent { get { return _BubbleIndent; } set { _BubbleIndent = value; } }
    public int BubbleSpacing { get { return _BubbleSpacing; } set { _BubbleSpacing=value; } }
    public bool DrawArrow { get { return _DrawArrow; } set { _DrawArrow = value; } }
    public int TruncatHistory { get { return _TruncateHistory; } set { _TruncateHistory = value; } }

    public MessageControl() {
        Messages = new List<Message>();
        SetStyle( ControlStyles.AllPaintingInWmPaint|ControlStyles.OptimizedDoubleBuffer|ControlStyles.ResizeRedraw|ControlStyles.SupportsTransparentBackColor|ControlStyles.UserPaint, true );
        DoubleBuffered=true;
        BackColor=Color.Orange;
        Anchor=AnchorStyles.Top|AnchorStyles.Left|AnchorStyles.Right|AnchorStyles.Bottom;
        AutoScroll=true;
    }

    public void Remove( Message message ) {
        this.Invalidate();
        Messages.Remove( message );
        RedrawControls();
    }

    public void Remove( Message[] messages ) {
        foreach ( Message m in messages ) {
            Messages.Remove( m );
        }
        RedrawControls();
        this.Invalidate();
    }

    public void Add( string Message, BubblePositionEnum Position ) {
        if ( Messages.Count>0 ) {
            Message m = Messages[Messages.Count-1];
            if ( m.BubblePosition==Position ) {
                Message=m.Text+"\n"+Message;
                Remove(m);
            }
        }

        Message b = new Message(Position);
        if ( Messages.Count>0 ) {
            b.Top=Messages[Messages.Count-1].Top+Messages[Messages.Count-1].Height+_BubbleSpacing;
        } else {
            b.Top=_BubbleSpacing;
        }

        b.Text = Message;
        b.DrawBubbleArrow=_DrawArrow;

        if ( VerticalScroll.Visible ) {
            b.Width=Width-( _BubbleIndent+_BubbleSpacing+SystemInformation.VerticalScrollBarWidth );
        } else {
            b.Width=Width-( _BubbleIndent+_BubbleSpacing );
        }
        if ( Position==BubblePositionEnum.Right ) {
            b.Left = _BubbleIndent;
            b.BubbleColor = _RightBubbleColor;
            b.ForeColor = _RightBubbleTextColor;
        } else {
            b.Left = _BubbleSpacing;
            b.BubbleColor=_LeftBubbleColor;
            b.ForeColor=_LeftBubbleTextColor;
        }

        this.Messages.Add(b);
        this.Controls.Add(b);

        if ( Messages.Count>_TruncateHistory&&_TruncateHistory>0 ) {
            Remove( Messages[0] );
            this.Invalidate();
        }
        base.ScrollControlIntoView(this.Controls[Controls.Count-1]);
    }

    public void Truncate( int count ) {
        if ( count>=( Controls.Count-1 ) ) {
//          Controls.Clear();
            Messages.Clear();
        } else if ( count>1 ) {
            int x=0;
            while ( x<count&&x<=Controls.Count ) {
                Messages.RemoveAt( 0 );
                x++;
            }
        } else {
            Messages.RemoveAt(0);
        }
        this.Invalidate();
        RedrawControls();

    }

    protected override void OnResize( System.EventArgs e ) {
        RedrawControls();
        base.OnResize( e );
    }

    private void RedrawControls() {
        int count=0;
        Message last=null;
        int new_width=this.Width;
        this.Controls.Clear();
        VerticalScroll.Visible = false;
        this.SuspendLayout();
        foreach ( Message m in this.Messages ) {
            if ( count>0 ) {
                m.Top=last.Top+last.Height+_BubbleSpacing;
                if ( VerticalScroll.Visible ) {
                    m.Width=new_width-( _BubbleIndent+_BubbleSpacing+SystemInformation.VerticalScrollBarWidth );
                } else {
                    m.Width=new_width-( _BubbleIndent+_BubbleSpacing );
                }
            } else {
                m.Top=_BubbleSpacing;
                if ( VerticalScroll.Visible ) {
                    m.Width=new_width-( _BubbleIndent+_BubbleSpacing+SystemInformation.VerticalScrollBarWidth );
                } else {
                    m.Width=new_width-( _BubbleIndent+_BubbleSpacing );
                }
            }
            last=m;
            count++;
        }
        this.Controls.AddRange(Messages.ToArray<Message>());
        if ( this.Controls.Count>0 ) {
            base.ScrollControlIntoView( this.Controls[Controls.Count-1] );
        }
        this.ResumeLayout();
    }

    public class Message : RichTextBox {
        private GraphicsPath Shape;
        private Color _TextColor=Color.FromArgb( 52, 52, 52 );
        private Color _BubbleColor=Color.FromArgb( 217, 217, 217 );
        private bool _DrawBubbleArrow=true;
        private BubblePositionEnum _BubblePosition = BubblePositionEnum.Left;

        public override Color ForeColor { get { return this._TextColor; } set { this._TextColor=value; this.Invalidate(); } }
        public BubblePositionEnum BubblePosition { get { return this._BubblePosition; } set { this._BubblePosition=value; this.Invalidate(); } }
        public Color BubbleColor { get { return this._BubbleColor; } set { this._BubbleColor=value; this.Invalidate(); } }
        public bool DrawBubbleArrow { get { return _DrawBubbleArrow; } set { _DrawBubbleArrow=value; Invalidate(); } }
        public Message(BubblePositionEnum Position) {
            _BubblePosition=Position;
            SetStyle( ControlStyles.AllPaintingInWmPaint|ControlStyles.OptimizedDoubleBuffer|ControlStyles.ResizeRedraw|ControlStyles.SupportsTransparentBackColor|ControlStyles.UserPaint, true );
            DoubleBuffered=true;
            Size=new Size( 152, 38 );
            BackColor=Color.Transparent;
            ForeColor=Color.FromArgb( 52, 52, 52 );
            Font=new Font( "Segoe UI", 10 );
            Anchor=AnchorStyles.Top|AnchorStyles.Left|AnchorStyles.Right;
            BorderStyle=System.Windows.Forms.BorderStyle.None;
            ScrollBars = RichTextBoxScrollBars.None;
        }

        [DllImport( "kernel32.dll", CharSet=CharSet.Auto )]
        static extern IntPtr LoadLibrary( string lpFileName );

        protected override CreateParams CreateParams {
            get {
                CreateParams prams=base.CreateParams;
                if ( LoadLibrary( "msftedit.dll" )!=IntPtr.Zero ) {
                    prams.ExStyle|=0x020; // transparent  
                    prams.ClassName="RICHEDIT50W";
                }
                return prams;
            }
        }

        protected override void OnResize( System.EventArgs e ) {
            SuspendLayout();
            Shape=new GraphicsPath();

            var _Shape=Shape;
            if ( BubblePosition==BubblePositionEnum.Left ) {
                _Shape.AddArc( 9, 0, 10, 10, 180, 90 );
                _Shape.AddArc( Width-11, 0, 10, 10, -90, 90 );
                _Shape.AddArc( Width-11, Height-11, 10, 10, 0, 90 );
                _Shape.AddArc( 9, Height-11, 10, 10, 90, 90 );
            } else {
                _Shape.AddArc( 0, 0, 10, 10, 180, 90 );
                _Shape.AddArc( Width-18, 0, 10, 10, -90, 90 );
                _Shape.AddArc( Width-18, Height-11, 10, 10, 0, 90 );
                _Shape.AddArc( 0, Height-11, 10, 10, 90, 90 );
            }
            _Shape.CloseAllFigures();

            Bitmap B=new Bitmap( this.Width, this.Height );
            Graphics G=Graphics.FromImage( B );

            SizeF s=G.MeasureString( Text, Font, Width-25 );
            this.Height=(int)( Math.Floor( s.Height )+10 );

            ResumeLayout();
            //Invalidate();
            base.OnResize( e );
        }

        protected override void OnClick( EventArgs e ) {
            //MessageBox.Show( base.Height.ToString() );
            base.OnClick( e );
        }

        protected override void OnPaint( PaintEventArgs e ) {
            base.OnPaint( e );
            Bitmap B=new Bitmap( this.Width, this.Height );
            Graphics G=Graphics.FromImage( B );

            B=new Bitmap( this.Width, this.Height );
            G=Graphics.FromImage( B );
            var _G=G;

            _G.SmoothingMode=SmoothingMode.HighQuality;
            _G.PixelOffsetMode=PixelOffsetMode.HighQuality;
            _G.Clear( BackColor );

            // Fill the body of the bubble with the specified color
            _G.FillPath( new SolidBrush( _BubbleColor ), Shape );
            // Draw the string specified in 'Text' property
//          if ( _BubblePosition==BubblePositionEnum.Left ) {
//              _G.DrawString( Text, Font, new SolidBrush( ForeColor ), new Rectangle( 13, 4, Width-19, Height-5 ) );
//          } else {
//              _G.DrawString( Text, Font, new SolidBrush( ForeColor ), new Rectangle( 5, 4, Width-19, Height-5 ) );
//          }

            // Draw a polygon on the right side of the bubble
            if ( _DrawBubbleArrow==true ) {
                if(_BubblePosition == BubblePositionEnum.Left) {
                    Point[] p = {
                        new Point(9, 9),
                        new Point(0, 15),
                        new Point(9, 20)
                   };
                    _G.FillPolygon( new SolidBrush( _BubbleColor ), p );
                    _G.DrawPolygon( new Pen( new SolidBrush( _BubbleColor ) ), p );
                } else {
                    Point[] p = {
                        new Point(Width - 8, 9),
                        new Point(Width, 15),
                        new Point(Width - 8, 20)
                    };
                    _G.FillPolygon( new SolidBrush( _BubbleColor ), p );
                    _G.DrawPolygon( new Pen( new SolidBrush( _BubbleColor ) ), p );
                }
            }
            G.Dispose();
            e.Graphics.InterpolationMode=InterpolationMode.HighQualityBicubic;
            e.Graphics.DrawImageUnscaled( B, 0, 0 );
            B.Dispose();
        }
    }
}

以防万一不清楚,我不想在上面绘制文字,因为你可以看到我对此没有任何问题。我希望在图形上呈现自然文本,同时保留使用 RichTextBox 控件的所有功能,例如

  • 可点击的链接
  • 内联字体样式更改
  • 嵌入表情(图像)的可能性
  • 完全可选择的文本
  • 右键选项
  • 其他未列出的东西,但在聊天/消息控件中拥有超级酷。

(对于那些在我将其变为现实时忍受这一点的人,由于社区的支持,我将将该控件的最终版本发布回社区 - 高度依赖于进度 ^^ - 正如您所知,主要的工作已经完成,所以除了这个微小的细节之外,一切都应该是为了添加所有其他的好处。)

c# winforms graphics transparency richtextbox
2个回答
0
投票

与其在源自

OnPaint
的控件的
RichTextBox
中绘制内容,不如在仅包含文本框的用户控件上的文本框周围绘制内容,并让文本框自行绘制。


0
投票

[![消息新控件][1]][1] 这是更新后的代码,尝试了多种方法使其工作

可点击链接已解决 您可以获取和设置内联字体样式更改 嵌入表情(图像)的可能性仍有待确定 完全可选的文本已解决 右键选项已解决


using System;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using static MessageNewControl;


public class MessageNewControl : ScrollableControl
{

    public List<MessageNew> MessageNews { get; private set; }

    private Color _LeftBubbleColor = Color.FromArgb(217, 217, 217);
    private Color _RightBubbleColor = Color.FromArgb(192, 206, 215);
    private Color _LeftBubbleTextColor = Color.FromArgb(52, 52, 52);
    private Color _RightBubbleTextColor = Color.FromArgb(52, 52, 52);
    private bool _DrawArrow = true;
    private int _BubbleIndent = 40;
    private int _BubbleSpacing = 10;

    private int _TruncateHistory = 0;

    public enum BubblePositionEnum { Left, Right }

    public Color LeftBubbleColor { get { return _LeftBubbleColor; } set { _LeftBubbleColor = value; } }
    public Color RightBubbleColor { get { return _RightBubbleColor; } set { _RightBubbleColor = value; } }
    public Color LeftBubbleTextColor { get { return _LeftBubbleTextColor; } set { _LeftBubbleTextColor = value; } }
    public Color RightBubbleTextColor { get { return _RightBubbleTextColor; } set { _RightBubbleTextColor = value; } }
    public int BubbleIndent { get { return _BubbleIndent; } set { _BubbleIndent = value; } }
    public int BubbleSpacing { get { return _BubbleSpacing; } set { _BubbleSpacing = value; } }
    public bool DrawArrow { get { return _DrawArrow; } set { _DrawArrow = value; } }
    public int TruncatHistory { get { return _TruncateHistory; } set { _TruncateHistory = value; } }

    public MessageNewControl()
    {
        MessageNews = new List<MessageNew>();
        SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor | ControlStyles.UserPaint, true);
        DoubleBuffered = true;
        BackColor = Color.FromArgb(128,Color.Orange);
        Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom;
        AutoScroll = true;

    }

    public void Remove(MessageNew message)
    {
        this.Invalidate();
        MessageNews.Remove(message);
        RedrawControls();
    }

    public void Remove(MessageNew[] messages)
    {
        foreach (MessageNew m in messages)
        {
            MessageNews.Remove(m);
        }
        RedrawControls();
        this.Invalidate();
    }

    public void Add(string MessageNew, BubblePositionEnum Position)
    {
        if (MessageNews.Count > 0)
        {
            MessageNew m = MessageNews[MessageNews.Count - 1];
            if (m.BubblePosition == Position)
            {
                MessageNew = m.Text + "\n" + MessageNew;
                Remove(m);
            }
        }

        MessageNew b = new MessageNew(Position);


        if (MessageNews.Count > 0)
        {
            b.Top = MessageNews[MessageNews.Count - 1].Top + MessageNews[MessageNews.Count - 1].Height + _BubbleSpacing;
        }
        else
        {
            b.Top = _BubbleSpacing;

        }

        b.Text = MessageNew;
        b.DrawBubbleArrow = _DrawArrow;

        if (VerticalScroll.Visible)
        {
            b.Width = Width - (_BubbleIndent + _BubbleSpacing + SystemInformation.VerticalScrollBarWidth);
        }
        else
        {
            b.Width = Width - (_BubbleIndent + _BubbleSpacing);
        }



        if (Position == BubblePositionEnum.Right)
        {
            b.Left = _BubbleIndent;
            b.BubbleColor = _RightBubbleColor;
            b.ForeColor = _RightBubbleTextColor;
        }
        else
        {
            b.Left = _BubbleSpacing;
            b.BubbleColor = _LeftBubbleColor;
            b.ForeColor = _LeftBubbleTextColor;
        }





        this.MessageNews.Add(b);
        this.Controls.Add(b);

        if (MessageNews.Count > _TruncateHistory && _TruncateHistory > 0)
        {
            Remove(MessageNews[0]);
            this.Invalidate();
        }
        base.ScrollControlIntoView(this.Controls[Controls.Count - 1]);
    }





    public void Truncate(int count)
    {
        if (count >= (Controls.Count - 1))
        {
            //          Controls.Clear();
            MessageNews.Clear();
        }
        else if (count > 1)
        {
            int x = 0;
            while (x < count && x <= Controls.Count)
            {
                MessageNews.RemoveAt(0);
                x++;
            }
        }
        else
        {
            MessageNews.RemoveAt(0);
        }
        this.Invalidate();
        RedrawControls();

    }

    protected override void OnResize(System.EventArgs e)
    {
        RedrawControls();
        base.OnResize(e);
    }

    private void RedrawControls()
    {
        int count = 0;
        MessageNew last = null;
        int new_width = this.Width;
        this.Controls.Clear();
        VerticalScroll.Visible = false;
        this.SuspendLayout();
        foreach (MessageNew m in this.MessageNews)
        {
            if (count > 0)
            {
                m.Top = last.Top + last.Height + _BubbleSpacing;
                if (VerticalScroll.Visible)
                {
                    m.Width = new_width - (_BubbleIndent + _BubbleSpacing + SystemInformation.VerticalScrollBarWidth);
                }
                else
                {
                    m.Width = new_width - (_BubbleIndent + _BubbleSpacing);
                }
            }
            else
            {
                m.Top = _BubbleSpacing;
                if (VerticalScroll.Visible)
                {
                    m.Width = new_width - (_BubbleIndent + _BubbleSpacing + SystemInformation.VerticalScrollBarWidth);
                }
                else
                {
                    m.Width = new_width - (_BubbleIndent + _BubbleSpacing);
                }
            }
            last = m;
            count++;
        }
        this.Controls.AddRange(MessageNews.ToArray<MessageNew>());
        if (this.Controls.Count > 0)
        {
            base.ScrollControlIntoView(this.Controls[Controls.Count - 1]);
        }
        this.ResumeLayout();
    }

  
}



[ToolboxBitmap(typeof(RichTextBox))]

public class MessageNew : RichTextBox, IMessageFilter
{

    private GraphicsPath Shape;
    private Color _TextColor = Color.FromArgb(52, 152, 152);
    private Color _BubbleColor = Color.FromArgb(217, 217, 217);
    private bool _DrawBubbleArrow = true;
    private BubblePositionEnum _BubblePosition = BubblePositionEnum.Left;

    public bool PreFilterMessage(ref Message m)
    {
        if (m.Msg == 0x20a) // WM_MOUSEWHEEL
        {
            OnMouseWheel(new MouseEventArgs(MouseButtons.None, 0, 0, 0, (short)((m.WParam.ToInt32() >> 16) & 0xffff)));
            return true;
        }
        return false;
    }

    protected override void OnLinkClicked(LinkClickedEventArgs e)
    {
        System.Diagnostics.Process.Start(e.LinkText);
    }


    public override Color ForeColor { get { return this._TextColor; } set { this._TextColor = value; this.Invalidate(); } }
    public BubblePositionEnum BubblePosition { get { return this._BubblePosition; } set { this._BubblePosition = value; this.Invalidate(); } }
    public Color BubbleColor { get { return this._BubbleColor; } set { this._BubbleColor = value; this.Invalidate(); } }
    public bool DrawBubbleArrow { get { return _DrawBubbleArrow; } set { _DrawBubbleArrow = value; Invalidate(); } }
    public MessageNew(BubblePositionEnum Position)
    {
        _BubblePosition = Position;
        SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor | ControlStyles.UserPaint, true);
        DoubleBuffered = true;
        Size = new Size(152, 38);
        BackColor = Color.Transparent;
        ForeColor = Color.FromArgb(52, 52, 52);
        Font = new Font("Segoe UI", 10);
        Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
        BorderStyle = System.Windows.Forms.BorderStyle.None;
        ScrollBars = RichTextBoxScrollBars.None;

        this.SelectionChanged += MessageNew_SelectionChanged; // Hook up event handler

    }
    private void MessageNew_SelectionChanged(object sender, EventArgs e)
    {
        HighlightSelectedText();
    }
    private void HighlightSelectedText()
    {
        // Get the current selection start and length
        int start = this.SelectionStart;
        int length = this.SelectionLength;

        // Highlight the selected text
        this.SelectionBackColor = Color.Yellow;

        // Move the selection back to its original position
        this.SelectionStart = start;
        this.SelectionLength = length;
    }


    protected override void OnResize(System.EventArgs e)
    {
        SuspendLayout();
        Shape = new GraphicsPath();

        //var _Shape = Shape;
        //if (BubblePosition == BubblePositionEnum.Left)
        //{
        //    _Shape.AddArc(9, 0, 10, 10, 180, 90);
        //    _Shape.AddArc(Width - 11, 0, 10, 10, -90, 90);
        //    _Shape.AddArc(Width - 11, Height - 11, 10, 10, 0, 90);
        //    _Shape.AddArc(9, Height - 11, 10, 10, 90, 90);
        //}
        var _Shape = Shape;
        if (BubblePosition == BubblePositionEnum.Left)
        {
            _Shape.AddArc(0, 0, 10, 10, 180, 90);
            _Shape.AddArc(Width - 11, 0, 10, 10, -90, 90);
            _Shape.AddArc(Width - 11, Height - 11, 10, 10, 0, 90);
            _Shape.AddArc(0, Height - 11, 10, 10, 90, 90);
        }

        else
        {
            _Shape.AddArc(0, 0, 10, 10, 180, 90);
            _Shape.AddArc(Width - 18, 0, 10, 10, -90, 90);
            _Shape.AddArc(Width - 18, Height - 11, 10, 10, 0, 90);
            _Shape.AddArc(0, Height - 11, 10, 10, 90, 90);
        }
        _Shape.CloseAllFigures();

        Bitmap B = new Bitmap(this.Width, this.Height);
        Graphics G = Graphics.FromImage(B);

        SizeF s = G.MeasureString(Text, Font, Width - 25);
        this.Height = (int)(Math.Floor(s.Height) + 10);
        ResumeLayout();
        //Invalidate();
        base.OnResize(e);
    }








    protected override void OnClick(EventArgs e)
    {
        //MessageNewBox.Show( base.Height.ToString() );
        base.OnClick(e);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        Bitmap B = new Bitmap(this.Width, this.Height);
        Graphics G = Graphics.FromImage(B);

        B = new Bitmap(this.Width, this.Height);
        G = Graphics.FromImage(B);
        var _G = G;

        _G.SmoothingMode = SmoothingMode.HighQuality;
        _G.PixelOffsetMode = PixelOffsetMode.HighQuality;
        _G.Clear(BackColor);

        // Fill the body of the bubble with the specified color
        _G.FillPath(new SolidBrush(_BubbleColor), Shape);

        ////Draw the string specified in 'Text' property
        //          if (_BubblePosition == BubblePositionEnum.Left)
        //{
        //    _G.DrawString(Text, Font, new SolidBrush(ForeColor), new Rectangle(13, 4, Width - 19, Height - 5));
        //}
        //else
        //{
        //    _G.DrawString(Text, Font, new SolidBrush(ForeColor), new Rectangle(5, 4, Width - 19, Height - 5));
        //}

        // Draw a polygon on the right side of the bubble
        if (_DrawBubbleArrow == true)
        {
            //if (_BubblePosition == BubblePositionEnum.Left)
            //{
            //    Point[] p = {
            //                new Point(9, 9),
            //                new Point(0, 15),
            //                new Point(9, 20)
            //           };
            //    _G.FillPolygon(new SolidBrush(Color.Black), p);
            //    _G.DrawPolygon(new Pen(new SolidBrush(_BubbleColor)), p);


            //}
            //else
            //{
            //    Point[] p = {
            //                new Point(Width - 8, 9),
            //                new Point(Width, 15),
            //                new Point(Width - 8, 20)
            //            };
            //    _G.FillPolygon(new SolidBrush(_BubbleColor), p);
            //    _G.DrawPolygon(new Pen(new SolidBrush(_BubbleColor)), p);
            //}
        }
        G.Dispose();
        e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
        e.Graphics.DrawImageUnscaled(B, 0, 0);
        B.Dispose();


        // Draw highlight selection
        if (isHighlighting)
        {
            using (Brush brush = new SolidBrush(Color.FromArgb(128, Color.HotPink)))
            {
                e.Graphics.FillRectangle(brush, highlightRect);
            }
        }

        // Render text on a transparent background
        using (Brush brush = new SolidBrush(this.ForeColor))
        {

            e.Graphics.DrawString(this.Text, this.Font, brush, 0, 0);


        }

        // Draw hyperlinks
        foreach (LinkArea linkArea in GetLinkAreas())
        {
            string linkText = this.Text.Substring(linkArea.Start, linkArea.Length);
            RectangleF rect = GetTextRectangle(linkArea);
            e.Graphics.DrawString(linkText, this.Font, Brushes.Blue, rect);
        }

        base.OnPaint(e);

    }

    // --------------------To Open Links browser 

    private IEnumerable<LinkArea> GetLinkAreas()
    {
        List<LinkArea> linkAreas = new List<LinkArea>();

        // Implement the logic to identify link areas in the text
        // For example:
        int startIndex = this.Text.IndexOf("http://");
        while (startIndex != -1)
        {
            int endIndex = this.Text.IndexOf(" ", startIndex);
            if (endIndex == -1)
                endIndex = this.Text.Length - 1;

            LinkArea linkArea = new LinkArea(startIndex, endIndex - startIndex);
            linkAreas.Add(linkArea);

            startIndex = this.Text.IndexOf("http://", endIndex);
        }

        return linkAreas;
    }

    private RectangleF GetTextRectangle(LinkArea linkArea)
    {
        // Get the position of the start and end characters of the link area
        PointF startPoint = GetPositionFromCharIndex(linkArea.Start);
        PointF endPoint = GetPositionFromCharIndex(linkArea.Start + linkArea.Length);

        // Calculate the width and height of the rectangle
        float width = endPoint.X - startPoint.X;
        float height = endPoint.Y - startPoint.Y;

        // Create and return the rectangle
        return new RectangleF(startPoint.X, startPoint.Y, width, height);
    }



    private const int WS_EX_TRANSPARENT = 0x20;

    [DllImport("user32.dll")]
    private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

    [DllImport("user32.dll")]
    private static extern int GetWindowLong(IntPtr hWnd, int nIndex);

    public MessageNew()
    {
        SetStyle(
                 ControlStyles.SupportsTransparentBackColor |
                 ControlStyles.AllPaintingInWmPaint |
                 ControlStyles.OptimizedDoubleBuffer, true);
        //SetStyle(ControlStyles.UserPaint, true);
        BackColor = Color.Transparent;
        Font = new Font(Font.FontFamily, 20);

    }

    //---------------------To Make It transparent 

    [DllImport("kernel32.dll")]
    private static extern IntPtr LoadLibrary(string lpFileName);
    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ExStyle |= 0x20; // WS_EX_TRANSPARENT
            if (LoadLibrary("msftedit.dll") != IntPtr.Zero)
            {
                cp.ClassName = "RICHEDIT50W"; //-----------behave like richtextbox  If you want it to be TextBox change "RICHEDIT50W" to "EDIT"
            }
            else if (LoadLibrary("riched20.dll") != IntPtr.Zero)
            {
                cp.ClassName = "RichEdit20W";
            }
            return cp;
        }
    }


    //----------------------------For Text Selection 

    private const int EM_GETSEL = 0xB0;
    private const int EM_GETRECT = 0xB2;
    private const int EM_SETRECT = 0xB3;
    private const int EM_HIDESELECTION = 0x201;
    private const int EM_EXGETSEL = 0x00B8;
    private const int EM_EXSETSEL = 0x00B1;

    private bool isHighlighting = false;
    private Rectangle highlightRect;

    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);

        switch (m.Msg)
        {
            case EM_GETRECT:
                RECT rect = (RECT)m.GetLParam(typeof(RECT));
                if (isHighlighting)
                {
                    rect.Top = highlightRect.Top;
                    rect.Bottom = highlightRect.Bottom;
                    Marshal.StructureToPtr(rect, m.LParam, true);
                }
                break;
        }
    }

    protected override void OnSelectionChanged(EventArgs e)
    {
        base.OnSelectionChanged(e);

        if (SelectionLength > 0)
        {
            isHighlighting = true;
            int start = SelectionStart;
            int end = start + SelectionLength;
            Point startPt = GetPositionFromCharIndex(start);
            Point endPt = GetPositionFromCharIndex(end);

            highlightRect = new Rectangle(startPt, new Size(endPt.X - startPt.X, Font.Height));
            Invalidate();
        }
        else
        {
            isHighlighting = false;
            Invalidate();
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }

    private ContextMenuStrip CreateCustomContextMenu()
    {
        ContextMenuStrip contextMenu = new ContextMenuStrip();
        // Undo
        ToolStripMenuItem undoMenuItem = new ToolStripMenuItem("Undo");
        undoMenuItem.ShortcutKeys = Keys.Control | Keys.Z; // Set Ctrl+Z as the shortcut key
        undoMenuItem.Click += (sender, e) => Undo();
        contextMenu.Items.Add(undoMenuItem);
        // Cut
        ToolStripMenuItem cutMenuItem = new ToolStripMenuItem("Cut");
        cutMenuItem.ShortcutKeys = Keys.Control | Keys.X; // Set Ctrl+X as the shortcut key
        cutMenuItem.Click += (sender, e) => Cut();
        contextMenu.Items.Add(cutMenuItem);
        // Copy
        ToolStripMenuItem copyMenuItem = new ToolStripMenuItem("Copy");
        copyMenuItem.ShortcutKeys = Keys.Control | Keys.C; // Set Ctrl+C as the shortcut key
        copyMenuItem.Click += (sender, e) => Copy();
        contextMenu.Items.Add(copyMenuItem);
        // Paste
        ToolStripMenuItem pasteMenuItem = new ToolStripMenuItem("Paste");
        pasteMenuItem.ShortcutKeys = Keys.Control | Keys.V; // Set Ctrl+V as the shortcut key
        pasteMenuItem.Click += (sender, e) => Paste();
        contextMenu.Items.Add(pasteMenuItem);
        // Select All
        ToolStripMenuItem selectAllMenuItem = new ToolStripMenuItem("Select All");
        selectAllMenuItem.ShortcutKeys = Keys.Control | Keys.A; // Set Ctrl+A as the shortcut key
        selectAllMenuItem.Click += (sender, e) => SelectAll();
        contextMenu.Items.Add(selectAllMenuItem);
        return contextMenu;
    }
    protected override void OnHandleCreated(EventArgs e)
    {
        base.OnHandleCreated(e);
        UpdateStyles();
        if (ContextMenuStrip == null)
        {
            ContextMenuStrip = CreateCustomContextMenu();
        }
    }

}


以及使用

using System;
using System.Windows.Forms;

namespace testApp
{
    public partial class Form4 : Form
    {

        public Form4()
        {
            InitializeComponent();

        }

        private void button1_Click(object sender, EventArgs e)
        {
            // You can add a message to the right side
            messageNewControl1.Add("This is a right side message  https://www.youtube.com/@Amro-Omran  "+"\n"+ "Please Like And subscribe For More useful Codes", MessageNewControl.BubblePositionEnum.Right);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            // You can add a message to the left side
            messageNewControl1.Add("This is a left side message ", MessageNewControl.BubblePositionEnum.Left);


        }

        private void button4_Click(object sender, EventArgs e)
        {
                        // You can add a message to the left side
            messageNewControl1.Truncate(0);


        }

        private void button3_Click(object sender, EventArgs e)
        {
            // Define the index of the message you want to remove
            int index = 0; // Replace 0 with the actual index you want to remove

            // Check if the index is within the valid range before attempting to remove the message
            if (index >= 0 && index < messageNewControl1.MessageNews.Count)
            {
                // Remove the message at the specified index
                messageNewControl1.Remove(messageNewControl1.MessageNews[index]);
            }
            else
            {
                // Handle the case where the index is out of range
                Console.WriteLine("Index is out of range.");
            }
        }

        private void Form4_Load(object sender, EventArgs e)
        {
            
        }
    }
}

namespace testApp
{
    partial class Form4
    {
        private System.ComponentModel.IContainer components = null;
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        private void InitializeComponent()
        {
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form4));
            this.button1 = new System.Windows.Forms.Button();
            this.button2 = new System.Windows.Forms.Button();
            this.button3 = new System.Windows.Forms.Button();
            this.button4 = new System.Windows.Forms.Button();
            this.messageNewControl1 = new MessageNewControl();
            this.SuspendLayout();
            // 
            // button1
            // 
            this.button1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(128)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))));
            this.button1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
            this.button1.ForeColor = System.Drawing.Color.Cornsilk;
            this.button1.Location = new System.Drawing.Point(75, 353);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(115, 30);
            this.button1.TabIndex = 1;
            this.button1.Text = "Add Right";
            this.button1.UseVisualStyleBackColor = false;
            this.button1.Click += new System.EventHandler(this.button1_Click);
            // 
            // button2
            // 
            this.button2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(128)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))));
            this.button2.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
            this.button2.ForeColor = System.Drawing.Color.Cornsilk;
            this.button2.Location = new System.Drawing.Point(228, 353);
            this.button2.Name = "button2";
            this.button2.Size = new System.Drawing.Size(115, 30);
            this.button2.TabIndex = 3;
            this.button2.Text = "Add Left";
            this.button2.UseVisualStyleBackColor = false;
            this.button2.Click += new System.EventHandler(this.button2_Click);
            // 
            // button3
            // 
            this.button3.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(128)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))));
            this.button3.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
            this.button3.ForeColor = System.Drawing.Color.Cornsilk;
            this.button3.Location = new System.Drawing.Point(549, 353);
            this.button3.Name = "button3";
            this.button3.Size = new System.Drawing.Size(145, 30);
            this.button3.TabIndex = 5;
            this.button3.Text = "Remove By Index";
            this.button3.UseVisualStyleBackColor = false;
            this.button3.Click += new System.EventHandler(this.button3_Click);
            // 
            // button4
            // 
            this.button4.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(128)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))));
            this.button4.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
            this.button4.ForeColor = System.Drawing.Color.Cornsilk;
            this.button4.Location = new System.Drawing.Point(381, 353);
            this.button4.Name = "button4";
            this.button4.Size = new System.Drawing.Size(130, 30);
            this.button4.TabIndex = 4;
            this.button4.Text = "Remove Index 0";
            this.button4.UseVisualStyleBackColor = false;
            this.button4.Click += new System.EventHandler(this.button4_Click);
            // 
            // messageNewControl1
            // 
            this.messageNewControl1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
            | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.messageNewControl1.AutoScroll = true;
            this.messageNewControl1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(200)))), ((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(255)))));
            this.messageNewControl1.BubbleIndent = 40;
            this.messageNewControl1.BubbleSpacing = 10;
            this.messageNewControl1.DrawArrow = true;
            this.messageNewControl1.Font = new System.Drawing.Font("Tahoma", 20F);
            this.messageNewControl1.LeftBubbleColor = System.Drawing.Color.FromArgb(((int)(((byte)(128)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))));
            this.messageNewControl1.LeftBubbleTextColor = System.Drawing.Color.White;
            this.messageNewControl1.Location = new System.Drawing.Point(32, 27);
            this.messageNewControl1.Name = "messageNewControl1";
            this.messageNewControl1.RightBubbleColor = System.Drawing.Color.FromArgb(((int)(((byte)(128)))), ((int)(((byte)(255)))), ((int)(((byte)(128)))), ((int)(((byte)(0)))));
            this.messageNewControl1.RightBubbleTextColor = System.Drawing.Color.FromArgb(((int)(((byte)(128)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(255)))));
            this.messageNewControl1.Size = new System.Drawing.Size(692, 277);
            this.messageNewControl1.TabIndex = 8;
            this.messageNewControl1.Text = "messageNewControl1";
            this.messageNewControl1.TruncatHistory = 0;
            // 
            // Form4
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 16F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.BackColor = System.Drawing.SystemColors.ControlLightLight;
            this.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("$this.BackgroundImage")));
            this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
            this.ClientSize = new System.Drawing.Size(770, 456);
            this.Controls.Add(this.messageNewControl1);
            this.Controls.Add(this.button3);
            this.Controls.Add(this.button4);
            this.Controls.Add(this.button2);
            this.Controls.Add(this.button1);
            this.Name = "Form4";
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
            this.Text = "Form4";
            this.Load += new System.EventHandler(this.Form4_Load);
            this.ResumeLayout(false);

        }

        private System.Windows.Forms.Button button1;
        private System.Windows.Forms.Button button2;
        private System.Windows.Forms.Button button3;
        private System.Windows.Forms.Button button4;
        private MessageNewControl messageNewControl1;
    }
}


  [1]: https://i.stack.imgur.com/biyP1.jpg
© www.soinside.com 2019 - 2024. All rights reserved.