LoginSignup
13
16

More than 5 years have passed since last update.

Windowsフォーム上のテキストボックスにプレースホルダテキストを表示させる

Last updated at Posted at 2017-02-03

プレースホルダ

sample.png

フォーム上の文字列入力項目に、入力例や入力時の注意をあらかじめ表示しておく手段のひとつとして「プレースホルダ」や「プロンプト」などと呼ばれる要素があります(ご存知の方も多いと思いますが HTML5 フォームの input 要素には placeholder 属性があります)
.NET Framework の Windows フォームで用意される標準テキストボックスには無い機能なので、拡張して搭載してみます。

サンプルコード

using System;

namespace WindowsFormsApplication1 // <- 組み込む名前空間で
{
    public class TextBoxEx : System.Windows.Forms.TextBox
    {
        private string _placeholder = string.Empty;

        // (プロパティ)
        public string Placeholder
        {
            get { return _placeholder; }
            set
            {
                _placeholder = value;
                Invalidate();
            }
        }

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

            if (m.Msg == 15) //  WM_PAINT == 15
            {
                if (this.Enabled && !this.ReadOnly && !this.Focused && (_placeholder != null) && (_placeholder.Length > 0) && (this.TextLength == 0))
                {
                    using (var g = this.CreateGraphics())
                    {
                        // 描画を一旦消してしまう
                        g.FillRectangle(new System.Drawing.SolidBrush(this.BackColor), this.ClientRectangle);

                        // プレースホルダのテキスト色を、前景色と背景色の中間として文字列を描画する
                        var placeholderTextColor = System.Drawing.Color.FromArgb((this.ForeColor.A >> 1 + this.BackColor.A >> 1), (this.ForeColor.R >> 1 + this.BackColor.R >> 1), ((this.ForeColor.G >> 1 + this.BackColor.G) >> 1), (this.ForeColor.B >> 1 + this.BackColor.B >> 1));
                        g.DrawString(_placeholder, this.Font, new System.Drawing.SolidBrush(placeholderTextColor), 1, 1);
                    }
                }
            }
        }
    }
}

sam.png

上記コード(クラス)を組み込んで一旦ビルドすると、Visual Studio で任意のフォームを作成・編集するときに、ツールボックスへ 「TextBoxEx」コントロールが追加されます。これを標準の TextBox などと同じくフォーム上に張り付けて、Placeholder プロパティにプレースホルダテキストをセットしてやります。フォームの InitializeComponent メソッド内を編集したりして、標準の System.Windows.Forms.TextBox を拡張対応させる方法でももちろんよいでしょう。

標準のテキストボックスコントロールを派生させて(サブクラス化して)、ウインドウプロシージャ (WndProc) の WM_PAINT 処理を拡張しています。標準の描画処理を行ったあと、プレースホルダを表示する条件(ここでは、Enabled=true, ReadOnly=false, ...)に該当していたら、一旦消してプレースホルダ文字列を描画させています。
わざわざ一旦消すことは無駄であろうになぜそうするか...標準の挙動とまったく同じくさせるコードを書くことが困難(しかも OS の仕様変更など将来にわたって)だからです(時間と気力があれば TextBoxBase クラスから派生させて独自コントロールを作ることも選択肢でしょうけれども、かけるコストと効果を比べると私はイヤ)
ちなみに System.Windows.Forms.TextBox コントロールでオーナードローをしたい(OnPaintOnPaintBackground をオーバーライドして処理をしたい)場合は、Control.SetStyle メソッドをコンストラクタなどで呼び出し、ControlStyles.UserPaint スタイルを有効にする必要があります。

プレースホルダテキストを使用する功罪

ご参考までに「プレースホルダテキストはユーザーの短期記憶に負荷をかける」ためプレースホルダを使うべきではない、との主張もあります。

13
16
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
16