첨부 소스 코드는 나눔고딕코딩 폰트를 사용합니다.
728x90
반응형
728x170

TestProject.zip
다운로드

▶ MainForm.cs

using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace TestProject
{
    /// <summary>
    /// 그룹 컨트롤
    /// </summary>
    public class GroupControl : GroupBox
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 그룹 테두리 그리기 여부
        /// </summary>
        private bool drawGroupBorder = true;

        /// <summary>
        /// 그룹 테두리 펜
        /// </summary>
        private Pen groupBorderPen;

        /// <summary>
        /// 그룹 배경 브러시
        /// </summary>
        private SolidBrush groupBackgroundBrush;

        /// <summary>
        /// 그룹 배경 이미지
        /// </summary>
        private Image groupBackgroundImage;

        /// <summary>
        /// 그룹 테두리 타입
        /// </summary>
        private GroupBorderType groupBorderType = GroupBorderType.ROUND_RECTANGLE;

        /// <summary>
        /// 그룹 헤더 테두리 색상
        /// </summary>
        private Pen groupHeaderBorderColor;

        /// <summary>
        /// 그룹 헤더 배경 색상
        /// </summary>
        private SolidBrush groupHeaderBackgroundColor;

        /// <summary>
        /// 그룹 헤더 텍스트 브러시
        /// </summary>
        private SolidBrush groupHeaderTextBrush;

        /// <summary>
        /// 문자열 포맷
        /// </summary>
        private StringFormat stringFormat;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 그룹 테두리 그리기 여부 - DrawGroupBorder

        /// <summary>
        /// 그룹 테두리 그리기 여부
        /// </summary>
        [Category("GroupControl")]
        [Description("그룹 테두리 그리기 여부를 가져오거나 설정합니다.")]
        [Browsable(true)]
        public bool DrawGroupBorder
        {
            get
            {
                return this.drawGroupBorder;
            }
            set
            {
                this.drawGroupBorder = value;

                Refresh();
            }
        }

        #endregion
        #region 그룹 테두리 색상 - GroupBorderColor

        [Category("GroupControl")]
        [Description("그룹 테두리 색상을 가져오거나 설정합니다.")]
        [Browsable(true)]
        public Color GroupBorderColor
        {
            get
            {
                return this.groupBorderPen.Color;
            }
            set
            {
                this.groupBorderPen.Color = value;

                Refresh();
            }
        }

        #endregion
        #region 그룹 배경 색상 - GroupBackgroundColor

        [Category("GroupControl")]
        [Description("그룹 배경 색상을 가져오거나 설정합니다.")]
        [Browsable(true)]
        public Color GroupBackgroundColor
        {
            get
            {
                return this.groupBackgroundBrush.Color;
            }
            set
            {
                this.groupBackgroundBrush.Color = value;

                Refresh();
            }
        }

        #endregion
        #region 그룹 배경 이미지 - GroupBackgroundImage

        [Category("GroupControl")]
        [Description("그룹 배경 이미지를 가져오거나 설정합니다.")]
        [Browsable(true)]
        public Image GroupBackgroundImage
        {
            get
            {
                return this.groupBackgroundImage;
            }
            set
            {
                this.groupBackgroundImage = value;

                Refresh();
            }
        }

        #endregion
        #region 그룹 테두리 타입 - GroupBorderType

        /// <summary>
        /// 그룹 테두리 타입
        /// </summary>
        [Category("GroupControl")]
        [Description("그룹 테두리 타입을 가져오거나 설정합니다")]
        [Browsable(true)]
        public GroupBorderType GroupBorderType
        {
            get
            {
                return this.groupBorderType;
            }
            set
            {
                this.groupBorderType = value;

                Refresh();
            }
        }

        #endregion
        #region 그룹 헤더 테두리 색상 - GroupHeaderBorderColor

        [Category("GroupControl")]
        [Description("그룹 헤더 테두리 색상을 가져오거나 설정합니다.")]
        [Browsable(true)]
        public Color GroupHeaderBorderColor
        {
            get
            {
                return this.groupHeaderBorderColor.Color;
            }
            set
            {
                this.groupHeaderBorderColor.Color = value;

                Refresh();
            }
        }

        #endregion
        #region 그룹 헤더 배경 색상 - GroupHeaderBackgroundColor

        [Category("GroupControl")]
        [Description("그룹 헤더 배경 색상을 가져오거나 설정합니다.")]
        [Browsable(true)]
        public Color GroupHeaderBackgroundColor
        {
            get
            {
                return this.groupHeaderBackgroundColor.Color;
            }
            set
            {
                this.groupHeaderBackgroundColor.Color = value;

                Refresh();
            }
        }

        #endregion
        #region 그룹 헤더 텍스트 색상 - GroupHeaderTextColor

        /// <summary>
        /// 그룹 헤더 텍스트 색상
        /// </summary>
        [Category("GroupControl")]
        [Description("그룹 헤더 텍스트 색상을 가져오거나 설정합니다.")]
        [Browsable(true)]
        public Color GroupHeaderTextColor
        {
            get
            {
                return this.groupHeaderTextBrush.Color;
            }
            set
            {
                this.groupHeaderTextBrush.Color = value;

                Refresh();
            }
        }

        #endregion

        #region 배경 색상 - BackColor

        [Browsable(false)] 
        [EditorBrowsable(EditorBrowsableState.Never)] 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        [Obsolete("BackColor 속성은 구현되지 않습니다.", true)] 
        public new Color BackColor 
        { 
            get
            {
                return base.BackColor;
            }
            set 
            { 
                throw new Exception("BackColor 속성은 구현되지 않습니다."); 
            }
        }

        #endregion
        #region 배경 이미지 - BackgroundImage

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [System.Obsolete("BackgroundImage 속성이 구현되지 않습니다.", true)]
        public new Image BackgroundImage
        {
            get
            {
                return base.BackgroundImage;
            }
            set
            {
                throw new Exception("BackgroundImage 속성이 구현되지 않습니다.");
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - GroupControl()

        /// <summary>
        /// 생성자
        /// </summary>
        public GroupControl()
        {
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

            Size = new Size(200, 100);

            this.groupBorderPen             = new Pen(Color.Black);
            this.groupBackgroundBrush       = new SolidBrush(base.BackColor);
            this.groupHeaderBorderColor     = new Pen(Color.Black);
            this.groupHeaderBackgroundColor = new SolidBrush(Color.White);
            this.groupHeaderTextBrush       = new SolidBrush(Color.Black);

            base.BackColor = Color.Transparent;

            this.stringFormat = new StringFormat
            {
                Alignment     = StringAlignment.Center,
                LineAlignment = StringAlignment.Center,
                Trimming      = StringTrimming.EllipsisCharacter,
                FormatFlags   = StringFormatFlags.NoWrap
            };
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Protected

        #region 텍스트 변경시 처리하기 - OnTextChanged(e)

        /// <summary>
        /// 텍스트 변경시 처리하기
        /// </summary>
        /// <param name="e">이벤트 인자</param>
        protected override void OnTextChanged(EventArgs e)
        {
            base.OnTextChanged(e);

            Refresh();
        }

        #endregion
        #region 페인트시 처리하기 - OnPaint(e)

        /// <summary>
        /// 페인트시 처리하기
        /// </summary>
        /// <param name="e">이벤트 인자</param>
        protected override void OnPaint(PaintEventArgs e)
        {
            Graphics graphis = e.Graphics;

            graphis.FillRectangle(this.groupBackgroundBrush, 0, 0, this.Width, this.Height);

            graphis.SmoothingMode = SmoothingMode.AntiAlias;

            int textWidth  = Convert.ToInt32(graphis.MeasureString(Text, Font).Width );
            int textHeight = Convert.ToInt32(graphis.MeasureString(Text, Font).Height);

            Rectangle groupBorderRectangle = new Rectangle
            (
                0,
                Convert.ToInt32(textHeight / 2),
                this.Width - 1,
                this.Height - 1 - Convert.ToInt32(textHeight / 2)
            );

            using(GraphicsPath graphicsPen = new GraphicsPath())
            {
                if(GroupBorderType == GroupBorderType.ROUND_RECTANGLE)
                {
                    int radius = 14;

                    graphicsPen.AddArc(groupBorderRectangle.Right - radius, groupBorderRectangle.Y              , radius, radius, 270, 90);
                    graphicsPen.AddArc(groupBorderRectangle.Right - radius, groupBorderRectangle.Bottom - radius, radius, radius, 0  , 90);
                    graphicsPen.AddArc(groupBorderRectangle.X             , groupBorderRectangle.Bottom - radius, radius, radius, 90 , 90);
                    graphicsPen.AddArc(groupBorderRectangle.X             , groupBorderRectangle.Y              , radius, radius, 180, 90);

                    graphicsPen.CloseFigure();
                }
                else
                {
                    graphicsPen.AddRectangle(groupBorderRectangle);
                }

                graphis.FillPath(this.groupBackgroundBrush, graphicsPen);

                if(GroupBackgroundImage != null)
                {
                    DrawBackgroundImage(e.Graphics, graphicsPen, Convert.ToInt32(textHeight / 2));
                }

                if(DrawGroupBorder)
                {
                    graphis.DrawPath(this.groupBorderPen, graphicsPen);
                }
            }

            if(textWidth > 0 & textHeight > 0)
            {
                Rectangle textRectangle = new Rectangle(7, 0, this.Width - 15, textHeight + 2);

                using(GraphicsPath graphicsPen = new GraphicsPath())
                {
                    int radius = 6;

                    graphicsPen.AddArc(textRectangle.Right - radius, textRectangle.Y              , radius, radius, 270, 90);
                    graphicsPen.AddArc(textRectangle.Right - radius, textRectangle.Bottom - radius, radius, radius, 0  , 90);
                    graphicsPen.AddArc(textRectangle.X             , textRectangle.Bottom - radius, radius, radius, 90 , 90);
                    graphicsPen.AddArc(textRectangle.X             , textRectangle.Y              , radius, radius, 180, 90);

                    graphicsPen.CloseFigure();

                    graphis.FillPath(this.groupHeaderBackgroundColor, graphicsPen);

                    graphis.DrawPath(this.groupHeaderBorderColor, graphicsPen);
                }

                graphis.DrawString(Text, Font, this.groupHeaderTextBrush, textRectangle, stringFormat);
            }
        }

        #endregion

        #region 처분하기 - Dispose(disposing)

        /// <summary>
        /// 처분하기
        /// </summary>
        /// <param name="disposing">처분 여부</param>
        protected override void Dispose(bool disposing)
        {
            this.groupBorderPen.Dispose();
            this.groupBackgroundBrush.Dispose();
            this.groupHeaderBorderColor.Dispose();
            this.groupHeaderBackgroundColor.Dispose();

            base.Dispose(disposing);
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Protected

        #region 배경 이미지 그리기 - DrawBackgroundImage(graphics, graphicsPath, topOffset)

        /// <summary>
        /// 배경 이미지 그리기
        /// </summary>
        /// <param name="graphics">그래픽스</param>
        /// <param name="graphicsPath">그래픽스 패스</param>
        /// <param name="topOffset">위쪽 오프셋</param>
        private void DrawBackgroundImage(Graphics graphics, GraphicsPath graphicsPath, int topOffset)
        {
            using(Bitmap bitmap = new Bitmap(Width, Height - topOffset))
            {
                using(Graphics bitmapGraphics = Graphics.FromImage(bitmap))
                {
                    if(BackgroundImageLayout == ImageLayout.None)
                    {
                        bitmapGraphics.DrawImage(GroupBackgroundImage, 0, 0, GroupBackgroundImage.Width, GroupBackgroundImage.Height);
                    }
                    else if(BackgroundImageLayout == ImageLayout.Tile)
                    {
                        int tileCountX = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(bitmap.Width  / GroupBackgroundImage.Width )));
                        int tileCountY = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(bitmap.Height / GroupBackgroundImage.Height)));

                        for(int y = 0; y <= tileCountY; y++)
                        {
                            for(int x = 0; x <= tileCountX; x++)
                            {
                                bitmapGraphics.DrawImage
                                (
                                    GroupBackgroundImage,
                                    x * GroupBackgroundImage.Width,
                                    y * GroupBackgroundImage.Height,
                                    GroupBackgroundImage.Width,
                                    GroupBackgroundImage.Height
                                );
                            }
                        }
                    }
                    else if(BackgroundImageLayout == ImageLayout.Center)
                    {
                        int imageLeft = Convert.ToInt32((Width / 2) - (GroupBackgroundImage.Width / 2));
                        int imageTop  = Convert.ToInt32(((Height - topOffset) / 2) - (GroupBackgroundImage.Height / 2));

                        bitmapGraphics.DrawImage(GroupBackgroundImage, imageLeft, imageTop, GroupBackgroundImage.Width, GroupBackgroundImage.Height);
                    }
                    else if(BackgroundImageLayout == ImageLayout.Stretch)
                    {
                        bitmapGraphics.DrawImage(GroupBackgroundImage, 0, 0, Width, Height - topOffset);
                    }
                    else if(BackgroundImageLayout == ImageLayout.Zoom)
                    {
                        double backgroundRatio = Width / (Height - topOffset);
                        double imageRatio      = GroupBackgroundImage.Width / GroupBackgroundImage.Height;

                        Rectangle backgroundRectangle = new Rectangle(0, 0, Width, Height - topOffset);

                        if(imageRatio > backgroundRatio)
                        {
                            backgroundRectangle.Width  = Width;
                            backgroundRectangle.Height = Convert.ToInt32(Width / imageRatio);
                        }
                        else if(imageRatio < backgroundRatio)
                        {
                            backgroundRectangle.Height = Height - topOffset;
                            backgroundRectangle.Width  = Convert.ToInt32((Height - topOffset) * imageRatio);
                        }

                        backgroundRectangle.X = Convert.ToInt32((Width / 2) - (backgroundRectangle.Width / 2));
                        backgroundRectangle.Y = Convert.ToInt32(((Height - topOffset) / 2) - (backgroundRectangle.Height / 2));

                        bitmapGraphics.DrawImage(GroupBackgroundImage, backgroundRectangle);
                    }
                }
                using(TextureBrush textureBrush = new TextureBrush(bitmap))
                {
                    if(BackgroundImageLayout != ImageLayout.Tile)
                    {
                        textureBrush.WrapMode = WrapMode.Clamp;
                    }

                    textureBrush.TranslateTransform(0, topOffset);

                    graphics.FillPath(textureBrush, graphicsPath);
                }
            }
        }

        #endregion
    }
}
728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요