WinForms超入門:初めての自作アプリ12選(最小機能つき)

“最初の一作目”は、短時間で完成して動く手応えが得られる題材が最適です。ここでは、レベル別におすすめアプリを並べ、各項目に学べること/最小機能/発展アイデアを添えました。記事後半には、フォーム構成の型頻出スニペットつまずき対策もまとめています。


レベル0(30〜90分)

1) クリックカウンター

  • 学べる:イベント、状態保持、プロパティ更新
  • 最小機能:回数表示ラベル+「+1」「リセット」ボタン
  • 発展アイデア:複数ボタンの内訳、履歴表示

2) 温度変換(℃↔︎℉)

  • 学べる:TryParse による入力検証、責務分離
  • 最小機能:数値入力→変換→結果表示(無効入力はメッセージ)
  • 発展アイデア:双方向切替、履歴リスト、クリップボード連携

3) ストップウォッチ/カウントダウン

  • 学べる:System.Windows.Forms.Timer、UIスレッド更新
  • 最小機能:開始/停止/リセット、mm:ss.ff 表示
  • 発展アイデア:ラップ記録、ホットキー、終了音

Timer最小サンプル(Form1)

public partial class Form1 : Form
{
    private readonly Timer _timer = new() { Interval = 10 }; // 10ms
    private int _elapsedMs;

    public Form1()
    {
        InitializeComponent();
        labelTime.Text = "00:00.00";
        _timer.Tick += Timer_Tick;   // ← シンプル
    }

    private void Timer_Tick(object? sender, EventArgs e)
    {
        _elapsedMs += _timer.Interval;
        labelTime.Text = TimeSpan.FromMilliseconds(_elapsedMs).ToString(@"mm\:ss\.ff");
    }

    private void btnStart_Click(object s, EventArgs e) => _timer.Start();
    private void btnStop_Click(object s, EventArgs e)  => _timer.Stop();
    private void btnReset_Click(object s, EventArgs e)
    {
        _elapsedMs = 0;
        labelTime.Text = "00:00.00";
    }
}

レベル1(半日〜1日)

4) じゃんけん/サイコロ

  • 学べる:Random、enum、switch
  • 最小機能:プレイヤー入力→CPU→勝敗表示
  • 発展アイデア:連勝数、グラフ風ラベル、効果音

5) 単位変換ツール(長さ・重さ・面積)

  • 学べる:ComboBox、モデルクラス設計
  • 最小機能:カテゴリと単位選択→変換
  • 発展アイデア:履歴CSV、ショートカット操作

6) クリップボード整形

  • 学べる:Clipboard API、文字列操作
  • 最小機能:貼り付け→整形→コピー(全角/半角・トリム)
  • 発展アイデア:履歴、正規表現プリセット

レベル2(1〜2日)

7) メモ帳(簡易Notepad)

  • 学べる:MenuStrip、OpenFileDialog/SaveFileDialog、文字コード
  • 最小機能:新規/開く/保存、変更フラグ、終了時の確認
  • 発展アイデア:最近使ったファイル(MRU)、検索/置換、UTF-8/Shift_JIS切替
  • 注意:using var でファイルを確実に閉じる

8) 画像ビューア

  • 学べる:PictureBox、D&D、TrackBarズーム
  • 最小機能:フォルダ選択→前後移動→フィット表示
  • 発展アイデア:回転/反転、サムネイル、スライドショー
  • 注意:pictureBox.Image?.Dispose() を忘れるとファイルがロックされる

9) 単語帳クイズ(CSV)

  • 学べる:ファイルI/O、List<T>、ランダム出題、スコア管理
  • 最小機能:問題→選択肢→正誤→スコア
  • 発展アイデア:タイムアタック、タグ出題、成績JSON保存

レベル3(2〜3日)

10) ToDoリスト(永続化)

  • 学べる:DataGridView / BindingList<T>、データバインディング、JSON保存
  • 最小機能:追加/編集/完了/削除、終了時保存→起動時復元
  • 発展アイデア:未完フィルタ、締切アラート、ドラッグで並べ替え

11) 家計簿ミニ

  • 学べる:LINQ集計、decimal(金額計算)、CSV入出力
  • 最小機能:収支入力→月次合計
  • 発展アイデア:カテゴリ別円グラフ、期間フィルタ、バックアップ

12) タイピングゲーム

  • 学べる:キーボードイベント、Timer、難易度調整
  • 最小機能:単語提示→タイプ→スコア
  • 発展アイデア:連続モード、ランキング、辞書入替

最初の一作:進め方テンプレート

ここでは「温度変換」を例に設計→実装→検証の型を示します。どの題材にも流用できます。

1. 仕様を1行で言語化

  • 「数値(℃)を入力し、ボタンで℉へ変換して表示。無効入力は警告する。」

2. フォーム構成(命名まで先に決める)

  • TextBox(txtCelsius)
  • Button(btnToFahrenheit)
  • Label(lblResult)
  • (任意)ErrorProvider(errorProvider1)

3. ロジックをFormから分離(テストしやすく)

public static class TemperatureConverter
{
    public static double CelsiusToFahrenheit(double c) => c * 9.0 / 5.0 + 32;
}

4. UIコードは薄く・入力検証は TryParse

private void btnToFahrenheit_Click(object sender, EventArgs e)
{
    errorProvider1.SetError(txtCelsius, "");
    if (!double.TryParse(txtCelsius.Text, out var c))
    {
        errorProvider1.SetError(txtCelsius, "数値を入力してください。");
        return;
    }
    var f = TemperatureConverter.CelsiusToFahrenheit(c);
    lblResult.Text = $"{f:F1} ℉";
}

5. 動作確認チェック

  • 無効入力時に落ちない(例外なし)
  • 小数入力もOK
  • 連打しても表示が崩れない

フォーム設計の「型」

命名規則(例)

  • Button: btnStart, btnSave
  • Label: lblStatus, lblCount
  • TextBox: txtInput, txtPath
  • Timer: timerMain
  • PictureBox: picPreview

イベントの基本

  • イベントは1アクション=1メソッドを原則に短く保つ
  • 長くなる処理は別クラスやメソッドへ切り出す
  • 匿名ラムダでの購読は解除が難しいので、基本は名前付きハンドラ

頻出スニペット集

1) TryParse パターン

if (!int.TryParse(txtCount.Text, out var count))
{
    MessageBox.Show("整数を入力してください。");
    return;
}

2) ファイルを確実に閉じる

using var sw = new StreamWriter(path, append: false, Encoding.UTF8);
sw.WriteLine("hello");

3) 実行ファイル横のデータを読む(学習用)

  • CSVや画像を「出力ディレクトリにコピー」して、以下で参照
string dataPath = Path.Combine(AppContext.BaseDirectory, "questions.csv");
var lines = File.ReadAllLines(dataPath, Encoding.UTF8);

実運用では AppData 等に保存するのが一般的。学習初期は「コピーして読む」で十分です。

4) 画像のロックを避ける

using var fs = new FileStream(path, FileMode.Open, FileAccess.Read);
using var img = Image.FromStream(fs);
pictureBox.Image?.Dispose();
pictureBox.Image = new Bitmap(img);

5) Timer は UI用を使う

  • やってはいけない:Thread.Sleep(…)(UIが固まる)
  • やるべき:System.Windows.Forms.Timer で Tick 内だけ更新

つまずき対策(よくある5項)

  1. UIが固まる
    • 原因:Thread.Sleep や重い処理の直書き
    • 対策:Timer・非同期処理へ分離、重い処理は別スレッド
  2. ファイルが保存/読み込みできない
    • 原因:パスの勘違い/ファイルを閉じていない
    • 対策:AppContext.BaseDirectory で確認、using で確実にDispose
  3. 画像が編集できない/上書きできない
    • 原因:Image のDispose漏れ
    • 対策:差し替え前に pictureBox.Image?.Dispose()
  4. イベントが解除できない
    • 原因:匿名ラムダで += して -= できない
    • 対策:名前付きハンドラ、またはラムダを変数に保持して解除
  5. テストが難しい
    • 原因:ロジックをFormに直書き
    • 対策:モデルクラスへ分離(例:TemperatureConverter)

学習課題(自力で伸ばすためのチェックリスト)

  • どの題材でも仕様を1行で言語化できたか
  • 最小機能を先に完成 → 後から発展アイデアを1つだけ足す
  • UI名前は意味のあるものに(button1卒業)
  • 例外を出さずに無効入力を扱えるか(TryParse/ErrorProvider)
  • 画像/ファイルは必ず閉じる(Dispose)

まとめ:まずは1時間で「動く」を掴む

  • 初作は ストップウォッチ か 温度変換 が特におすすめ。
  • できあがったら、命名の見直し入力検証だけでもう一段きれいになります。
  • ロジックを別クラスに分ける癖を、この段階から身につけましょう。

訪問数 3 回, 今日の訪問数 3回