【C#/WinForms】タブコントロールに閉じるボタンを付ける方法

C#
この記事は約6分で読めます。

標準ではタブの閉じるボタンは用意されていないため、独自に閉じるボタンを描画する処理が必要になります。

オーナードローによる描画でもいいのですができれば外観を変えたくないため WndProc で WM_PAINT メッセージ発生時に描画します。 下記ソースはタブの閉じるボタン描画しクリックするとイベントを発生させるサンプルです。

適用イメージ

サンプルではタブの名前に「□(全角スペース)」を追加し閉じるボタンを描画するスペースを設定しています。

サンプルコード

TabControl を継承して閉じるボタンを描画します。

using System;
using System.Drawing;
using System.Windows.Forms;

namespace Test {

    public class TabControlEx : TabControl {

        // タブの閉じるボタンクリックイベント
        public event EventHandler TabCloseButtonClick;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public TabControlEx() {
        }

        /// <summary>
        /// タブの閉じるボタンクリックイベント
        /// </summary>
        /// <param name="e"></param>
        protected void OnCloseButtonClick(EventArgs e) {

            MessageBox.Show("タブの閉じるボタンが押されたよ!");

            this.TabCloseButtonClick?.Invoke(this, e);
        }

        /// <summary>
        /// OnMouseUp
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseUp(MouseEventArgs e) {
            base.OnMouseUp(e);
            Point pt = new Point(e.X, e.Y);
            Rectangle rect = this.GetTabCloseButtonRect(pt);
            if (rect.Contains(pt)) {
                this.OnCloseButtonClick(new EventArgs());
                this.Invalidate(rect);
            }
        }

        /// <summary>
        /// タブの閉じるボタン場所を取得
        /// </summary>
        /// <param name="pt"></param>
        /// <returns></returns>
        private Rectangle GetTabCloseButtonRect(Point pt) {
            Rectangle rect;
            for (int i = 0; i < base.TabCount; i++) {
                rect = this.GetTabCloseButtonRect(i);
                if (rect.Contains(pt)) {
                    return rect;
                }
            }
            return Rectangle.Empty;
        }

        /// <summary>
        /// タブの閉じるボタン場所を取得
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        private Rectangle GetTabCloseButtonRect(int index) {
            Rectangle rect = this.GetTabRect(index);
            rect.X = rect.Right - 20;
            rect.Y = rect.Top + 2;
            rect.Width = 16;
            rect.Height = 16;

            return rect;
        }

        /// <summary>
        /// タブに閉じるボタンを描画
        /// </summary>
        private void DrawTabCloseButton() {
            Graphics g = this.CreateGraphics();
            Rectangle rect = Rectangle.Empty;
            Point pt = this.PointToClient(Cursor.Position);
            for (int i = 0; i < this.TabPages.Count; i++) {
                rect = this.GetTabCloseButtonRect(i);
                // 閉じるボタン描画
                ControlPaint.DrawCaptionButton(g, rect, CaptionButton.Close, ButtonState.Flat);
            }
            g = null;
        }

        /// <summary>
        /// WndProc
        /// </summary>
        /// <param name="m"></param>
        protected override void WndProc(ref Message m) {
            base.WndProc(ref m);

            const int WM_PAINT = 0x000F;
            
            switch (m.Msg) {
                case WM_PAINT:
                    this.DrawTabCloseButton();
                    break;
                default:
                    break;
            }
        }
    }
}

おわりに

自作エディタも最初は標準コントロールのタブを利用していましたが、色々問題が発生して、最終的にはタブコントロールも自作しました。

コメント

タイトルとURLをコピーしました