@interface AppController : NSObject { int prevOperation; /* 사용자가 이전에 클릭한 연산 값 */ int isClear; /* 연산을 클릭 후, 다시 값을 입력할 때 지원야 함을 알리는 플래그 */
int totalValue; /* 현재 계산 총 합 */
IBOutlet MyWindow *myWindow; /* 사용자 윈도우 */ IBOutlet NSTextField *txtValue; /* 현재/결과 값 표시 창 */ IBOutlet NSTextField *txtOperation; /* 현재 연산 모드 결과 표시 창 */ IBOutlet NSTextField *txtHistory; /* 연산 내역 표시 창 */ }
/* 키가 눌려질 경우, 자동으로 호출된다. */ - (void)keyDown:(NSEvent *)event { int keyCode; int val = -1;
/* 현재 눌려진 키값을 얻어 온다. */ keyCode = [event keyCode];
NSLog(@"KEY: %d", keyCode); /* 키값을 AppController에서 처리할 수 있도록 변경해 준다. 각각의 키값은 좌측 숫자키 보드에서 누른 키값들이며, 위의 NSLog에서 확인할 수 있다. */ if(keyCode >= 82 && keyCode <= 90) // 0~7 val = keyCode - 82; else if(keyCode ==91) // 8 val = 8; else if(keyCode ==92) // 9 val = 9; else if(keyCode == 67) // * val = BTN_MULTIPLE; else if(keyCode == 75) // / val = BTN_DIVISION; else if(keyCode == 69) // + val = BTN_PLUS; else if(keyCode == 78) // - val = BTN_MINUS; else if(keyCode == 71) // clear val = BTN_CLEAR; else if(keyCode == 81) // = val = BTN_RESULT; /* val이 세팅되어 처리해야 될 값일 경우에, AppController의 processInput에 값을 넘겨 준다. */ if(val != -1) [app processInput:val]; [self interpretKeyEvents:[NSArray arrayWithObject:event]]; } @end
3) AppController.m 소스파일 변경
#import "AppController.h" #import "MyWindow.h"
@implementation AppController /* awakeFromNib는 nib파일이 로드된 후, 오브젝트들에게 보내지는 메세지 입니다. 어플리케이션 실행 후, 각종 초기화 작업을 할 수 있습니다. */ - (void)awakeFromNib { isClear = 0; prevOperation = 0; totalValue = 0;
/* 연산자 (+, -, X, /, = )가 입력되었을 경우, 처리 합니다. */ - (void)processCalcul:(int)val { /* 이전에 설정된 연산자를 처리한다. */ if(prevOperation == BTN_PLUS) totalValue += [txtValue intValue]; else if(prevOperation == BTN_MINUS) totalValue -= [txtValue intValue]; else if(prevOperation == BTN_MULTIPLE) totalValue *= [txtValue intValue]; else if(prevOperation == BTN_DIVISION) totalValue /= [txtValue intValue]; /* 연산명령이 처음 수행되었을 경우에는, 결과값을 현재 입력된 값으로 설정 합니다. */ if([[txtHistory stringValue] length] < 1) totalValue = [txtValue intValue]; char operation; NSString *strTemp; /* 입력된 키에 따라 출력될 문자를 설정 합니다. */ if(val == BTN_PLUS) operation = '+'; else if(val == BTN_MINUS) operation = '-'; else if(val == BTN_MULTIPLE) operation = '*'; else if(val == BTN_DIVISION) operation = '/'; else operation = '='; /* 계산 History에 출력될 값으로 = 일 경우에는 결과값을 출력합니다. */ if(val == BTN_RESULT) strTemp = [[NSString alloc] initWithFormat:@"= %d\n", totalValue]; else strTemp = [[NSString alloc] initWithFormat:@"%c", operation]; /* clear 모드를 1로 설정해 이후 다시 숫자를 입력 하면, 이전 결과 값이 지워진 후, 새 입력값이 나올 수 있도록 합니다. prevOperation에 다음 연산 작업을 위해 입력된 연산값을 저장합니다. */ isClear = 1; prevOperation = val; /* 연산 창에 현재 연산모드를 출력합니다. */ [txtOperation setStringValue:[NSString stringWithFormat:@"%c", operation]];
/* 연산내역 창에 현재 연산 내역을 추가 합니다. */ [txtHistory setStringValue:[NSString stringWithFormat:@"%@ %@ %@", [txtHistory stringValue], [txtValue stringValue], strTemp]]; /* 결과 창에 현재까지 계산된 결과를 보여 줍니다. */ [txtValue setFloatValue:totalValue]; [strTemp release]; }
/* 버튼 클릭과 사용자의 키보드 입력을 처리 합니다. */ - (void)processInput:(int)val { NSString *strTemp; if(val >= 0 && val <= 9) { /* 숫자가 입력되었을 경우, 처리 합니다. */ if(isClear == 1) { /* 연산을 클릭하고, 처음 숫자가 입력되었을 경우 결과창을 초기화 합니다. */ [txtValue setStringValue:@""]; isClear = 0; }
/* 결과 창에 현재 입력된 값을 추가하여 출력 합니다. */ strTemp = [NSString stringWithFormat:@"%@%d", [txtValue stringValue], val]; [txtValue setStringValue:strTemp]; } else if(val == BTN_CLEAR) { /* clear 키를 입력하였을 경우, 데이터와 출력을 초기화 합니다. */ isClear = 0; prevOperation = 0; [txtValue setStringValue:@""]; [txtHistory setStringValue:@""]; [txtOperation setStringValue:@""]; } else if(val >= BTN_PLUS && val <= BTN_RESULT) { /* 연산이 입력되었을 경우에 현재 값이 있는지 확인 후 처리 합니다. */ if([[txtValue stringValue] length] > 0) [self processCalcul:val]; } }
/* 버튼이 클릭되었을 경우에, processInput에 알려 줍니다. */ - (IBAction) processCommand:(id)sender { /* 현재 선택(클릭)된 버튼의 tag값을 얻어 옵니다. */ int val = [[sender selectedCell] tag]; [self processInput:val]; } @end
이제 모든 작업이 완료되었습니다. 빌드하고 실행시켜 계산기 프로그램을 테스트 해 봅니다.
아직 처리하지 않는 부분이 많이 있습니다. 이 부분과 몇 가지 기능들을 다음 튜토리얼을 통해 계속 수정/추가해 나가겠습니다. 이번 장부터는 소스코드를 압축하여 올립니다. 참고하실 분은 다운 받아 압축을 풀고, Xcode에서 확인하시고, 이 소스코드에는 주석이 되어 있지 않습니다.
IBOutlet NSTextField *txtResult; IBOutlet NSTextField *txtValue; 위와 같이 계산된 결과값을 표시해 줄 txtResult와 사용자가 입력하는 숫자를 입력 받을 txtValue를 선언 합니다.
- (IBAction)plusClicked:(id)sender; - (IBAction)minusClicked:(id)sender; - (IBAction)muntiplyClicked:(id)sender; - (IBAction)devideClicked:(id)sender; 위와 같이 더하기/빼기/곱하기/나누기 연산을 처리 할 메소드를 선언합니다.
2) AppController.m 파일 변경
다음은 AppController.m 파일을 편집창에서 열어 아래와 같이 파란색 라인을 추가합니다.
나중에 인터페이스 빌더에서 만들어질 +, -, *, / 버튼이 클릭되었을 때, 행동을 지정합니다. 모두 같은 기능을 하니 plucClicked만 예를 들겠습니다.
float curResult = [txtResult floatValue]; 결과 창의 현재 값을 가지고 옵니다. 소수점을 지원하기 위해 float으로 선언합니다.
float curValue = [txtValue floatValue]; 현재 사용자가 입력한 값을 가지고 옵니다.
curResult += curValue; 사용자가 입력한 값을 현재 값에 더합니다. curResult = curResult + curValue; 과 같은 의미입니다. 더하기(+)와 마이너스(-)는 일반 사용하는 기호와 같지만 곱하기는 "*", 나누기는 "/"를 사용합니다.
[txtResult setFloatValue:curResult]; 계산된 값을 텍스트 필드에 저장 합니다. 이 명령으로 사용자는 최종 계산된 값을 볼 수 있습니다.
[txtValue setStringValue:@""]; 다음 입력을 위하여 현재 입력창의 내용을 지웁니다. 쌍따움표 앞에 @는 아스키 코드를 NSString 형태로 바꾸어 줍니다. @""로는 한글은 표현할 수 없습니다.
곱하기와 나누기에는 아래의 내용이 더 추가되어 있습니다. if(curValue == 0.0f) return; 사용자가 미입력시나 0을 입력하였을 경우, 0으로 곱하거나 나누어지는 것을 방지합니다.
3) Nib에 인스턴스 생성
이제 소스파일에서 변경된 사항을 저장하고 Xcode의 AppController.h를 마우스로 드래그 하여 인터페이스 빌더의 윈도우로 가져다 놓습니다. classes 윈도우에서 AppController를 우클릭 하여, Instantiate AppController를 클릭하여 아래와 같이 인스턴스를 생성합니다.
1.4.3 인터페이스 빌더에서 윈도우 생성 및 연결
1) 컨트롤 추가
윈도우를 틀릭하여 아래와 같이 컨트롤들을 추가하고 배치 합니다.
텍스트 필드 두개와 버튼 네개 (버튼은 하나를 가져 온 후, 복사/붙여 놓기로 사용하셔도 됩니다.)를 가져다 놓습니다. 상하 구분선은 팔레트의 두번째 Controls 항목에 있으며, 아래의 화살표를 참조 하여 마우스로 드래그 해 오시면 됩니다.
텍스트 필드는 숫자 형식으로 보여지기 위해, 아래의 우측에 보이는 팔레트에서 1.99$로 표시되어 있는 숫자형식을 지정하는 콘트롤을 드래그 해서 윈도우의 텍스트 필드에 가져다 놓습니다. 그 하단의 텍스트 필드에도 위와 같이 숫자형식 콘트롤을 드래그 해 놓습니다.
윈도우의 텍스트 필드를 클릭하고 [command + shift + i]를 클릭하여, 인스펙터를 오픈합니다. 숫자를 표현하기 위해 좌측 Attributes 항목에서 Alignment를 세번째 우측 정렬로 선택합니다. 위의 숫자형식 콘트롤을 추가하였기 때문에 오른쪽 이미지와 같이 마지막 속성에 Formmatter란 숫자형식을 지정할 수 있는 속성이 추가되었습니다. 첫번째 항목을 선택 합니다. 위의 작업 역시 하단의 텍스트 필드에도 똑같이 해줍니다.
가장 위의 결과창(모서리가 동그란 입력창)은 보여주기만 하므로 Options에서 Editable 클릭을 해제합니다.
2) AppCrontroller와 연결
이제는 AppConroller의 속성과 메소드를 연결합니다. AppController를 controll키와 함께 드래그하여 상단의 텍스트 필드와 txtResult 아울렛에 연결합니다. 마찬가지로 하단 왼쪽의 텍스트 필드와 txtValue와 연결합니다.
각각의 버튼들 controll키와 함께 AppController로 드래그 하여 + -> plusClicked, - -> minusClicked, * -> multiflyClicked, / -> devideClicked 로 연결(Connect)합니다.
위의 인터페이스 빌더의 일련의 작업들이 이해가 안가시는 분은 이전 포스트를 참조해 주세요.
1.4.4 테스트 및 추가사항 이제 모든 작업이 완료되었습니다. Build And Go를 클릭합니다. 빌드가 완료되면 아래와 같이 윈도우가 나타납니다. 좌측 아래 사각 입력창에 숫자를 입력하고 버튼들을 차례로 누르면서 결과값을 확인해 봅니다.
정말로 간단한 계산기가 완료 되었습니다. 다음번엔 여기에 기능들을 추가하고 조금은 어플리케이션 다운모습으로 만들어 볼려고 합니다.
저도 공부하면서 올리는 중이니 용어 사용이나, 구현에 있어 적절치 못한 부분이 많이 있을 것으로 생각됩니다. 지적과 조언은 언제나 감사하게 받아 들이겠습니다.