C#のwinformsでUserControlのサンプル

コンピュータ

UserControlで16進数を入力するサンプルを作成してみました。

namespace UserControlSample;

public class User1 : UserControl
{
    Font fnt = new Font("MS Gothic", 12);
    int cur_x = 0;
    int cur_y = 0;
    int char_width = 40;
    int char_height = 28;
    byte[] bins = new byte[16*16];
    bool cur_flag = false;
    string input_key = "";

    System.Timers.Timer timer;

    public User1()
    {
        Size = new Size(640, 480);
        DoubleBuffered = true;
        timer = new System.Timers.Timer(500);
        timer.Elapsed += (s, e) => {
            cur_flag = !cur_flag;
            Invalidate();
        };
    }
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        timer.Start();
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        
        Brush a = cur_flag ? Brushes.Black : Brushes.White;
        e.Graphics.FillRectangle(a,
            cur_x * char_width,
            cur_y * char_height + char_height - 3, char_width, 3);

        for(int i=0;i < bins.Count(); i++)
        {
            int x = i % 16;
            int y = i / 16;

            string t = String.Format("{0:X2} ", bins[i]);

            e.Graphics.DrawString(t, fnt, Brushes.Black,
                x * char_width,
                y * char_height);

        }
    }
    protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
    {
        base.OnPreviewKeyDown(e);
        bool flag = true;
        switch (e.KeyCode) {
            case Keys.Left:
                if (cur_x == 0) break;
                cur_x--;
                break;
            case Keys.Right:
                if (cur_x == 15) break;
                cur_x++;
                break;
            case Keys.Up:
                if (cur_y == 0) break;
                cur_y--;
                break;
            case Keys.Down:
                if (cur_y == 15) break;
                cur_y++;
                break;
            default:
                flag = false;
                break;
        }
        if (flag) {
            Invalidate();
        }
    }
    protected override void OnKeyDown(KeyEventArgs e)
    {
        base.OnKeyDown(e);

        switch (e.KeyCode) {
            case Keys.NumPad0:
            case Keys.D0:
                input_key += "0";
                break;
            case Keys.NumPad1:
            case Keys.D1:
                input_key += "1";
                break;
            case Keys.NumPad2:
            case Keys.D2:
                input_key += "2";
                break;
            case Keys.NumPad3:
            case Keys.D3:
                input_key += "3";
                break;
            case Keys.NumPad4:
            case Keys.D4:
                input_key += "4";
                break;
            case Keys.NumPad5:
            case Keys.D5:
                input_key += "5";
                break;
            case Keys.NumPad6:
            case Keys.D6:
                input_key += "6";
                break;
            case Keys.NumPad7:
            case Keys.D7:
                input_key += "7";
                break;
            case Keys.NumPad8:
            case Keys.D8:
                input_key += "8";
                break;
            case Keys.NumPad9:
            case Keys.D9:
                input_key += "9";
                break;
            case Keys.A:
                input_key += "A";
                break;
            case Keys.B:
                input_key += "B";
                break;
            case Keys.C:
                input_key += "C";
                break;
            case Keys.D:
                input_key += "D";
                break;
            case Keys.E:
                input_key += "E";
                break;
            case Keys.F:
                input_key += "F";
                break;
        }
        if (input_key.Length >= 2) {
            int i = cur_y * 16 + cur_x;
            bins[i] = (byte)Convert.ToInt32(input_key, 16);
            input_key = "";
            if (cur_x == 15 && cur_y == 15) {

            } else {
                cur_x++;
                if (cur_x >= 16) {
                    cur_x = 0;
                    cur_y++;
                }
            }
            Invalidate();
        }
    }
    protected override void Dispose(bool disposing)
    {
        base.Dispose(Disposing);

        System.Diagnostics.Debug.Print("Dispose()");
        fnt.Dispose();
        timer.Stop();
    }
}
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        var user1 = new User1();

        Controls.Add(user1);
    }
}

バイナリエディタが作れないかとエディト部分を試作してみました。
16進数の入力は2文字分を打つと値が変更されてカーソルが移動します。

カーソルを点滅させるためにタイマーをセットしていますが、画面の更新のたびにチラつくようになりました。
チラつき防止のためにDoubleBufferedにtrueをセットしています。
また、OnKeyDownで十字キーを拾う事が出来なかったので、十字キーはOnPreviewKeyDownで処理するようにしています。

UserControlについて
自分のイメージするところのUserControlを使ったサンプルなのですが、実用に問題ないレベルのオリジナルコントロールを作ろうとすると大変で余り現実的ではないような気がします。既存のコントロール同士を組み合わせて、使いまわすような使い方が現実的だと思われます。
例えばPictureBoxにスクロールバー機能をつけるためにAutoScrollをtrueにしたPanelにPictureBoxのSizeModeをAtutoSzieにしたコントロールを配置します。また、表示画像をドラッグアンドドロップで受け入れるルーチンなども毎回同じコードを書くことが多いです。このような自分が良く使うコントロールへ機能の追加や設定を施した状態をUserControlとしてライブラリ化することが実用的な使い方だと思われます。

コメント