自家製クオンツ

ソフトウェア技術を使って金融や投資の考察をしています。

MagicalNuts.UI.Baseのその他機能

f:id:yooce:20211207091046p:plain

ひとりアドベントカレンダー23日目です。今日は、MagicalNuts.UI.Baseのうち、これまでに説明できなかった機能を2つ紹介します。

ControlExtensions

ControlExtensionsは、C#組み込みのSystem.Windows.Forms.Controlにメソッドを追加するクラスです。

/// <summary>
/// Controlの拡張を表します。
/// </summary>
public static class ControlExtensions
{
    /// <summary>
    /// Controlを左寄せします。
    /// </summary>
    /// <param name="me">自Control</param>
    /// <param name="baseCtrl">基準Control</param>
    public static void AlignLeft(this Control me, Control baseCtrl)
    {
        me.Left = baseCtrl.Left + baseCtrl.Width + baseCtrl.Margin.Right + me.Margin.Left;
    }

    /// <summary>
    /// Controlを上寄せします。
    /// </summary>
    /// <param name="me">自Control</param>
    /// <param name="baseCtrl">基準Control</param>
    public static void AlignTop(this Control me, Control baseCtrl)
    {
        me.Top = baseCtrl.Top + baseCtrl.Height + baseCtrl.Margin.Bottom + me.Margin.Top;
    }

    /// <summary>
    /// クリップボードにキャプチャ画像をコピーします。
    /// </summary>
    /// <param name="me">自Control</param>
    /// <param name="zoom">倍率</param>
    public static void CopyToClipboard(this Control me, double zoom)
    {
        // キャプチャ
        Bitmap bmp = new Bitmap(me.Width, me.Height);
        me.DrawToBitmap(bmp, new Rectangle(0, 0, me.Width, me.Height));

        // 拡縮
        Bitmap canvas = new Bitmap((int)(me.Width * zoom), (int)(me.Height * zoom));
        Graphics g = Graphics.FromImage(canvas);
        g.DrawImage(bmp, 0, 0, (int)(bmp.Width * zoom), (int)(bmp.Height * zoom));

        // クリップボードにコピー
        Clipboard.SetImage(canvas);

        // 終了
        g.Dispose();
        canvas.Dispose();
        bmp.Dispose();
    }
}

コントロールの左寄せと上寄せ、クリップボードへのキャプチャコピーを実装しています。これらを使う場合はusingした上で、

using MagicalNuts.UI.Base;

Label label1 = new Label();
label1.Left = label1.Margin.Left;

Label label2 = new Label();
label2.AlignLeft(label1);

というように使います。この例では、label1の右隣に「左揃え」でlabel2を配置しています。今はこれだけですが、例えばGroupBox内でのコントロール配置などがあっても良いかもしれません。このように、C#はメソッドを追加して既存のクラスを拡張できるので便利ですよね。まあ、JavascriptPythonでもできるのですけども。

StockIncrementalTextBox

StockIncrementalTextBoxインクリメンタルサーチを備えたテキストボックスです。銘柄選択を用途として想定しており、次のイメージのように動作します。昔作ったGIFアニメーションなので、MagicalNutsで非推奨の米国株になっていますが…。

f:id:yooce:20201023052552g:plain

サンプルとしてIncrementalTextBoxSampleを用意しており、最も基本的な使い方としては、Stockの配列を用意してSetCandidates()に渡すだけです。

StockIncrementalTextBox incrementalTextBox = new StockIncrementalTextBox();
Stock[] Stocks = ...

incrementalTextBox1.SetCandidates(Stocks);

ただ、SetCandidates()は内部で辞書を生成するため、大量の検索対象を渡した場合、処理が重くなります。複数のStockIncrementalTextBoxを配置し、それぞれのSetCandidates()をコールすると、その数だけ処理時間が増大してしまいます。そこで、先に辞書を作っておいて、それを各StockIncrementalTextBoxに設定して高速化を図ることができます。

Dictionary<string, List<IncrementalTextBox.ListViewCandidate>> dict = await IncrementalTextBox.GetCandidateListViewItemDictionaryAsync(
    Stocks, StockIncrementalTextBox.StockKeysForDictionary, StockIncrementalTextBox.StockMatch);

incrementalTextBox2.CandidateListViewItemDictionary = dict;
incrementalTextBox3.CandidateListViewItemDictionary = dict;

StockIncrementalTextBoxの検索対象はStockクラスに限定していますが、その基底クラスIncrementalTextBoxは投資検証に特化したクラスではないので、どんな種類のWindowsフォームアプリケーションでも使用できます。

IncrementalTextBox1 incrementalTextBox = new IncrementalTextBox();

string[] candidates = new string[] { "apple", "banana", "orange", "grape", "peach", "strawberry" };
incrementalTextBox1.SetCandidates(candidates);