C# 이것저것/WinForm

[C#] WinForm을 활용한 계산기 만들기

agingcurve 2024. 2. 5. 09:44
반응형

 

 

WinForm에 익숙해지기 위해 기본적인 사칙연산을 수행하는 계산기 프로그램을 만들어 봤다

 

구현사항

 - 버튼의 이벤트 처리

 - 계산 로직

 - 결과 표시

 - 오류 처리

 - 소수점 계산등의 추가기능

 

 

나누기 버튼 예시

 - 사칙연산 버튼 클릭 시 어떤 계산을 수행할지 currentOperator 변수에 Operator Enum을 설정하고(Add, Sub, Mul, Div 중 하나), 계산과정 창에 수행할 계산 기호 추가함

    public partial class Form1 : Form
    {
        enum Operators
        {
            None,
            Add,
            Sub,
            Mul,
            Div,
            Res
        }

        Operators currentOperator = Operators.None;
    }

 

private void ButtonDivide_Click(object sender, EventArgs e)
{
    try
    {
        if (currentOperator != Operators.None && isNumClicked)
        {
            display_process.Text = "";
            CalCulOperator(currentOperator);
            isNumClicked = false;
        }
        firstOper = double.Parse(display.Text);
        currentOperator = Operators.Div;
        operatorChangeFlag = true;
        if (display_process.Text.Contains("="))
        {
            display_process.Text = "";
        }
        if (display_process.Text.Contains("÷") == false)
        {
            display_process.Text = "";
            display_process.Text += display.Text + " ÷ ";
        }
    }
    catch (Exception ex)
    {
        LogException(ex);
    }

}

 

숫자버튼 예시

- 숫저버튼이 눌릴경우, operatorChangeFlag를 통해 이전 이벤트가 사칙연산인지 확인, 사칙연산이라면 결과차으이 숫자를 지우고 새로운 숫자를 입력함

private void ButtonOne_Click(object sender, EventArgs e)
{
    try
    {
        Cal_Res_Reset();
        if (operatorChangeFlag == true)
        {
            display.Text = "";
            operatorChangeFlag = false;
        }
        string strNumber = display.Text += "1";
        isNumClicked = true;
        display.Text = Change_Numtype(strNumber);
    }
    catch (Exception ex)
    {
        LogException(ex);
    }

}

 

계산기능예시

 - Enum 정의를 통해 연산과정의 가독성을 높였으며 설정된 연산에 따라 firstOper에 저장된 변수와 현재 결과창에 있는 숫자를 secondOper에 저장 후 계산을 수행 및 결과를 송출

 - 이부분은 C# 스타일상 switch case로 구현했으면 깔끔한 코드가 될 수 있었던거 같다

 

private void CalCulOperator(Operators currentOperator)
{
secondOper = double.Parse(display.Text);
if (currentOperator == Operators.Add)
{
    firstOper += secondOper;
    display.Text = firstOper.ToString();
}
else if (currentOperator == Operators.Sub)
{
    firstOper -= secondOper;
    display.Text = firstOper.ToString();
}
else if (currentOperator == Operators.Mul)
{
    firstOper *= secondOper;
    display.Text = firstOper.ToString();
}
else if (currentOperator == Operators.Div)
{
    if (secondOper == 0)
    {
        display.Text = "0으로 나눌 수 없습니다";
    }
    else
    {
        firstOper /= secondOper;
        display.Text = firstOper.ToString();
    }

}

 

 

오류처리

 - 각 기능별 예기치 못한 오류 발생 시, 오류를 확인하라는 메시지 박스로 안내 후, log 기록 및 저장

 - 각 기능을 try ~ catch를 통해서 오류 발생 시, 해당코드가 실행되도록 구성시간, 예외타입, 메시지, StackTrace 등을 통해 코드 상 어디부분에 에러가 발생하였는지 확인 로그로 가능

 

public void LogException(Exception ex)
{
    string logFileName = $"error_{DateTime.Now:yyyyMMdd}.log";
    string logFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, logFileName);

    try
    {
        if (!File.Exists(logFilePath))
        {
            using (StreamWriter newFileWriter = new StreamWriter(logFilePath, false))
            {
                newFileWriter.WriteLine($"[Error Log - {DateTime.Now}]");
            }
        }
        using (StreamWriter writer = new StreamWriter(logFilePath, true))
        {
            writer.WriteLine($"Exception Type: {ex.GetType().Name}");
            writer.WriteLine($"Message: {ex.Message}");
            writer.WriteLine($"StackTrace: {ex.StackTrace}");
            writer.WriteLine(new string('-', 50));
        }
        display.Text = $"Exception Error! {ex.Message}";
    }
    catch (Exception logEx)
    {
        display.Text = $"Exception Log record Error! {logEx.Message}";
    }
}