あたも技術ブログ

セットジャパンコーポレーションの社員が運営しています。

【C#】Windowsフォーム アプリケーションのグラデーション背景と枠線を表示できるパネルユーザコントロール

 久しぶりのWindowsフォーム アプリケーションのユーザコントロールネタです。
 WPFだとコントロールに枠線やグラデーションを行うのは容易ですが、Windowsフォーム アプリケーションだと面倒なことこの上ないです。
 Panelを継承し、OnPaintをoverrideして自力で背景と枠線を描画してやっと出来るっていう…。

 グラデーション背景と枠線を表示できるパネルユーザコントロールの実装コードです。

namespace GradationPanelSample
{
  partial class GradationPanel
  {
    /// <summary> 
    /// 必要なデザイナー変数です。
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary> 
    /// 使用中のリソースをすべてクリーンアップします。
    /// </summary>
    /// <param name="disposing">マネージ リソースを破棄する場合は true を指定し、その他の場合は false を指定します。</param>
    protected override void Dispose(bool disposing)
    {
      if (disposing && (components != null))
      {
        components.Dispose();
      }
      base.Dispose(disposing);
    }

    #region コンポーネント デザイナーで生成されたコード

    /// <summary> 
    /// デザイナー サポートに必要なメソッドです。このメソッドの内容を 
    /// コード エディターで変更しないでください。
    /// </summary>
    private void InitializeComponent()
    {
      components = new System.ComponentModel.Container();
    }

    #endregion
  }
}
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace GradationPanelSample
{
  /// <summary>
  /// グラデーションパネルユーザコントロール
  /// </summary>
  public partial class GradationPanel : Panel
  {
    #region プロパティ
    /// <summary>
    /// コントロールの境界線のスタイル
    /// </summary>
    /// <remarks>PanelのデフォルトプロパティであるBorderStyleを隠蔽している。</remarks>
    [CategoryAttribute("表示")]
    [DescriptionAttribute("コントロールの境界線スタイルを取得または設定します。")]
    [BrowsableAttribute(false)]
    public new BorderStyle BorderStyle { get; set; } = BorderStyle.None;

    /// <summary>
    /// コントロールの境界線の色
    /// </summary>
    [CategoryAttribute("表示")]
    [DescriptionAttribute("コントロールの境界線の色を取得または設定します。")]
    [BrowsableAttribute(true)]
    public Color BorderColor { get; set; } = Color.Black;

    /// <summary>
    /// コントロールの境界線の太さ
    /// </summary>
    [CategoryAttribute("表示")]
    [DescriptionAttribute("コントロールの境界線の太さを取得または設定します。0を設定した場合は枠線は描画されません。")]
    [BrowsableAttribute(true)]
    [DefaultValue(0)]
    public int BorderThickness { get; set; } = 0;

    /// <summary>
    /// コントロールのグラデーション開始色
    /// </summary>
    [CategoryAttribute("表示")]
    [DescriptionAttribute("コントロールのグラデーション開始色を取得または設定します。")]
    [BrowsableAttribute(true)]
    public Color StartColor { get; set; } = SystemColors.Control;

    /// <summary>
    /// コントロールのグラデーション終了色
    /// </summary>
    [CategoryAttribute("表示")]
    [DescriptionAttribute("コントロールのグラデーション終了色を取得または設定します。")]
    [BrowsableAttribute(true)]
    public Color EndColor { get; set; } = SystemColors.Control;

    /// <summary>
    /// コントロールのグラデーションモード
    /// </summary>
    [CategoryAttribute("表示")]
    [DescriptionAttribute("コントロールのグラデーションのモードを取得または設定します。")]
    [BrowsableAttribute(true)]
    public LinearGradientMode GradientMode { get; set; } = LinearGradientMode.Vertical;
    #endregion

    #region コンストラクタ
    /// <summary>
    /// クラスの新しいインスタンスを初期化します。
    /// </summary>
    public GradationPanel()
    {
      InitializeComponent();
    }
    #endregion

    #region protectedメソッド
    /// <summary>
    /// 描画処理
    /// </summary>
    /// <param name="pevent">Paintイベント引数</param>
    protected override void OnPaint(PaintEventArgs pevent)
    {
      using (var graphics = pevent.Graphics)
      {
        var borderThickness = GetHarfBorderThickness();
        var x = borderThickness;
        var y = borderThickness;
        var width = 0 < borderThickness ? Width - (borderThickness * 2) : Width;
        var height = 0 < borderThickness ? Height - (borderThickness * 2) : Height;

        // 幅と高さが0より小さい場合は、最小値の1を設定する
        if (width <= 0) { width = 1; }
        if (height <= 0) { height = 1; }

        // 算出した幅と高さがコントロールの領域の1/2より大きい場合は、値を設定し直す
        if ((Width / 2) < borderThickness)
        {
          borderThickness = (int)Math.Floor(Width / 2.0F);
        }
        if ((Height / 2) < borderThickness)
        {
          borderThickness = (int)Math.Floor(Height / 2.0F);
        }

        // 背景の描画領域を指定する
        var rectangle = new Rectangle(x, y, width, height);
        using (var linearGradientBrush = new LinearGradientBrush(new Rectangle(x, y, width, height), StartColor, EndColor, GradientMode))
        {
          // グラデーションブラシを生成し描画する
          graphics.FillRectangle(linearGradientBrush, rectangle);
        }

        if (0 < BorderThickness)
        {
          using (var pen = new Pen(BorderColor, BorderThickness))
          {
            graphics.DrawRectangle(pen, 0 + borderThickness, 0 + borderThickness, width, height);
          }
        }
      }
    }
    #endregion

    #region privateメソッド
    /// <summary>
    /// 枠線の太さの1/2の値を取得します。
    /// </summary>
    /// <returns>枠線の太さの1/2の値</returns>
    private int GetHarfBorderThickness()
    {
      return (int)System.Math.Floor((double)(BorderThickness) / 2 + 0.5);
    }
    #endregion
  }
}

 枠線の太さの最小値と最大値を補正するように記述しています。頭が悪いのでもっと綺麗に書けそうですが、わたしの脳みそではこれで限界です。
 Windowsフォーム アプリケーションのユーザコントロールネタにまた戻ってきましたが、そろそろネタが無くなりそう。