【C#】WinFormsクイズアプリの作成

この資料では、Windows Formsを使った簡単なクイズアプリの作成方法を紹介します。初学者にも理解しやすいように、ステップバイステップで説明します

クイズアプリサンプル

1. プロジェクトの作成

  1. Visual Studioを開きます。
  2. 新しいプロジェクトを作成します。Windows Forms Appテンプレートを選択します。
  3. プロジェクト名を「QuizApp」とし、保存場所を選択して「作成」をクリックします。

2. フォームデザインとイベントハンドラーの登録

  1. フォームのタイトルを「クイズアプリ」に変更します。
  2. 以下のコントロールをフォームに追加します:
    • Label: 質問を表示するためのラベル。名前を questionLabel に変更。
    • RadioButton: 選択肢を表示するためのラジオボタン。4つ追加し、それぞれの名前を option1RadioButtonoption2RadioButtonoption3RadioButtonoption4RadioButton に変更。
    • Button: 回答を確認するためのボタン。名前を submitButton に変更し、テキストを「確認」に設定。
    • Label: 結果を表示するためのラベル。名前を resultLabel に変更し、初期テキストを空白に設定。
  3. submitButton のクリックイベントハンドラーを登録します:
    • Visual Studioのフォームデザイナーで、submitButton を選択します。
    • プロパティウィンドウで、イベント(稲妻アイコン)タブをクリックします。
    • Click イベントの欄に「SubmitButton_Click」と入力してEnterキーを押します。

3. コードの追加

  1. Form1.cs を開きます。
  2. クラスの先頭に以下のコードを追加し、質問と回答を保持するリストを定義します。
using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace QuizApp
{
    public partial class Form1 : Form
    {
        private List<Question> questions;
        private int currentQuestionIndex;
        
        public Form1()
        {
            InitializeComponent();
            LoadQuestions();
            DisplayQuestion();
        }

        private void LoadQuestions()
        {
            questions = new List<Question>
            {
                new Question
                {
                    Text = "日本の首都はどこですか?",
                    Options = new string[] { "大阪", "東京", "京都", "福岡" },
                    CorrectOption = 1
                },
                new Question
                {
                    Text = "次のうち、2 + 2 の答えはどれですか?",
                    Options = new string[] { "3", "4", "5", "6" },
                    CorrectOption = 1
                }
                // ここにさらに質問を追加
            };
            currentQuestionIndex = 0;
        }

        private void DisplayQuestion()
        {
            if (currentQuestionIndex < questions.Count)
            {
                var question = questions[currentQuestionIndex];
                questionLabel.Text = question.Text;
                option1RadioButton.Text = question.Options[0];
                option2RadioButton.Text = question.Options[1];
                option3RadioButton.Text = question.Options[2];
                option4RadioButton.Text = question.Options[3];
            }
            else
            {
                questionLabel.Text = "これ以上の質問はありません。";
                option1RadioButton.Visible = false;
                option2RadioButton.Visible = false;
                option3RadioButton.Visible = false;
                option4RadioButton.Visible = false;
                submitButton.Visible = false;
            }
        }

        private void SubmitButton_Click(object sender, EventArgs e)
        {
            var question = questions[currentQuestionIndex];
            int selectedOption = -1;
            if (option1RadioButton.Checked) selectedOption = 0;
            if (option2RadioButton.Checked) selectedOption = 1;
            if (option3RadioButton.Checked) selectedOption = 2;
            if (option4RadioButton.Checked) selectedOption = 3;

            if (selectedOption == question.CorrectOption)
            {
                resultLabel.Text = "正解!";
            }
            else
            {
                resultLabel.Text = "不正解。正しい答えは:" + question.Options[question.CorrectOption];
            }

            currentQuestionIndex++;
            DisplayQuestion();
        }
    }

    public class Question
    {
        public string Text { get; set; }
        public string[] Options { get; set; }
        public int CorrectOption { get; set; }
    }
}

リファクタリング

1. リファクタリングとは

リファクタリングとは、既存のコードの外部動作を変えずに内部構造を改善することを指します。これにより、コードの可読性、保守性、再利用性が向上します。


2. リファクタリングの目的

  • 可読性の向上: 他の開発者や未来の自分が理解しやすいコードを書く。
  • 保守性の向上: 変更や修正が容易になる。
  • 再利用性の向上: 同じコードを他のプロジェクトでも利用しやすくする。

3. 具体的なリファクタリングの手順

  1. 冗長なコードの削減: 繰り返し使われるコードをメソッドにまとめる。
  2. 命名の改善: 変数やメソッドの名前を意味のあるものに変更する。
  3. 分離と抽出: 大きなメソッドを小さなメソッドに分割し、それぞれが単一の責任を持つようにする。
  4. クラスの整理: クラスの責任を明確にし、関連するデータやメソッドをまとめる。

4. リファクタリング後のコード

using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace QuizApp
{
    public partial class Form1 : Form
    {
        private List<Question> questions;
        private int currentQuestionIndex;

        public Form1()
        {
            InitializeComponent();
            LoadQuestions();
            DisplayQuestion();
        }

        private void LoadQuestions()
        {
            questions = new List<Question>
            {
                new Question("日本の首都はどこですか?", new[] { "大阪", "東京", "京都", "福岡" }, 1),
                new Question("次のうち、2 + 2 の答えはどれですか?", new[] { "3", "4", "5", "6" }, 1)
                // ここにさらに質問を追加
            };
            currentQuestionIndex = 0;
        }

        private void DisplayQuestion()
        {
            if (currentQuestionIndex < questions.Count)
            {
                var question = questions[currentQuestionIndex];
                questionLabel.Text = question.Text;
                DisplayOptions(question.Options);
            }
            else
            {
                ShowEndOfQuiz();
            }
        }

        private void DisplayOptions(string[] options)
        {
            option1RadioButton.Text = options[0];
            option2RadioButton.Text = options[1];
            option3RadioButton.Text = options[2];
            option4RadioButton.Text = options[3];
        }

        private void ShowEndOfQuiz()
        {
            questionLabel.Text = "これ以上の質問はありません。";
            option1RadioButton.Visible = false;
            option2RadioButton.Visible = false;
            option3RadioButton.Visible = false;
            option4RadioButton.Visible = false;
            submitButton.Visible = false;
        }

        private void SubmitButton_Click(object sender, EventArgs e)
        {
            var question = questions[currentQuestionIndex];
            int selectedOption = GetSelectedOption();

            if (selectedOption == question.CorrectOption)
            {
                resultLabel.Text = "正解!";
            }
            else
            {
                resultLabel.Text = $"不正解。正しい答えは:{question.Options[question.CorrectOption]}";
            }

            currentQuestionIndex++;
            DisplayQuestion();
        }

        private int GetSelectedOption()
        {
            if (option1RadioButton.Checked) return 0;
            if (option2RadioButton.Checked) return 1;
            if (option3RadioButton.Checked) return 2;
            if (option4RadioButton.Checked) return 3;
            return -1;
        }
    }

    public class Question
    {
        public string Text { get; }
        public string[] Options { get; }
        public int CorrectOption { get; }

        public Question(string text, string[] options, int correctOption)
        {
            Text = text;
            Options = options;
            CorrectOption = correctOption;
        }
    }
}

リファクタリングのポイント

  1. Questionクラスのコンストラクタ追加:
    • 以前のQuestionクラスはプロパティ設定のために複数行必要でした。コンストラクタを追加することで、インスタンス化を1行で行えるようになり、コードがシンプルになりました。
  2. DisplayOptionsメソッドの追加:
    • 選択肢を表示する部分をDisplayOptionsメソッドに分離することで、DisplayQuestionメソッドの責任を減らし、単一責任の原則を守るようにしました。
  3. ShowEndOfQuizメソッドの追加:
    • クイズの終わりを表示する部分をShowEndOfQuizメソッドに分離することで、DisplayQuestionメソッドのコード量を減らし、可読性を向上させました。
  4. GetSelectedOptionメソッドの追加:
    • 選択されたオプションを取得する部分をGetSelectedOptionメソッドに分離することで、SubmitButton_Clickメソッドがより明確になり、理解しやすくなりました。

5. まとめ

リファクタリングを行うことで、コードの可読性や保守性が向上します。リファクタリングの基本原則を理解し、実際にコードに適用することで、より良いプログラムを書く力を身につけることができます。