cyphen156

C# 실습 1 .NET 8 Winforms 앱 만들기 본문

프로그래밍/C#

C# 실습 1 .NET 8 Winforms 앱 만들기

cyphen156 2023. 11. 30. 10:41

이 글에서는 .NET 8과 Winforms를 사용하여 계산기와 로그인창, 숫자 맞추는 게임을 만든다.

 

1. 기본 개념익히기

맨처음 WindowsForms 앱 템플릿으로 프로젝트를 생성하면 다음과 같은 화면 구성을 만들 수 있다.

완벽하게 일치하는 것은 아니지만 어느정도 안드로이드 앱 만들때의 경험을 되살려서 여기에 써먹을 수 있을것 같다. Form1.cs[디자인]에서는 안드로이드 XML파일과 같이 화면 구성을 담당하는 파일이다. 도구상자에서 UI구성에 필요한 요소들을 디자인 창에 드래그 & 드롭으로 추가할 수 있다. 

Form1.cs파일은 디자인 파일과 연동되어 실제 화면 로직에서 여러 이벤트들이 발생했을 때 처리되는 로직들을 담당할 클래스파일이다. 추가된 요소들을 속성 창을 통해 제어하거나 직접 코드 수정을 통해 바꿀 수 있다.

Program.cs파일은 프로그램이 실행되었을 때 가장 먼저 진입하게되는 main파일로, 안드로이드의 Mainactivity.java(kt)파일에 해당한다.

버튼을 디자인에 놓았을 때 From1.cs파일 안에 private void button1_click이라는 함수가 생겼다. 그리고 Form1.Designer.cs파일에는 private Button 버튼1이라는 버튼 인스턴스가 생겻다.

이 인스턴스는 Form1.Designer.cs파일 안에 존재하는 InitializeComponent 메서드가 호출될때 버튼에 대한 정보를 담고 있는 인스턴스로, 여러가지 옵션들을 가지고 있다. 여기서 직접 코드를 수정해도 되고, 속성 창을 통해 수정해도 된다.

이제 버튼을 한개 더 넣고서 클릭 이벤트에서 버튼 텍스트를 바꾸는 로직을 적용시켜보자

이래놓고서 F5를 눌러 디버깅하면 다음과 같이 동작하는 프로그램이 완성된다.

https://youtu.be/kPTnOox6_rA

 

2. 로그인 창 구성하기

맨 처음 해야할 일은 화면 레이아웃부터 구성하는것이다. 

코드가 길어서 접어놓겠다.

더보기
namespace WinFormsEx
{
    partial class Form1
    {
        /// <summary>
        ///  Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        ///  Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        ///  Required method for Designer support - do not modify
        ///  the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            label1 = new Label();
            textBox1 = new TextBox();
            textBox2 = new TextBox();
            button1 = new Button();
            SuspendLayout();
            // 
            // label1
            // 
            label1.AutoSize = true;
            label1.Location = new Point(240, 158);
            label1.Name = "Login";
            label1.Size = new Size(100, 23);
            label1.TextAlign = ContentAlignment.MiddleCenter;
            label1.TabIndex = 0;
            label1.Text = "로그인 창";
            label1.Click += label1_Click;
            // 
            // textBox1
            // 
            textBox1.Location = new Point(222, 176);
            textBox1.Name = "ID";
            textBox1.Text = "ID";
            textBox1.Size = new Size(100, 23);
            textBox1.TabIndex = 1;
            textBox2.TextChanged += this.textBox1_TextChanged;
            // 
            // textBox2
            // 
            textBox2.Location = new Point(222, 205);
            textBox2.Name = "Password";
            textBox2.Text = "Password";
            textBox2.Size = new Size(100, 23);
            textBox2.TabIndex = 2;
            textBox2.TextChanged += this.textBox2_TextChanged;
            // 
            // button1
            // 
            button1.Location = new Point(222, 234);
            button1.Name = "Log-In";
            button1.Size = new Size(100, 30);
            button1.TabIndex = 3;
            button1.Text = "로그인 하기";
            button1.UseVisualStyleBackColor = true;
            button1.Click += this.button1_Click;
            // 
            // Form1
            // 
            AutoScaleDimensions = new SizeF(7F, 15F);
            AutoScaleMode = AutoScaleMode.Font;
            ClientSize = new Size(800, 450);
            Controls.Add(button1);
            Controls.Add(textBox2);
            Controls.Add(textBox1);
            Controls.Add(label1);
            Name = "Form1";
            Text = "Form1";
            ResumeLayout(false);
            PerformLayout();
        }

        #endregion

        private Label label1;
        private TextBox textBox1;
        private TextBox textBox2;
        private Button button1;
    }
}

위 코드를 Form1.Designer.cs파일에 적용하면 다음과 같은 화면 레이아웃이 구성된다.

그리고 나서 이벤트 연결을 위해 Form1.cs파일에 다음과 같은 메서드들을 추가한다. 

이 메서드들 중 button1_Click이벤트만 사용할 것이다.

private void button1_Click(object sender, EventArgs e)
{
    string UId = textBox1.Text;
    string UPw = textBox2.Text;
    if (UId.Equals("Admin"))
    {
        if (UPw.Equals("12345678"))
        {
            MessageBox.Show("로그인 성공", "로그인");
        }
        else
        {
            MessageBox.Show("비밀번호가 다릅니다.", "WrongPassword");
        }
    }
    else
    {
        MessageBox.Show("아이디가 다릅니다.", "invalid ID");
    }
    
}

https://youtu.be/rwzjuk-vMdI

추가적으로 비밀번호 가리기 옵션은 textBox2의 속성에 Passwordchar에 원하는 문자를 넣으면 해당 문자로 대체되어 표기된다.

3. 숫자 맞히기 게임으로 이동하기

로그인에 성공했으면 숫자맞히기 게임으로 화면을 전환시킬것이다. 기존에 사용하는 창을 그대로 놔둔 채 가시/비가시를 이용해 바꾸려고 한다.

우선 로그인 성공시 로그인화면을 비활성화 하자. 

2에서 만들었던 button1_Click메서드의 로그인 성공 로직에 다음 코드를 삽입하자. 사실 그냥 보이지 않도록 처리한것이기때문에 로그인 기능은 해당 화면에 아직 살아있다.

label1.Visible = false;
textBox1.Visible = false;
textBox2.Visible = false;
button1.Visible = false;

 

그리고 UI에 label 1개, textBox1개, button 2개를 추가로 생성하되, 초기 visible의 값을 false로 준다.

추가된 메서드는 다음과 같다.

더보기
namespace WinFormsEx
{
    partial class Form1
    {
        /// <summary>
        ///  Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        ///  Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        ///  Required method for Designer support - do not modify
        ///  the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            label1 = new Label();
            textBox1 = new TextBox();
            textBox2 = new TextBox();
            button1 = new Button();
            label2 = new Label();
            textBox3 = new TextBox();
            button2 = new Button();
            button3 = new Button();
            SuspendLayout();
            // 
            // label1
            // 
            label1.AutoSize = true;
            label1.Location = new Point(240, 158);
            label1.Name = "Login";
            label1.Size = new Size(100, 23);
            label1.TextAlign = ContentAlignment.MiddleCenter;
            label1.TabIndex = 0;
            label1.Text = "로그인 창";
            label1.Click += label1_Click;
            // 
            // textBox1
            // 
            textBox1.Location = new Point(222, 176);
            textBox1.Name = "ID";
            textBox1.Text = "ID";
            textBox1.Size = new Size(100, 23);
            textBox1.TabIndex = 1;
            textBox2.TextChanged += this.textBox1_TextChanged;
            // 
            // textBox2
            // 
            textBox2.Location = new Point(222, 205);
            textBox2.Name = "Password";
            textBox2.Text = "Password";
            textBox2.Size = new Size(100, 23);
            textBox2.TabIndex = 2;
            textBox2.TextChanged += this.textBox2_TextChanged;
            // 
            // button1
            // 
            button1.Location = new Point(222, 234);
            button1.Name = "Log-In";
            button1.Size = new Size(100, 30);
            button1.TabIndex = 3;
            button1.Text = "로그인 하기";
            button1.UseVisualStyleBackColor = true;
            button1.Click += this.button1_Click;
            // 
            // label2
            // 
            label2.AutoSize = false;
            label2.Location = new Point(220, 202);
            label2.Name = "GameLabel";
            label2.Size = new Size(150, 30);
            label2.TabIndex = 4;
            label2.Text = "게임을 시작합니다.";
            label2.Visible = false;
            // 
            // textBox3
            // 
            textBox3.Location = new Point(156, 224);
            textBox3.Name = "TextInput";
            textBox3.Size = new Size(100, 23);
            textBox3.TabIndex = 5;
            textBox3.Visible = false;
            // 
            // button2
            // 
            button2.Location = new Point(287, 223);
            button2.Name = "InputText";
            button2.Size = new Size(75, 23);
            button2.TabIndex = 6;
            button2.Text = "입력";
            button2.UseVisualStyleBackColor = true;
            button2.Visible = false;
            button2.Click += Button2_Click;
            // 
            // button3
            // 
            button3.Location = new Point(240, 253);
            button3.Name = "StartGame";
            button3.Size = new Size(75, 23);
            button3.TabIndex = 7;
            button3.Text = "게임 시작";
            button3.UseVisualStyleBackColor = true;
            button3.Visible = false;
            button3.Click += Button3_Click;
            // 
            // Form1
            // 
            AutoScaleDimensions = new SizeF(7F, 15F);
            AutoScaleMode = AutoScaleMode.Font;
            ClientSize = new Size(800, 450);
            Controls.Add(button3);
            Controls.Add(button2);
            Controls.Add(textBox3);
            Controls.Add(label2);
            Controls.Add(button1);
            Controls.Add(textBox2);
            Controls.Add(textBox1);
            Controls.Add(label1);
            Name = "Form1";
            Text = "Form1";
            ResumeLayout(false);
            PerformLayout();
        }

        #endregion

        private Label label1;
        private TextBox textBox1;
        private TextBox textBox2;
        private Button button1;
        private Label label2;
        private TextBox textBox3;
        private Button button2;
        private Button button3;
    }
}

아직 프로그램을 실행하지 않은 상태에서는 다음과 같이 화면이 구성된다.

로그인 성공시 비활성화 코드 하단에 다음과 같은 코드를 입력해 새 폼을 보여준다.

label2.Visible = true;
textBox3.Visible = true;
button2.Visible = true;
button3.Visible = true;

Form1 클래스 내부에 다음과 같은 변수들을 선언하고, button3에 이벤트를 연결하여 게임 시작버튼 이벤트를 생성한다.

private int findNumber = 0;
private int chance = 0;
private void Button3_Click(object sender, EventArgs e)
{
    var rand = new Random();
    findNumber = rand.Next(1, 21);
    chance = 10;
    label2.Text = "맞힐 숫자를 입력하세요.";
}

그리고 입력 버튼에 이벤트를 연결한다.

private void Button2_Click(object sender, EventArgs e)
{
    int inputNumber = Int32.Parse(textBox3.Text);
    if ( inputNumber == findNumber)
    {
        label2.Text = "승리했습니다.!!";
    }
    else
    {
        chance--;
        label2.Text = "기회는" + chance + "번 남았습니다.";
    }

    if (chance <= 0)
    {
        label2.Text = "실패하였습니다.";
    }
}

 

C# Winform 숫자 맞히기 게임 - YouTube

4. 계산기로 화면 전환하기.

이번엔 기존 화면을 그대로 사용하여 눈속임 하는것이 아니라 실제로 화면을 이동시킬 것이다.

3. 에서의 정답을 맞췄을 때 계산기 폼 인스턴스를 생성하고, 화면을 보여준다.

if ( inputNumber == findNumber)
{
    label2.Text = "승리했습니다.!!\n계산기로 이동합니다.";
    // 계산기 폼으로 이동
    Calculator calculatorForm = new Calculator();
    calculatorForm.Show();
}

이러면 연결준비는 끝났다. 이제 계산기 로직만 스스로 구현하면 된다.

최종 결과물과 코드는 다음과 같다.

https://youtu.be/1bTsN6xZdrU

더보기
namespace WinFormsEx
{
    public partial class Calculator : Form
    {
        // 연산자 
        enum Operators
        {
            None,
            Add,
            Subtract,
            Multiply,
            Divide,
            Reset
        }

        Operators currentOperator = Operators.None;
        Boolean operatorChangeFlag = false;
        double firstOperand = 0;
        double secondOperand = 0;

        public Calculator()
        {
            InitializeComponent();
        }
        private void AddNumberToDisplay(string number)
        {
            if (operatorChangeFlag)
            {
                label1.Text = "";
                operatorChangeFlag = false;
            }

            label1.Text += number;
        }
        private void tableLayoutPanel1_Paint(object sender, PaintEventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            AddNumberToDisplay("1");
        }

        private void button2_Click(object sender, EventArgs e)
        {
            AddNumberToDisplay("2");
        }

        private void button3_Click(object sender, EventArgs e)
        {
            AddNumberToDisplay("3");
        }

        private void button4_Click(object sender, EventArgs e)
        {
            AddNumberToDisplay("4");
        }

        private void button5_Click(object sender, EventArgs e)
        {
            AddNumberToDisplay("5");
        }

        private void button6_Click(object sender, EventArgs e)
        {
            AddNumberToDisplay("6");
        }

        private void button7_Click(object sender, EventArgs e)
        {
            AddNumberToDisplay("7");
        }

        private void button8_Click(object sender, EventArgs e)
        {
            AddNumberToDisplay("8");
        }

        private void button9_Click(object sender, EventArgs e)
        {
            AddNumberToDisplay("9");
        }

        private void label1_Click(object sender, EventArgs e)
        {

        }

        private void button17_Click(object sender, EventArgs e)
        {
            try
            {
                secondOperand = double.Parse(label1.Text);
                double result = 0;

                // 연산자에 따라 계산
                if (currentOperator == Operators.Add)
                {
                    result = firstOperand + secondOperand;
                }
                else if (currentOperator == Operators.Subtract)
                {
                    result = firstOperand - secondOperand;
                }
                else if (currentOperator == Operators.Multiply)
                {
                    result = firstOperand * secondOperand;
                }
                else if (currentOperator == Operators.Divide)
                {
                    if (secondOperand == 0)
                    {
                        label1.Text = "0으로 나눌 수 없습니다.";
                        return;
                    }
                    result = firstOperand / secondOperand;
                }

                label1.Text = result.ToString();
                firstOperand = result; // 다음 연산을 위해 결과 저장
            }
            catch
            {
                label1.Text = "오류";
            }
        }

        private void button15_Click(object sender, EventArgs e)
        {
            AddNumberToDisplay("0");
        }

        private void button14_Click(object sender, EventArgs e)
        {
            if (operatorChangeFlag)
            {
                label1.Text = "";
                operatorChangeFlag = false;
            }

            // 이미 소수점이 있으면 추가하지 않음
            if (!label1.Text.Contains("."))
            {
                label1.Text += ".";
            }
        }

        private void button13_Click(object sender, EventArgs e)
        {
            firstOperand = 0;
            secondOperand = 0;
            currentOperator = Operators.None;
            label1.Text = "";
        }

        private void button11_Click(object sender, EventArgs e)
        {
            firstOperand = double.Parse(label1.Text);
            currentOperator = Operators.Divide;
            operatorChangeFlag = true;
        }

        private void button16_Click(object sender, EventArgs e)
        {
            firstOperand = double.Parse(label1.Text);
            currentOperator = Operators.Add;
            operatorChangeFlag = true;
        }

        private void button10_Click(object sender, EventArgs e)
        {
            firstOperand = double.Parse(label1.Text);
            currentOperator = Operators.Subtract;
            operatorChangeFlag = true;
        }

        private void button12_Click(object sender, EventArgs e)
        {
            firstOperand = double.Parse(label1.Text);
            currentOperator = Operators.Multiply;
            operatorChangeFlag = true;
        }
    }
}

최종적으로는 다음과 같이 프로그램이 작동한다.

전체 코드는 다음 경로에 있습니다.

Workspace/C#/WinFormsEx at main · cyphen156/Workspace (github.com)

 

 

 

 

 

'프로그래밍 > C#' 카테고리의 다른 글

C# 버전별 핵심 기능 (1.0 ~ 7.0)  (0) 2023.12.01
C#에서 클래스와 namespace(C++와 다른점 2)  (0) 2023.11.29
C# 기초2 C/C++와 다른점  (2) 2023.11.28
C# 기초1  (0) 2023.11.28