役所風にEnterキーで次のテキストボックスへ移動

先日、子供の出生届に行ってきたわけですが、まだまだ古いパソコンを使っていましたお役所さん。出生届もインターネット越しでもいいんじゃない?と思ったり、思わなかったりしたのですが、ひょいと、パソコンの画面を見ると懐かしのDOS画面でありました。

役所関係や事務関係では、まだまだ強いですよね、この手のインターフェース。

そんな訳で「タブキーで次のフォーカスに移ればいいじゃん」と思っても「エンターキー(Enter Key)で次のフォーカスに移りたい」訳で、そこには、Silverlight とか、WPF とか、WEB やら jQuery やらの話は出てきません。ひたすら、今の業務にそろえたい訳です。

という訳で、UXってのが「ユーザー体験」ならば、かつてのDOS画面風を再現させたっていいじゃないと思いついたのがこの画面。

<001>

20100901_08.jpg

って、バックを「黒」にして、文字を「緑」にしただけなんですが、もうちょっと工夫が必要ですよね。

  • MS ゴシックのフォントでは字がつぶれるので、もっと適切な固定ピッチフォントで。
  • アルファベット&数字が、きれい過ぎる感じがするので、そのあたりも。

とか。

で、真っ先に実装したいのが Enter キーによるフォーカス移動です。
Enter キーのフォーカス移動は、落とし穴が多くって、少なくとも、

・複数行のテキストボックスが入ると破綻する。
・漢字の確定の Enter キーと、アルファベットの入力途中の Enter キーを区別する。
・1行のテキストボックスだと、Enter キーでビープ音が鳴る仕様。

があります。

複数行のテキストボックスの場合は、かつての画面ってこのパターンはなかったんですよ、考えてみれば。DOSで業務画面を作る場合は、テキストのスクロールとかもなくて、大抵の場合、複数行の入力なんてのもありません。

となれば、ちょっと、業務画面チックに Enter キーを変えていくのも良いかと。

{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

#if true
            // ひとつずつ登録する場合
            ekm = new EnterKeyManager();
            ekm.ProcessTabKeyEvent += new EnterKeyManager.EnterKeyEventHandler(ekm_SampleEvent);
            ekm.Add(textBox1);
            ekm.Add(textBox2);
            ekm.Add(textBox3);
            ekm.Add(textBox4);
            ekm.Add(textBox5);
            ekm.Add(textBox6);
            ekm.Add(textBox7);
            ekm.Add(button1);
#else
            // 全てのコントロールを登録する場合
            ekm = new EnterKeyManager();
            ekm.ProcessTabKeyEvent += new EnterKeyManager.EnterKeyEventHandler(ekm_SampleEvent);
            ekm.SetForm(this);
#endif

        }

        // Enterキーの制御クラス
        EnterKeyManager ekm;
        // タブ移動のイベント
        void ekm_SampleEvent(object sender, bool b)
        {
            this.ProcessTabKey(b);
        }
    }

    /// <summary>
    /// Enterキーで移動させるためのクラス
    /// </summary>
    public class EnterKeyManager
    {
        private List<Control> m_lst = new List<Control>();
        private bool imeEnter = false;

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

        // テキストボックスを追加
        public void Add(TextBox ctrl)
        {
            ctrl.PreviewKeyDown += new PreviewKeyDownEventHandler(ctrl_PreviewKeyDown);
            ctrl.KeyUp += new KeyEventHandler(ctrl_KeyUp);
            ctrl.KeyPress += new KeyPressEventHandler(ctrl_KeyPress);
            m_lst.Add(ctrl);
        }
        // テキスト以外を追加
        public void Add(Control ctrl)
        {
            ctrl.KeyUp += new KeyEventHandler(ctrl_KeyUp);
            m_lst.Add(ctrl);
        }

        // テキストボックスでEnterを押した時、BEEPが鳴るのを防ぐ
        void ctrl_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)Keys.Enter)
            {
                e.Handled = true;
            }
        }

        // タブキー移動のハンドラ
        public delegate void EnterKeyEventHandler(object sender, bool b);
        // Declare the event.
        public event EnterKeyEventHandler ProcessTabKeyEvent;

        // Enterキーの処理
        void ctrl_KeyUp(object sender, KeyEventArgs e)
        {
            if (ProcessTabKeyEvent == null)
                return;

            if (e.KeyCode == Keys.Enter)
            {
                TextBox t = sender as TextBox;
                if (t == null)
                {
                    ProcessTabKeyEvent(sender, !e.Shift);
                }
                else
                {
                    if (e.Shift)
                    {
                        ProcessTabKeyEvent(sender, !e.Shift);
                        e.Handled = true;
                    }
                    else
                    {

                        if (imeEnter == true)
                        {
                            ProcessTabKeyEvent(sender, !e.Shift);
                            e.Handled = true;
                        }
                        imeEnter = false;
                    }
                }
            }
        }
        // 日本語の変換確定のEnterを区別する処理
        private void ctrl_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {
            TextBox t = sender as TextBox;
            if (t != null)
            {
                if (e.KeyData == Keys.Enter)
                {
                    imeEnter = true;
                }
            }
        }

        // フォームから全てのコントロールを設定する
        public void SetForm( Form frm )
        {
            foreach (Control c in frm.Controls)
            {
                TextBox t = c as TextBox;
                if (t != null)
                {
                    this.Add(t);
                }
                else
                {
                    this.Add(c);
                }
            }
        }
    }
}

EnterKeyManager クラスってのを作ってしまいます。
このクラスに、Enter キーで移動したいコントロールを Add メソッドで登録していくか、面倒な場合は Form そのものを渡してしまうか。

ひとずつ登録する場合は

            ekm = new EnterKeyManager();
            ekm.ProcessTabKeyEvent += new EnterKeyManager.EnterKeyEventHandler(ekm_SampleEvent);
            ekm.Add(textBox1);
            ekm.Add(textBox2);
            ekm.Add(textBox3);
            ekm.Add(textBox4);
            ekm.Add(textBox5);
            ekm.Add(textBox6);
            ekm.Add(textBox7);
            ekm.Add(button1);

フォームにあるコントロールを一括で登録する場合は

            ekm = new EnterKeyManager();
            ekm.ProcessTabKeyEvent += new EnterKeyManager.EnterKeyEventHandler(ekm_SampleEvent);
            ekm.SetForm(this);

イベントで、ProcessTabKeyEvent を登録しているのは、フォーカス移動のメソッド ProcessTabKey を呼び出すためなんですね。ProcessTabKey メソッドが protected になっているので、こんな風にしています。
リフレクションを使えば EnterKeyManager クラスに抑え込むことができるかもしれませんが、まあ、ひとまず。

        // Enterキーの制御クラス
        EnterKeyManager ekm;
        // タブ移動のイベント
        void ekm_SampleEvent(object sender, bool b)
        {
            this.ProcessTabKey(b);
        }

な感じで、イベントを受けたら呼び出してくださいということで。

エンターキーのフォーカス移動では、漢字の変換を確定したときの Enter キーと区別するのが結構面倒なので、晒しておきます。

電話番号入力とか、数字のみとか、フォントを固定ピッチにしてよりDOSらしくとか、ちょっと作ってみようかな、と思案中です。

■参考サイト

Enterキーを押した時に、まるでTabキーを押した時のように、次のコントロールにフォーカスを移す: .NET Tips: C#, VB.NET, Visual Studio
http://dobon.net/vb/dotnet/control/enterliketab.html#section1

全ては時の中に… : 【VB.NET】Enterキーで次のコントロールにフォーカスを移す
http://blog.livedoor.jp/akf0/archives/51318097.html#

@IT:.NET TIPS Windowsアプリケーションで[Enter]キーによるフォーカス移動を行うには? – C# VB.NET Windowsフォーム
http://www.atmarkit.co.jp/fdotnet/dotnettips/231winentermove/winentermove.html

単一行テキストボックスでEnterやEscapeキーを押した時にビープ音が鳴らないようにする: .NET Tips: C#, VB.NET, Visual Studio
http://dobon.net/vb/dotnet/control/tbsuppressbeep.html

カテゴリー: 開発 パーマリンク

役所風にEnterキーで次のテキストボックスへ移動 への2件のフィードバック

  1. ふたみ のコメント:

    未確定文字列は反転色、なんて演出も欲しいですね(^^)

  2. t.masuda のコメント:

    「演出」ってw

    そうですね。コマンドプロンプトで漢字変換すると、青地に白文字。
    一太郎の場合は、水色に白文字だった覚えが。

コメントは停止中です。