일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 패널 교체
- Python
- 싱글 스레드
- node.js
- 코틀린
- 노트북 추천
- Kotlin
- 함수
- ListView
- var
- golang
- adapter
- 안드로이드
- 리스트 뷰
- 자바
- javascript
- Array
- 오버로딩
- blockchain
- Java
- Overloading
- 파이썬
- HP
- 노트북
- 연산자
- 자바스크립트
- Android
- go
- 배열
- js
- Today
- Total
Bbaktaeho
[Android] 계산기 앱 만들기 (안드로이드, 계산기 애플리케이션, 후위 표기법, Calculator, infix, postfix) 본문
[Android] 계산기 앱 만들기 (안드로이드, 계산기 애플리케이션, 후위 표기법, Calculator, infix, postfix)
Bbaktaeho 2020. 9. 14. 18:272020-09-14 수정 : (우리가 일상에서 이용하는 수식은 중위 표기법입니다)
들어가며
자바 언어를 검색을 통해서 익히다 보니 어떤 util이 더 좋은지 아직 감이 안 잡혔고 메서드를 만들어 사용하는 것도 많이 부족합니다.
때문에 자바 언어가 많이 미숙해서 코드가 좋지 못한 점 양해 부탁드립니다.
제가 구현한 코드는 답이 아닙니다. 참고로만 봐주시면 감사하겠습니다.
이번에 만들어볼 계산기는 윈도우 계산기입니다.


간단한 연산만 할 수 있도록 구현하겠습니다.
참고로 계산기를 구현하는 것은 쉬운 일이 아닙니다. 저 역시 구현하면서 논리적인 생각, 자료구조를 떠올리며 많은 노력을 쏟았습니다.
프로젝트 생성
[Android] 자기소개 앱 만들기 (안드로이드 기초, Splash)
새로운 프로젝트 생성하는 방법은 아래 포스팅에서 확인해주세요. [개발(develop)/안드로이드(android)] - [Android] Click 이벤트로 Toast 생성하기 (setOnclickListener, makeToast) 들어가며 동작하는 기능 없..
bbaktaeho-95.tistory.com
위의 포스팅에서 프로젝트 생성과 Splash 구현까지 그대로 따라 하면 됩니다.
res/values/colors.xml
프로젝트에서 사용할 색상을 먼저 작성합니다.
<color name="colorBlack">#000000</color>
<color name="colorWhite">#FFFFFF</color>
<color name="colorMyGray">#E6E6E6</color>
검은색, 흰색, 회색을 추가했습니다.
res/values/styles.xml
화면에 보일 스타일을 따로 작성했습니다.
메인 파일에서 추가하지 않고 어떻게 해야 스타일을 적용시킬 수 있을까 찾아보다가 styles.xml 에서 원하는 스타일을 작성하면 layout들의 스타일, 테마까지 쉽게 적용시킬 수 있었습니다.
<style name="SplashTheme" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowBackground">@color/colorWhite</item>
</style>
<style name="MainTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:windowBackground">@color/colorMyGray</item>
</style>
Splash 화면, Main 화면에 적용시킬 스타일만 작성했습니다.
res/layout/activity_main.xml
이제 UI를 만들어보겠습니다.
가장 먼저 루트 레이아웃으로 LinearLayout을 선택했고 그 안에 RelativeLayout, TableLayout 으로 구현했습니다.

각 TableRow에 버튼을 균형적으로 배치할 수 있도록 TableLayout의 속성 값으로 android:stretchColumns="*" 옵션을 추가했습니다.

<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<Button
android:id="@+id/btn_mod"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:backgroundTint="#3EBAB4B4"
android:onClick="buttonClick"
android:text="%"
android:textSize="18sp" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:backgroundTint="#3EBAB4B4"
android:clickable="false"
android:enabled="false"
android:text="CE"
android:textSize="18sp" />
<Button
android:id="@+id/btn_clear"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:backgroundTint="#3EBAB4B4"
android:onClick="clearClick"
android:text="C"
android:textSize="18sp" />
<Button
android:id="@+id/btn_delete"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:backgroundTint="#3EBAB4B4"
android:text="Del"
android:onClick="deleteClick"
android:textSize="18sp" />
</TableRow>
하나의 TableRow에 들어있는 Button들입니다.
여기서 버튼에 onClick 속성이 있는데 자바, 코틀린 코드에서 리스너 메서드를 구현하지 않아도 각 뷰 컴포넌트들에게 직접적으로 메서드를 연결할 수 있었습니다.
이러한 방법을 추천하지 않는다고 하지만 단순히 어떤 버튼이 클릭되었는지만 아는 기능뿐이고 메인 코드가 줄어드는 장점이 있기 때문에 적용했습니다.

다음은 수식과 결과가 나오는 TextView입니다.
여기는 RelativeLayout을 이용해서 구현했습니다.
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="171dp">
<TextView
android:id="@+id/txt_expression"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginTop="44dp"
android:layout_marginRight="20dp"
android:hint="expression"
android:textSize="18sp" />
<TextView
android:id="@+id/txt_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/txt_expression"
android:layout_alignRight="@+id/txt_expression"
android:layout_marginTop="25dp"
android:hint="result"
android:textColor="@color/colorBlack"
android:textSize="36sp"
android:textStyle="bold" />
</RelativeLayout>
MainActivity.java
앞서 말씀드렸던 onClick 속성을 적용하려면 View 타입의 매개변수가 있는 메서드를 선언해야 합니다.
public void buttonClick(View v) {...}
특히 public 제어자로 선언하지 않으면 사용할 수 없습니다. (엄청 삽질함)
자꾸 새로 만들라는 경고 메시지만 나옵니다.
다음은 MainActivity 클래스의 필드입니다.
private TextView txtExpression;
private TextView txtResult;
private List<Integer> checkList; // -1: 이콜, 0: 연산자, 1: 숫자, 2: . / 예외 발생을 막는 리스트
private Stack<String> operatorStack; // 연산자를 위한 스택
private List<String> infixList; // 중위 표기
private List<String> postfixList; // 후위 표기
TextView들은 수식과 계산 결과 UI입니다.
나머지 스택과 리스트는 계산, 예외 처리를 하기 위한 필드입니다.
다음으로 전체 MainActivity 클래스의 메서드들입니다.

예외나 추가적인 기능을 처리하느라 메서드가 많아지고 서로 연관성이 좀 생겼습니다..
전체 코드는 깃허브 링크로 공유하겠습니다. 포스팅에서 몇 가지 메서드들만 다뤄보겠습니다.
init()
// 필드 초기화
void init() {
txtExpression = findViewById(R.id.txt_expression);
txtResult = findViewById(R.id.txt_result);
checkList = new ArrayList<>();
operatorStack = new Stack<>();
infixList = new ArrayList<>();
postfixList = new ArrayList<>();
ActionBar actionBar = getSupportActionBar();
assert actionBar != null;
actionBar.hide();
}
필드들을 초기화하고 ActionBar를 숨김 처리합니다.
getWeight(String)
// 연산자 가중치 (우선순위 *,/,%,+,-)
int getWeight(String operator) {
int weight = 0;
switch (operator) {
case "X":
case "/":
weight = 5;
break;
case "%":
weight = 3;
break;
case "+":
case "-":
weight = 1;
break;
}
return weight;
}
연산자의 우선순위에 따라 가중치를 부여하는 메서드입니다.
후위 표기법으로 나타낼 때 가장 중요한 역할을 합니다.
infixToPostfix()
// 전위 -> 후위
void infixToPostfix() {
for (String item : infixList) {
// 피연산자
if (isNumber(item)) postfixList.add(String.valueOf(Double.parseDouble(item)));
// 연산자
else {
if (operatorStack.isEmpty()) operatorStack.push(item);
else {
if (getWeight(operatorStack.peek()) >= getWeight(item)) postfixList.add(operatorStack.pop());
operatorStack.push(item);
}
}
}
while (!operatorStack.isEmpty()) postfixList.add(operatorStack.pop());
}
중위 표기법을 후위 표기법으로 변환하는 메서드입니다.
미리 저장했던 infixList(중위 표기법)에서 operatorStack을 이용해 연산자 우선순위에 따라 postfixList(후위 표기법)에 추가합니다.

calculate()
// 계산
String calculate(String num1, String num2, String op) {
double first = Double.parseDouble(num1);
double second = Double.parseDouble(num2);
double result = 0.0;
try {
switch (op) {
case "X": result = first * second;break;
case "/": result = first / second;break;
case "%": result = first % second;break;
case "+": result = first + second;break;
case "-": result = first - second;break;
}
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "연산할 수 없습니다.", Toast.LENGTH_SHORT).show();
}
return String.valueOf(result);
}
실질적인 계산을 하는 메서드입니다.
결과 값을 문자열로 변환하고 리턴해줍니다.
실행
동영상은 팝업창 또는 전체 화면으로 봐주세요.
GitHub
bbaktaeho/all-my-studies
👨🏫 배움은 끝이 없다고 합니다.. Contribute to bbaktaeho/all-my-studies development by creating an account on GitHub.
github.com
참고 자료
안드로이드 렐러티브레이아웃. (Android RelativeLayout)
1. 안드로이드 RelativeLayout 클래스. [안드로이드 리니어레이아웃. (Android LinearLayout)]에서 설명한 LinearLayout 을 사용하여 UI 레이아웃을 구성하다보면, 원하는 배치 구조를 만들기가 쉽지 않은 경우��
recipes4dev.tistory.com
wayhome25.github.io/cs/2017/04/18/cs-22/
강의노트 21. 자료구조 - stack을 이용한 후위표기법 계산기 만들기 · 초보몽키의 개발공부로그
패스트캠퍼스 컴퓨터공학 입문 수업을 듣고 중요한 내용을 정리했습니다. 개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.
wayhome25.github.io
버튼 클릭 이벤트를 처리하는 몇 가지 방법. (Android Button Click Event)
1. Button의 클릭 이벤트 처리 안드로이드에서 Button 클릭 이벤트를 처리하기 위해서는 리스너(listener)의 개념과 구현 방식을 이해하고 있어야 합니다. 만약 리스너에 대한 내용을 처음 접하신다면,
recipes4dev.tistory.com
'개발 (Develop) > 안드로이드 (Android)' 카테고리의 다른 글
[Android] ListView 사용하기 (안드로이드, 리스트뷰, Adapter) (0) | 2020.09.20 |
---|---|
[Android] AlertDialog 사용하기 (안드로이드, 경고창, 팝업창) (0) | 2020.09.20 |
[Android] 액티비티 생명 주기 (Activity Lifecycle) (0) | 2020.09.13 |
[Android] Intent 다뤄보기 (startActivity, getIntent, putExtra, getExtra) (1) | 2020.09.12 |
[Android] 기본적인 View 요소들과 역할 (0) | 2020.09.06 |