07 문자열 그리기와 키보드 이벤트 - 타자 애플리케이션 (1)
지난 글 - 06 커스텀 뷰와 이벤트 활용 - 간단 패인트 애플케이션 / 루비 코코아 프로그래밍
패인트 예제에 이어 타자 애플리케이션을 만들며 다양한 방법으로 커스텀 뷰를 발전시킨다. 이번 예제에서는 키보드 입력을 받고 문자열을 출력한다. 코코아 프로그래밍 16장 ~ 19장에서 설명하고 있는 예제를 루비 코코아로 옮긴 것이다.
Responder
드디어 인터페이스 빌더에 있던 묘한 아이콘의 정체를 알 수 있었다.
윈도우마다 firstResponder라는 아웃렛을 갖고 있으며, 이 아웃렛은 현재 활성화된, 즉 키보드 이벤트를 주로 받을 뷰를 지칭하고 있다. firstResponder가 되기전에는 아래 메시지들을 차례로 전달 받는다.
- acceptsFirstResponder
- resignFirstResponder
- becomeFirstResponder
그리고 인터페이스 빌더에서 특유의 방식(컨트롤 + 드래그)를 통해 다음 리스폰더를 지정하는 모습은 흥미로웠다. 그렇게 리소폰더 체인이 연결되는 모습이 눈에 보였다. 기존에는 Tabstop을 정해주고 각 stop의 우선순위를 정하는 방식으로 개발을 해봤었는데, 장단점이 있는 것 같다. 그리고 타겟이 nil로 정해졌을 때 리스폰더 체인을 따라가면 메시지가 전달되는 모습도 흥미로웠다.
그 외의 구현은 크게 어렵지 않았다.
문자열 그리기
NSAttributedString을 이용하면 범위와 속성으로 문자열을 쉽게 그릴 수 있다. 여기서 설정할 수 있는 속성은 폰트명, 바탕색, 배경색, 밑줄 여부, 밑줄색, 첨자, 그림자 등이다. 그 외에도 RTF나 HTML, WORD등의 파일로부터도 쉽게 속성이 있는 문자열을 얻어올 수 있다. 아래는 타자 애플리케이션에 사용한 루틴이다. BigLetterView의 중앙에 75포인트로 한 글자를 출력한다.
- def attributes
@attributes ||= {
OSX::NSFontAttributeName => OSX::NSFont.fontWithName_size('Helvetica', 75),
OSX::NSForegroundColorAttributeName => OSX::NSColor.redColor }
end
def draw_string_centered_in(rect)
size = @string.sizeWithAttributes(attributes)
origin = OSX::NSPoint.new
origin.x = rect.origin.x + (rect.size.width - size.width) / 2
origin.y = rect.origin.y + (rect.size.height - size.height) / 2
@string.drawAtPoint_withAttributes(origin, attributes)
end
결과는 아래와 같다.
PDF로 저장
코코아 프레임워크의 PDF 지원이 좋다는 이야기는 많이 들었지만, 이 정도인줄은 몰랐다. 정말 간단하게 PDF 문서를 생성할 수 있었다. 단, 두줄이면 충분했다.
- data = dataWithPDFInsideRect(bounds)
data.writeToFile_atomically(sheet.filename, true)
아래는 이러게 만들어진 PDF 문서다.
Pasteboard
Pasteboard는 윈도의 클립보드와 같은 역할을 하는 서버 프로세스(/System/Library/CoreServices/pbs)다. 이를 이용해 잘라내기, 복사하기, 붙여넣기를 추가할 수 있다.
- def write_string_to_pasteboard(pb)
pb.declareTypes_owner(OSX::NSArray.arrayWithObject(OSX::NSStringPboardType), self)
pb.setString_forType(@string, OSX::NSStringPboardType)
end
def read_string_from_pasteboard(pb)
return false unless pb.availableTypeFromArray(OSX::NSArray.arrayWithObject(OSX::NSStringPboardType))
value = pb.stringForType(OSX::NSStringPboardType)
return false unless value.length == 1
self.string = value
end
Objective-C의 클래스도 열려있다
전에 Numeric#bytes - 열린 클래스와 DSL라는 글을 쓴적이 있다. 루비의 클래스는 열려있어서, 언제든 기존 클래스에 새로운 기능을 추가할 수 있다. 이는 간결한 코딩을 가능케하고, 루비가 확장성있는 언어가 되는데 기틀이 되었다. 그런데 놀랍게도 Obiective-C의 클래스도 열려있었다. 19장에보면 NSString 클래스에 firstLetter라는 메서드를 구현하는 예가 나온다. 여기서는 카테고리라고 부르는 것 같다. 카테고리는 마치 모듈을 만들어 기존 클래스에 믹스인하는 것과 유사해보인다.
Objective-C는 상당히 재미있는 언어인 것 같다.
마치며
지금까지 구현한 내용의 전체 소스 코드는 아래 링크에서 내려받을 수 있다.
다음에는 이 예제에 드래그-앤-드랍을 구현해볼 것이다. 어떤 플랫폼이건 드래그-앤-드랍은 귀찮음의 대명사다. 코코아도 별반 다르지 않을 것 같다. 다음 글은 08 드래그-앤-드롭과 타이머 - 타자 애플리케이션 (2)이다(전체보기 - 루비 코코아 프로그래밍).
Comments (0)