사용자 삽입 이미지
흔히 사용되는 컨트롤들의 간단한 사용법을 알아 보겠습니다.
만들려는 예제의 모습은 좌측과 같습니다. 각 컨트롤들의 설정에 따라서 상단 텍스트 필드의 내용을 변경하여 보여주는 샘플을 작성해 보겠습니다.

이 예제를 따라 해보기 위해서는 인터페이스 빌더의 사용법과  인스턴스 생성, 인스턴스와의 연결 등에 관한 기본 내용을 알고 있어야 합니다. 잘 이해가지 않는 분들은 이전 포스트를 확인해 보신 후에 다시 보시기 바랍니다.



1. AppController 생성

XCode에서 Cocoa Application으로 새로운 프로젝트를 생성합니다. 다시 New File에서 Objective-C Class를 선택한 후에 AppController란 이름으로 새로운 클래스를 생성합니다.

1) AppController.h 변경
이번 장에서 사용할 컨트롤들은 아래와 같습니다. 아래의 컨트롤들을 인터페이스 빌더에서 연결하기 위해 IBOutlet 변수들을 생성합니다.
NSTextField, NSTableView, NSMatrix, NSComboBox, NSColorWell, NSSlider, NSButton, NSProgressIndicator  

사용자의 조작으로 컨트롤의 상태가 변하는 알림 메시지를 받을 메소드를 생성합니다. 각 메소드는 아래와 같습니다.

- (IBAction)setDisplayText:(id)sender;
- (IBAction)adverbSelecterChanged:(id)sender;
- (IBAction)alignSliderChanged:(id)sender;
- (IBAction)notCheckerChanged:(id)sender;
- (IBAction)subjectMatrixChanged:(id)sender;
- (IBAction)colorWellChanged:(id)sender;

AppController.h
#import <Cocoa/Cocoa.h>

@interface AppController : NSObject {
    IBOutlet NSTextField* displayString;
    IBOutlet NSTableView* wordList;
    IBOutlet NSMatrix* subjectMatrix;
    IBOutlet NSComboBox* adverbSelecter;
    IBOutlet NSColorWell* colorWell;
    IBOutlet NSSlider* alignSlider;
    IBOutlet NSButton* notChecker;
    IBOutlet NSProgressIndicator* progressBar;   
}

- (int)numberOfRowsInTableView:(NSTableView *)tableView;
- (id)tableView:(NSTableView *)tableView
    objectValueForTableColumn:(NSTableColumn *)tableColumn
            row:(int)row;

- (IBAction)setDisplayText:(id)sender;
- (IBAction)adverbSelecterChanged:(id)sender;
- (IBAction)alignSliderChanged:(id)sender;
- (IBAction)notCheckerChanged:(id)sender;
- (IBAction)subjectMatrixChanged:(id)sender;
- (IBAction)colorWellChanged:(id)sender;

@end


2) AppController.m 변경

사용자 삽입 이미지
TableView는 좌측과 같이 테이블 형식으로 목록을 보여주는 컨트롤입니다. 각 셀에 데이터를 입력하기 위해서는 데이터를 등록하여 주는 dataSource를 지정해야 합니다.

여기서는  나중에 인터페이스 빌더에서 AppController를 dataSource로 등록하겠습니다. tableView의 dataSource가 되면 데이터를 요구하는 메시지에 응답하기 위해서 아래와 같은 두개의 메소드를 구현해야 합니다.

- (int)numberOfRowsInTableView:(NStableView *)tableView;
목록의 갯수를 반환합니다.

- (id)tableView:(NSTableView *)tableView
    objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row

각 셀의 데이터를 반환합니다. 이 반환된 값들로 각 셀들이 채워집니다. 셀에 데이터를 등록하는 것은 다음 포스팅에서 구현해 보겠습니다.

메시지를 처리하는 각 메소드들은 실제 기능을 구현하기 전에 정확히 동작하는지 확인하기 위해서 NSLog를 추가합니다. 소스파일 전체는 아래와 같습니다.

AppController.m
#import "AppController.h"

@implementation AppController

- (void)awakeFromNib
{
}

- (void)dealloc
{
    [super dealloc];
}

- (IBAction)setDisplayText:(id)sender
{
    NSLog(@"Button colicked");
}

- (IBAction)adverbSelecterChanged:(id)sender
{
    NSLog(@"adverbSelecter changed");
}

- (IBAction)alignSliderChanged:(id)sender
{
    NSLog(@"alignSlider Changed");
}

- (IBAction)notCheckerChanged:(id)sender
{
    NSLog(@"notChecker changed");
}

- (IBAction)subjectMatrixChanged:(id)sender
{
    NSLog(@"subject matix");
}

- (IBAction)colorWellChanged:(id)sender
{
    NSLog(@"colorWell changed");
}

- (int)numberOfRowsInTableView:(NSTableView *)tableView
{
    NSLog(@"tableView getRowCount");
    return 1;
}

- (id)tableView:(NSTableView *)tableView
    objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row
{
    NSLog(@"tableView getColumnValue");
    return nil;
}

@end


2. 인터페이스 빌더에서 작업
 
1) 컨트롤 배치

윈도우에 각 컨트롤들이 배치되어야 할 모습은 아래와 같습니다.

사용자 삽입 이미지

사용자 삽입 이미지
팔레트에서 마우스 포인터를 해당 컨트롤 위에 놓으면 좌측의 빨간 화살표가 가르키는 것과 같이 컨트롤의 종류를 확인할 수 있습니다.

위의 이미지를 참조하여 팔레트에서 각각의 콘트롤들을 드래그로 가지고 와서 배치 합니다.





2) 속성 설정
각각의 콘트롤들의 속성을 변경합니다.

NSTextField
사용자 삽입 이미지
텍스트필드의 옵션을 좌측과 같이 설정합니다. 사용자의 입력은 받지 않기 때문에 Editable, Enabled를 해제합니다.


NSTableView
사용자 삽입 이미지
Attributes에서 Columns를 2로 설정합니다.
NSTableView를 더블클릭하면 좌측과 같이 푸른 테두리가  나타납니다. 이 상태에서 컬럼을 더블클릭하여 입력 모드로 변경되면 이름을 변경할 수 있습니다.

각각 목적어, 동사로 변경합니다.

NSMatrix
Rows는 1 Cols는 2로 설정하고 Mode가 'Radio'로 되어 있음을 확인합니다.

NSComboBox
사용자 삽입 이미지
좌측과 같이 Visible Items를 4로 입력하고 4개의 항목을 추가합니다.

추가는 하단의 입력필드에서 이름을 입력 후에 [+] 버튼을 클릭합니다. 삭제는 아이템을 선택한 후에 [-]버튼을 클릭합니다.



NSColorWell
변경없이 기본값을 유지합니다.

NSSlider
사용자 삽입 이미지
좌측과 같이 최소값을 0.0, 최대값을 100.0, 기본값을 50.0으로 설정합니다. 세단계만 선택되게 하기 위해 Number Of Markers를 3으로  Stop on ticks marks only를 체크 합니다.


NSButton
Type이  'CheckBox'로 되어 있음을 확인하고 Title에 '부정어로 만듭니다.'로 입력합니다.

NSProgressIndicator  
MinumRange는 0.0, MaximumRange는 100.0으로 설정하고 Indeterminate를 체크 합니다.

2) AppControll 인스턴스 생성
AppController.h를 인터페이스 빌더의 MainMenu.nib 윈도우로 드래그 해 놓습니다. Classes 항목에서 AppController를 우클릭하여 Instantiate AppController를 선택하여 인스턴스를 생성합니다.

이제 아래의 연결된 모습을 참조하여 윈도우의 각 항목들을 AppController의 IBOutlet 변수와 IBAction 메소드로 연결합니다.
사용자 삽입 이미지

각 컨트롤들은 아래의 AppController의 IBAction 메소드와 연결됩니다.
  • adverbSelecterChanged <- NSComboBox
  • alignSliderChanged <- NSSlider
  • notCheckerChanged <-NSButton (Check Box)
  • subjectMatrixChanged <- NSMatrix
  • colorWellChanged <- NSColorWell
  • setDisplayText <- NSButton (적용 Button)
 
사용자 삽입 이미지
마지막으로 위에 설명한 대로 좌측과 같이  TableView의 dataSource를 AppControll로 설정합니다.








이제 컴파일 하고 실행한 후에 각각의 콘트롤의 값과 상태를 변경하여 봅니다. 그리고 RunLog 창에서 아래와 같이 메시지를 보내고 받는지 확인합니다.

잘 동작하지 않는 분들은 아래의 샘플 파일을 다운로드 받으신 후에 비교해 보시기 바랍니다.
사용자 삽입 이미지

AND

flex2로 만든 Tree로 메뉴를 보여주는 샘플 입니다. xml에서 데이터를 읽어 오기 때문에 메뉴 이름이나 URL이 변경되더라도 다시 컴파일할 필요가 없습니다. 그리고 제목을 클릭해도 오픈/클로즈가 가능하고 링크가 있을 시에는 해당 링크가 오픈됩니다.


lmenu.mxml (flex2 소스 파일)
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
    creationComplete="initData()" width="180" height="200" fontSize="11">
    <mx:Script>
        <![CDATA[
            import mx.rpc.events.FaultEvent;
            import mx.rpc.events.ResultEvent;
            import flash.net.navigateToURL;

            /* murl 파라미터에서 설정된 url로 부터 xml 데이터를 가져 온다. */
            private function initData():void {
                xmlService.url = Application.application.parameters.murl;
                xmlService.send();
            }
           
            /* xml 가져오기 오류 시 메시지 출력 */
            private function faultHandler(event:FaultEvent):void {
                mx.controls.Alert.show(event.fault.message);
            }
           
            /* Tree 마우스 클릭 이벤트 처리 */
            private function onItemClicked(event:Event):void {
                if(event.currentTarget.selectedItem.@data) {
                   
                    /* 현재 선택된 아이템의 데이터 값을 가져 온다. */
                    var dataString:String = "";
                    dataString = event.currentTarget.selectedItem.@data;
                   
                    /* data(link)가 있을 시에는 url을 연다 */
                    if(dataString.length > 0)
                    {
                        var url:URLRequest = new URLRequest(dataString);
                        navigateToURL(url);
                    }   

                    /* 아이템이 열려 있으면 닫고, 닫혀있으면 연다 */
                    var openFlag = !(menuTree.isItemOpen(event.currentTarget.selectedItem) == true);
                    menuTree.expandItem(event.currentTarget.selectedItem, openFlag);   
                }
            }
        ]]>
    </mx:Script>

    <mx:HTTPService id="xmlService" resultFormat="e4x" fault="faultHandler(event)" useProxy="false" />
    <mx:XMLListCollection id="xc" source="{xmlService.lastResult.item}" />

    <mx:Tree id="menuTree" labelField="@label" showRoot="true"
        x="0" y="0" width="180" height="200"
        dataProvider="{xc}" click="onItemClicked(event);" />
</mx:Application>
현재 창에서 링크가 열리기를 원하시면 navigateToURL(url)을 navigateToURL(url, "_self")로 변경합니다.

test.html (html 샘플 파일)
<html lang="ko">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Flex Menu Test</title>
<script type="text/javascript">
function goURL(url)
{
    document.location.href = url;
}
</script>
</head>
<body>
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
            id="flexMenu" width="500" height="400"
            codebase= "http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
<param name="movie" value="[swf url]?murl=[xml url]" />
<param name="quality" value="high" />
<embed src="[swf url]?murl=[xml url]" quality="high" bgcolor="#efefef"
                width="500" height="400" name="flex" align="middle"
                play="true"
                loop="false"
                quality="high"
                type="application/x-shockwave-flash"
                pluginspage="http://www.adobe.com/go/getflashplayer">
            </embed>
    </object>
</body>
</html>
murl로 xml 파일의 url을 전달합니다.

[swf url] 컴파일된 swf 파일의 url입니다.
[xml url] 메뉴 구조가 정의된 xml의 url입니다. 구조는 아래와 같습니다.

src와 movie에서의 내용을http://www.domain1.com/lmenu.swf?murl=http://www.domain2.com/menu.xml 과 같이 입력하시면 됩니다.

menu.xml (메뉴 구조 샘플 파일)
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <item label="포탈 사이트">
        <item label="네이버" data="http://www.naver.com"/>
        <item label="다음" data="http://www.daum.net"/>
        <item label="야후" data="http://www.yahoo.co.kr"/>
        <item label="엠파스" data="http://www.empas.com"/>
    </item>
    <item label="블로그">
        <item label="내 블로그" data="http://www.cocoadev.co.kr"/>
        <item label="올블로그" data="http://www.allblog.net"/>
        <item label="티스토리" data="http://www.tisotry.com"/>
    </item>
</root>
서브 메뉴를 포함하고 있을 때는 "<item>[.. sub item]</item>"과 같이 포함하지 않으면 "<item />"과 같이 사용하시면 됩니다. 링크가 필요한 경우에는 item의 data 필드를 이용합니다.

crossdomain.xml
<?xml version="1.0"?>
<cross-domain-policy>
    <allow-access-from domain="*"/>
</cross-domain-policy>

swf가 있는 도메인과 xml이 있는 도메인이 다를 경우에는 xml이 있는 곳에 위와 같은 crossdomain.xml 파일이 존재하여야 합니다.
AND

사용자 삽입 이미지
이번 장에서는 키보드의 입력에 따라 움직이는 우주선을 만들어 보겠습니다. 그리고 우주선의 불꽃 부분이 움직이는 에니메이션 효과와 우주선의 움직임에 따라 선을 그리도록 추가해 보겠습니다.

1. 에니메이션

1) 스프라이트 추가

사용자 삽입 이미지
먼저 우주선 스프라이트를 추가해 보겠습니다. 우선 스크래치를 실행하고, 좌측과 같이 스프라이트의 메뉴에서 Costumes를 선택합니다.

페인트 에디터를 이용하여 직접 그릴 경우에는 [Paint] 버튼을 클릭하고 기존의 이미지에서 불러 올 경우에는 [Import] 버튼을 클릭합니다. 아래의 압축 파일을 다운로드 받으시면 이 예제에서 사용한 2개의 우주선 이미지를 사용할 수 있습니다.

 
사용자 삽입 이미지
기존의 사용하지 않는 costume들은 삭제합니다. 각 이미지 우측 하단의 [X] 버튼을 클릭하여 삭제합니다.


2) 기준점 설정
사용자 삽입 이미지
기존 커스텀은 삭제되고 좌측과 같이 불꽃 모양이 다른 우주선 커스툼 두개가 등록되어 있습니다.

만약 페인트 에디터를 사용하여 직접 그리거나 다른 이미지를 불러 왔다면, 이름을 더블클릭하여 좌측과 같이 커스툼 이름을 변경하여 줍니다.

좌측을 보시면 39X39와 36X39로 두개의 이미지 크기가 다릅니다. 이는 번갈아 보여주는 에니메이션시 두개의 우주선의 위치가 바뀌어 보일 수 있습니다.

사용자 삽입 이미지
좌측과 같이 똑 같은 위치에 우주선을 보여 주면 너비가 다르기 때문에 위치가 변경되어 우주선이 흔들리는 것처럼 보여 집니다.

이와 같이 크기가 틀린 커스툼들을 보여줄 경우에는 위치를 보정하기 위해 기준점을 설정합니다. 기준점은 페인트 에디터에서 설정할 수 있습니다. 커스텀 영역내에 있는 [Edit] 버튼을 클릭하여 페인트 에디터를 실행합니다.
 

사용자 삽입 이미지
기준점 설정을 위하여 페인트 에디터의 좌측하단에 있는 [Set rotation center] 버튼을 클릭합니다.

사용자 삽입 이미지
좌측과 같이 기준점을 비행기 중앙의 원의 중심에 일치하도록 설정합니다. 두번째 그림(ship2)도 이와 동일하게 적용합니다.

이제 크기가 다른 이미지가 번갈아 가며 보여지더라도 정확한 위치에서 흔들림 없이 불꽃의 길이만 변경됩니다.


3) 스크립트
사용자 삽입 이미지
에니메이션을 위해 좌측과 같이 블럭을 스크립트 영역에 배열합니다.

[When flag Clicked] 사용자가 시작 버튼을 클릭하면 연결된  명령들이 실행됩니다.

[point in direction [0]] 우주선의 초기 방향을 위로 향하도록 합니다. 방향에 대한 설명은 아래에서 다시 하겠습니다.

[forever] forever내의 명령들은 프로젝트가 실행되는 동안 무한으로 반복되어 실행됩니다.
    [switch to costume [sihp]] 모양을 ship 커스툼으로 변경합니다.
    [wait [0.1] secs] ship 커스텀 모양을 0.1초 유지하도록 합니다.
    [switch to costume [sihp2]] 모양을 ship2 커스툼으로 변경합니다.

이제 깃발 버튼을 클릭하여 프로젝트를 실행 하고 에니메이션이 되는지 확인합니다.

2. 이동
사용자 삽입 이미지
방향키가 클릭되었을 때 이미지를 선택된 방향으로 회전하고 이동하도록 하여 줍니다. 좌측과 같이 각각의 블럭들을 배치합니다.

[when [up arrow] key pressd]
위 방향키가 클릭되었을 때 연결된 블럭들이 실행됩니다.

[change y by [10]]
현재 y 좌표에 10을 더합니다. y의 수가 클수록 위로 이동합니다.

[point in direction [0]]
주어진 각도로 이미지를 회전합니다. 이미지 회전 위치는 아래와 같습니다.

다른 방향키도 위와 같은 방법으로 설정된 방향으로 방향을 바꾸고 이동하도록 되어 있습니다.



사용자 삽입 이미지
[point in direction [값]] 블럭은 값에 따라서 좌측의 이미지와 같은 방향으로 커스툼을 회전합니다. 방향에 따른 각각의 값들은 아래와 같습니다.

위: 0
아래:180
좌측:-90
우측:90


3. 선 그리기
사용자 삽입 이미지
이제 마지막으로 우주선이 움직이는 경로에 선이 그려지도록 하겠습니다. 이와 관계된 블럭들은 [pen] 분류에 있습니다.

사용자 삽입 이미지
좌측과 같이 기존의 [when flag clicked]에 펜에 관련된 초록색 블럭들을 세개 추가합니다.

[clear] 펜으로 그려진 선들을 모두 지웁니다.

[pen down] 해당 스프라이트가 이동 시에 현재 스프라이트 위치에 선을 그리도록 설정합니다.
 
[set pen size to [5]] 선 굵기로 5로 설정합니다.





이제 실행하여 보면 아래와 같이 우주선의 이동경로를 따라 지정된 선이 그려지는 것을 확인할 수 있습니다.
사용자 삽입 이미지
웹에서 실행되는 모습과 프로젝트 파일 다운로드는 스크레치 사이트의 제 프로젝트에서 확인하실 수 있습니다.
AND