CafeM0ca

[JUCE]튜토리얼6 Advanced GUI layout techniques 본문

Programming/JUCE

[JUCE]튜토리얼6 Advanced GUI layout techniques

M0ca 2018. 2. 17. 03:54
반응형

//발번역 https://docs.juce.com/master/tutorial_rectangle_advanced.html

tutorial_rectangle_advanced.zip


데모 프로젝트는 적은 수의 버튼 컴포넌트를 사용하여 상위 컴포넌트에 배치한다. 이 예제에서 placeholders로 버튼을 사용하고 있다. JUCE의 어트 타입의 컴포넌트도 된다. 빌드하고 실행해보면 다음과 같다.




직사각형 레이아웃 // 레이아웃은 겹 또는 층이라 이해하면 된다.

이 간단한 응용프로그램에서 메인윈도우의 몇 가지 영역이 있다.

-header 구역에 타이틀이나 툴바

-footer 구역에 어플리케이션의 정보

-Sidebar에 섹션의 종류또는 컴포넌트

-몇가지 컴포넌트 항목이 창의 나머지 부분


아래 코드들은 MainContentComponent 생성자에 추가되어있다.


MainContentComponent()
{
header.setButtonText ("Header");
addAndMakeVisible (header);
footer.setButtonText ("Footer");
addAndMakeVisible (footer);
sidebar.setButtonText ("Sidebar");
addAndMakeVisible (sidebar);
limeContent.setColour (TextButton::buttonColourId, Colours::lime);
addAndMakeVisible (limeContent);
grapefruitContent.setColour (TextButton::buttonColourId, Colours::yellowgreen);
addAndMakeVisible (grapefruitContent);
lemonContent.setColour (TextButton::buttonColourId, Colours::yellow);
addAndMakeVisible (lemonContent);
orangeContent.setColour (TextButton::buttonColourId, Colours::orange);
addAndMakeVisible (orangeContent);
setSize (400, 400);
}

실제 배치는 일반적으로 Component::resized() 함수에 의해 된다.


전통적인 레이아웃

전통적으로, 컴포넌트를 변수의 위치와 크기를 계산하여 배치하고 항상 계산의 합이 옳은지 주의해야한다. 심지어 window 주요 부분에 색깔있는 버튼을 배치하는 일은 지루하고 실수하기 쉽다. 같은 크기의 버튼 4개를 배치하려면 다음과 같이 하면 된다.

//...
limeContent.setBounds (0, 0, 200, 24);
grapefruitContent.setBounds (0, 24, 200, 24);
lemonContent.setBounds (0, 48, 200, 24);
orangeContent.setBounds (0, 72, 200, 24);
//...

직사각형을 세분화하여 레이아웃

직사각형을 작게작게 쪼개서 컴포넌트를 다시 분할하여 레이아웃을 배치하면 동일하게 보이지만 다음과 같은 이점이 있다.

- 유지보수가 쉽다.

- 공간을 정확히 사용했는지 확인하는것이 쉽다.

- 크기를 조정할 수 있는 컴포넌트로 작업하고 특정 영역에 대한 규칙을 일정 크기 이상으로 만드는것이 쉽다.


데모 프로젝트의 MainContentComponent::resized() 함수를 보면 아래와 같다.

void resized() override
{
Rectangle<int> area (getLocalBounds());
const int headerFooterHeight = 36;
header.setBounds (area.removeFromTop (headerFooterHeight));
footer.setBounds (area.removeFromBottom (headerFooterHeight));
const int sidebarWidth = 80;
sidebar.setBounds (area.removeFromLeft (sidebarWidth));
const int contentItemHeight = 24;
limeContent.setBounds (area.removeFromTop (contentItemHeight));
grapefruitContent.setBounds (area.removeFromTop (contentItemHeight));
lemonContent.setBounds (area.removeFromTop (contentItemHeight));
orangeContent.setBounds (area.removeFromTop (contentItemHeight));
}

레이아웃할 컴포넌트의 지역 범위를 getLocalBounds() 함수로 가져온다. 이것은 항상 직사각형을 리턴하는데 직사각형은 (0,0)위치에 있는 같은 넓이,높이 컴포넌트다.  

Rectangle<int> area (getLocalBounds());

이 직사각형은 자식컴포넌트로 배치하기 위해 세분화 할 것이다. 첫번째는 header다.

header.setBounds (area.removeFromTop (headerFooterHeight));

여기서는 전체 컴포넌트를 나타내는 사각형을 가져와서 효과적으로 두개의 직사각형을 만든다. Rectangle::removeFromTop() 함수는 너비는 같지만 인수에 의해 요청된 높이만 반환한다. 이 경우 36픽셀 높이를 요구할 수 있다. 이 함수의 또 다른 기능은 반환한 사각형을 제거하는 원래 사각형을 수정한다. 본질적으로 사각형의 꼭대기부터 36픽셀을 나누는데 사각형의 위쪽을 반환하고 원래 사각형을 아래쪽 사각형과 동일하게 수정한다.


첫번째로 나눈 사각형


두번째 레이아웃 footer

footer.setBounds (area.removeFromBottom (headerFooterHeight));

Rectangle::removeFromBottom() 함수는 Rectangle::removeFromTop() 함수와 같은 의미를 갖는다. 메인 직사각형의 바텀 부분을 지운거하고 상단 사각형을 유지한다는 점에서 예외다.



- 나머지 사각형에서 왼쪽 80픽셀을 제거하여 세로 막대를 만든다.

- Rectangle::removeFromTop() 함수를 사용하여 남은 직사각형을 여러번 나눈다.


항목 재정렬

앞서 언급한 바와 같이 항목을 이 기술로 제정렬하는것은 정말 쉽다. 예를 들어 오렌지 직사각형을 꼭대기로 간단하게 resized() 함수를 사용해 옮길 수 있다.

 

//...
const int contentItemHeight = 24;
orangeContent.setBounds (area.removeFromTop (contentItemHeight)); // [1]
limeContent.setBounds (area.removeFromTop (contentItemHeight));
grapefruitContent.setBounds (area.removeFromTop (contentItemHeight));
lemonContent.setBounds (area.removeFromTop (contentItemHeight));
//..



고정된 컴포넌트 몇개를 이 방식으로 접근하면 분명히 더 좋다. 변하기 쉬운 내용을 렌더링할때 유용하다.


사이드바를 오른쪽으로 단순히 항목을 재정렬하여 옮길 수는 없지만 Rectangle::removeFromLeft() 함수를 사용하는것 대신에 Rectangle::removeFromRight() 함수를 사용하면 된다.

//...
const int sidebarWidth = 80;
sidebar.setBounds (area.removeFromRight (sidebarWidth)); // [2]
//...



컴포넌트 사이즈 재조절

이 접근 방식으로 공짜로 얻을 수 있는 점은 크기 조정하는 것이 자주 그냥 작동한다. 여기 컴포넌트를 더 넓게하고 높이를 줄였다.



만약 몇 개, 또는 모든 레이아웃이 비례하길 원하면 쉽게 인자를 코드에 넣어주면 된다. 예를 들어 사이드바가 항상 전체 너비의 4분의 1이 되도록 하고싶으면

sidebar.setBounds (area.removeFromRight (area.getWidth() / 4));

이 방법을 사용하면 유용한 제한값이 낮아진다. 이 방법으로 쉽게 통합할 수 있다. 사이드바 넓이를 전체 너비의 4분의 1로 설정하는 대신 80픽셀보다 낮게 제한하면 아래와 같다.


sidebar.setBounds (area.removeFromRight (jmax (80, area.getWidth() / 4)));

연습하기: 몇개의 버튼을 만들고 다른 색으로 수평으로 정렬하여 orangeContent, limeContent, grapefruitContent, lemonContent 컴포넌트를 추가하시오. 만들고나서 전체 너비를 채우시오.


또다른 시나리오

지금까지의 예제에서는 나머지 직사각형을 쪼개서 다음 컴포넌트를 배치했다. 일부 사각형중 하나를 저장하고 쪼개야 하는 경우가 있다.


예를 들어 항목을 예제의 슬라이더바에 배치시킬때 슬라이더바를 일시적으로 저장하고나서 쪼개야한다. 데모 프로젝트에 컴포넌트를 추가해보자.

private:
TextButton header;
TextButton sidebar;
TextButton sideItemA; // 이거
TextButton sideItemB; // 요기
TextButton sideItemC; // 이것두
TextButton limeContent;
TextButton grapefruitContent;
TextButton lemonContent;
TextButton orangeContent;
TextButton footer;

그런 다음 사이드 바 버튼에서 텍스트를 제거하면서 생성자를 구성한다.

//...
// sidebar.setButtonText 지우세요
addAndMakeVisible (sidebar);
sideItemA.setButtonText ("Item A");
sideItemB.setButtonText ("Item B");
sideItemC.setButtonText ("Item C");
addAndMakeVisible (sideItemA);
addAndMakeVisible (sideItemB);
addAndMakeVisible (sideItemC);
//...

마지막으로 resized() 함수를 아래와 같이 바꿔주자. (항목들을 그려줘야 하니까)


void
resized() override
{
Rectangle<int> area (getLocalBounds());
const int headerFooterHeight = 36;
header.setBounds (area.removeFromTop (headerFooterHeight));
footer.setBounds (area.removeFromBottom (headerFooterHeight));
{
Rectangle<int> sideBarArea (area.removeFromRight (jmax (80, area.getWidth() / 4)));
sidebar.setBounds (sideBarArea);
const int sideItemHeight = 40;
const int sideItemMargin = 5;
sideItemA.setBounds (sideBarArea.removeFromTop (sideItemHeight).reduced (sideItemMargin));
sideItemB.setBounds (sideBarArea.removeFromTop (sideItemHeight).reduced (sideItemMargin));
sideItemC.setBounds (sideBarArea.removeFromTop (sideItemHeight).reduced (sideItemMargin));
}
const int contentItemHeight = 24;
orangeContent.setBounds (area.removeFromTop (contentItemHeight));
limeContent.setBounds (area.removeFromTop (contentItemHeight));
grapefruitContent.setBounds (area.removeFromTop (contentItemHeight));
lemonContent.setBounds (area.removeFromTop (contentItemHeight));
}

컴파일하고 실행하면



이번 튜토리얼에서는 레이아웃을 세분화하여 배치하는법과 레이아웃의 위치를 상대적으로 조정하는 법을 배웠다.

반응형
Comments