CafeM0ca

[JUCE]튜토리얼7 Listeners and broadcasters 본문

Programming/JUCE

[JUCE]튜토리얼7 Listeners and broadcasters

M0ca 2018. 2. 17. 05:18
반응형

//발번역 https://juce.com/doc/tutorial_listeners_and_broadcasters

tutorial_listeners_and_broadcasters.zip



데모 프로젝트는 버튼,레이블이 하나씩 있다.


이 인터페이스는 아무것도 제공하지 않는다. 코드를 추가해서 버튼이 레이블에 현제 데이터와 시간을 표시해보자.


인터페이스 구성

MainContentComponent 클래스는 자식컴포넌트로 TextButton 객체와 Lable 객체를 구성하고 있다. TextButton 객체는 버튼이 포함된 텍스트 표시할 수 있고 Lable 객체는 텍스트 부분을 표시할 수 있다.


Note: TextButton 클래스는 버튼의 일종이다. Button 클래스는 JUCE에서 많은 타입이 있다. API 레퍼런스 문서 ToggleButton,ShapeButton,ImageButton,DrawableButton,ArrowButton 클래스들을 참고해라.


MainCOmponent.h에 정의된 MainContentComponent 클래스는 다음과 같다.


class MainContentComponent : public Component
{
public:
//==============================================================================
MainContentComponent()
{
// ...
}
~MainContentComponent()
{
// ...
}
void resized() override
{
// ...
}
private:
TextButton checkTheTimeButton;
Label timeLabel;
//==============================================================================
};

버튼과 레이블은 MainContentComponent 객체에 추가되어있고 MainContentComponent 생성자에 변수를 만들었다.


MainContentComponent()
{
addAndMakeVisible (checkTheTimeButton);
checkTheTimeButton.setButtonText ("Check the time...");
addAndMakeVisible (timeLabel);
timeLabel.setColour (Label::backgroundColourId, Colours::black);
timeLabel.setColour (Label::textColourId, Colours::white);
timeLabel.setJustificationType (Justification::centred);
setSize (600, 110);
}

이 코드에서 버튼 텍스트를 설정하고 지정한 레이블을 나타내게 구성한다. 이 레이블은 검은 바탕에 흰색 글씨를 디폴트로 보여준다. 레이블은 아무 텍스트도 표시하지 않는다.


listener 기본 클래스 추가하기

JUCE에서 버튼,슬라이더, 그리고 많은 타입들은 다른 객체에 상태 변경에 대해 알릴 필요가 있는 다른 유형의 컨트롤은 브로드 캐스터 객체 유형이다. //브로드케스트(broadcast)는 '방송하다'라는 의미가 있다. 여기서는 전체 송신(또는 전달)의 의미로 이해하면 편하다.

브로드케스터 객체에서 바뀌는걸 기다리는 것 대신에 다른 클래스에서 listener가 될 것이 지정한 브로드케스터 타입을 위해 필요하다. (뿌렸으면 받아줄 사람이 필요하다는 의미) 리스너는 또한 최소한 하나의 등록된 지정한 브로드케스터 타입이 있어야한다. (반대로 받아줄 사람이 있으면 뿌린 사람도 있어야한다는 의미) JUCE에서 브로드케스터-리스너 시스템은 옵저버 패턴(https://en.wikipedia.org/wiki/Observer_pattern)을 따른다. 많은 브로드케스터 객체들은 해당 유형의 브로드케스터에 대한 리스너가 되기 위해 상속받을 수 있는 중첩된 리스너 클래스가 있다. 예를 들어 Button 클래스는 중첩된 클래스인 Button::Listener가 이 목적을 위해 포함하고 있다.


Note: Button::Listener 클래스는 다른 버튼 타입을 포함하고 있는 인스턴스로 수신하는데 사용할 수 있다.


Button::Listener 클래스를 사용하기위해 기본 클래스를 추가해주자. 우리의 경우 Button::Listener 클래스는 MainContentComponent에 기반이 된다.

class MainContentComponent : public Component,
public Button::Listener // [1]
{
public:
// ...

커스텀 클래스는 같은 방법으로 리스너의 기본 클래스를 추가 함으로써 다른 브로드케스터 타입의 리스터가 될 수 있다.


리스너 콜백 정의하기

각각의 리스너 클래스는 최고 하나의 pure virtual(http://www.learncpp.com/cpp-tutorial/126-pure-virtual-functions-abstract-base-classes-and-interface-classes/) 함수를 갖고 있다. 브로드케스터 객체가 변경 사항을 브로드케스팅해야 할 때 콜백으로 호출 될 함수다. 코드를 컴파일하고 사용하기 위해서는 오버라이드 해야한다.


Note: 리스터 클래스는 자주 오버로드된 가상함수를 포함하고있다. 하지만 옵션일뿐 적은 케이스에서 필요된다.


pure virtual 함수는 Button::Listener 클래스에서 Button::Listener::buttonClicked() 함수다. MainContentComponent 클래스에서 아래와 같이 정의한다.

MainContentComponent()
{
// ...
}
~MainContentComponent()
{
// ...
}
void resized() override
{
// ...
}
void buttonClicked (Button* button) override // [2]
{
}
// ...


리스너 콜백 구현하기

이제 MainContentComponent::buttonCliked() 함수를 구현하자. 변경을 브로드캐스팅한 객체에 대한 포인터가 전달된다. 이 포인터를 다른 객체와 비교하여 객체를 확인한다.

    void MainContentComponent::buttonClicked (Button* button)
    {
    if (button == &checkTheTimeButton) // [3]
    {
    const Time currentTime (Time::getCurrentTime()); // [4]
    const bool includeDate = true;
    const bool includeTime = true;
    const String currentTimeString (currentTime.toString (includeDate, includeTime)); // [5]
    timeLabel.setText (currentTimeString, dontSendNotification); // [6]
    }
    }

    [3] : 함수에 전달 된 포인터와 버튼의 주소를 비교하여 일치하는지 확인한다. 버튼 하나만 있어도 이 작업을 수행한다. 여기 표시된 것처럼 TextButton 클래스와 같은Button 하위 클래스의 인스턴스를 사용하여 함수에 전달 된 기본 버튼 클래스에 대한 포인터를 비교하는것이 안전하다.

    [4] : 운영체제로부터 현제 시간을 알아내는 Time 클래스를 사용하기 위해서다.

    [5] : Time 객체가 문자열을 읽을 수 있도록 바꿔준다. 두개의 bool 값은 출력의 커스텀을 허용한다.

    [6] : 레이블에 텍스트가 업데이트 되는걸 표시한다.


    Note: dontSendNotification 인자 [7]은 레이블에 해당 변경 사항을 해당 리스너에게 브로드케스팅하지 못하게한다. 이 경우 이것은 아무 리스너를 가질 수 없지만 명시적으로 하는 것이 좋다.



    브로드케스터에 리스너 등록

    메시지가 브로드케스트되는걸 받기 대신에 리스너 객체를 하나 또는 그 이상에 브로드캐스트 객체에 등록할 필요가 있다. 지금 경우네는 TextButton 객체를 등록할 필요가 있다. 일반적으로 이것은 리스너의 서브 클래스 [7]의 생성자내에서 수행된다.

    MainContentComponent()
    {
    addAndMakeVisible (checkTheTimeButton);
    checkTheTimeButton.setButtonText ("Check the time...");
    checkTheTimeButton.addListener (this); // [7]
    // ...

    Note: 대부분의 브로드케스터 객체는 addListener() 함수를 이러한 목적으로 갖고있다. (ChangeBroadcaster 객체는 예외다. 이것은 ChangeBroadcaster::addChangeListener() 함수를 대신 갖고있다.)


    브로드케스터와 리스너의 등록 취소

    브로드케스터는 removeListener() 함수를 갖고있다. 예를 들어 Button::removeListener() 함수를 보자. 버튼이 리스닝을 수행하는 클래스와 같은 클래스에 속해 있으므로 리스너와 동시에 버튼이 삭제되므로 리스너를 제거할 필요가 없다. 완벽하게 하기위해 소멸자에 다음을 추가하자.

    MainContentComponent::~MainContentComponent()
    {
    checkTheTimeButton.removeListener (this);
    }

    주의: 적절하게 리스너를 삭제하는건 중요하다 만약 당신이 더 많은 브로드케스터-리스너 시스템을 복잡하게 설정한 경우.


    컴파일하고 실행해보자.


    Note: 완성된 코드는 MainComponent_02.h에 있다.

    연습하기: 텍스트가 표시되는 포멧을 바꿔보라. Time::toString() 함수의 인자전달을 바꿀 수 있다. 또한 라벨이 절대 시간이 아닌 버튼 클릭 사이의 밀리 초 수를 표시하도록 코드를 변경할 수도 있다.


    마지막 연습하기 코드는 MainComponent_03.h에 있다.

    반응형
    Comments