メインコンテンツまでスキップ

チュートリアルリスナーとブロードキャスター

📚 Source Page

このチュートリアルでは、JUCEの重要なコンセプトであるリスナーとブロードキャスターのシステムを紹介します。ボタンのクリックに応答する簡単なアクションの実装を通して、この概念を見ていきます。

レベル初心者

プラットフォーム:Windows, macOS, Linux, iOS, Android

クラス: Button,TextButton,Button::Listener,Time

スタート

このチュートリアルのデモ・プロジェクトのダウンロードはこちらから:PIP|ZIP.プロジェクトを解凍し、最初のヘッダーファイルをProjucerで開く。

このステップにヘルプが必要な場合は、以下を参照してください。Tutorial: Projucer Part 1: Getting started with the Projucer.

デモ・プロジェクト

このチュートリアルのデモ・プロジェクトでは、1つのボタンと1つのラベルを持つシンプルなユーザー・インターフェースを紹介します。インターフェイスは次のスクリーンショットに似ているはずです:

基本的なボタンとラベルのインターフェイス。
基本的なボタンとラベルのインターフェイス。

インターフェイスは提供された状態では何もしない。ボタンをクリックすると、ラベルに現在の日付と時刻が表示されるようにコードを追加する。

インターフェイスの設定

についてMainContentComponentクラスは2つの子コンポーネントで構成されています。TextButtonオブジェクトとLabelオブジェクトATextButtonオブジェクトは、特定のテキストを含むボタンを表示することができます。Labelオブジェクトはテキストを表示できる。

注記

についてTextButtonクラスは1種類のボタンを実装している。ボタンの種類はたくさんある。Buttonクラスは JUCE で利用可能です。のAPIリファレンスドキュメントを参照してください。ToggleButton,ShapeButton,ImageButton,DrawableButtonそしてArrowButtonのクラスがある。

を宣言した。MainContentComponentクラスは以下の通りである:

class MainContentComponent   : public juce::Component
{
public:
//==============================================================================
MainContentComponent()
{
// ...
}

~MainContentComponent()
{
// ...
}

void resized() override
{
// ...
}

private:
juce::TextButton checkTheTimeButton;
juce::Label timeLabel;

//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
};
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)This is a shorthand way of writing both a JUCE_DECLARE_NON_COPYABLE and JUCE_LEAK_DETECTOR macro for ...Definition juce_PlatformDefs.h:262

ボタンとラベルはMainContentComponentオブジェクトに表示される。MainContentComponentビルダー

    MainContentComponent()
{
addAndMakeVisible (checkTheTimeButton);
checkTheTimeButton.setButtonText ("Check the time...");

addAndMakeVisible (timeLabel);
timeLabel.setColour (juce::Label::backgroundColourId, juce::Colours::black);
timeLabel.setColour (juce::Label::textColourId, juce::Colours::white);
timeLabel.setJustificationType (juce::Justification::centred);

setSize (600, 110);
}

ここでは、ボタンのテキストを設定し、ラベルの特定の外観を設定します。これにより、ラベルは黒い背景に白いテキストを表示します。デフォルトでは、ラベルはテキストを表示しません。

リスナー・ベース・クラスの追加

JUCEでは、ボタンやスライダーなど、他のオブジェクトに状態の変化を知らせる必要のあるコントロールの多くはブロードキャスターオブジェクトの変更に対応するために、他のクラスがブロードキャスター・オブジェクトの変更に応答するためには、他のクラスがリスナーリスナーは、そのブロードキャスターの特定のタイプに登録する必要があります。リスナーはまた、そのタイプの少なくとも1つの特定のブロードキャスターオブジェクトに登録される必要があります。(JUCEのブロードキャスター・リスナーシステムはobserver pattern.)多くの放送局オブジェクトは、ネストされたListenerクラスを継承することで、そのタイプのブロードキャスターのリスナーになることができる。例えばButtonクラスは、ネストされたクラスButton::Listenerそのためである。

注記

についてButton::Listenerクラスのインスタンスを含む、さまざまなボタンタイプをリッスンするために使用することができます。TextButtonクラスは次のようになる。

を使用する。Button::Listenerクラスをベース・クラスとして追加する必要がある。私たちの場合はButton::Listenerクラスをベース・クラスとしている。MainContentComponentクラス[1]:

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

カスタム・クラスは、同じようにリスナー・ベース・クラスを追加することで、異なるタイプのブロードキャスターのリスナーになることができる。

リスナーのコールバックを宣言する

通常、各リスナークラスは少なくとも1つのpure virtual関数を呼び出します。これは、ブロードキャスター・オブジェクトがその変更をブロードキャストする必要があるときに、コールバックとして呼び出される関数である。コードをコンパイルして使うためには、これをオーバーライドしなければならない。

注記

リスナー・クラスは、オーバーライドされるかもしれない他の仮想関数をしばしば含むが、それらは必要なケースが少ないのでオプションである。のドキュメントを参照してください。Slider::Listenerクラスの例である。

についてpure virtual関数のButton::ListenerクラスはButton::Listener::buttonClicked()関数を追加する必要があります。その宣言を追加する必要がある。[2]我々のMainContentComponentクラスは次のようになる:

    MainContentComponent()
{
// ...
}

~MainContentComponent()
{
// ...
}

void resized() override
{
// ...
}

void buttonClicked (juce::Button* button) override // [2]
{
}

// ...
buttonfloat float UnityEventModifiers int buttonDefinition juce_UnityPluginInterface.h:200

リスナー・コールバックの実装

ではMainContentComponent::buttonClicked()関数に渡される。ここでは、変更をブロードキャストしたオブジェクトへのポインタが渡される。そして、このポインターを他のオブジェクトと比較することで、どのオブジェクトが変更されたかを判断することができる:

    void buttonClicked (juce::Button* button) override  // [2]
{
if (button == &checkTheTimeButton) // [3]
{
auto currentTime = juce::Time::getCurrentTime(); // [4]

auto includeDate = true;
auto includeTime = true;
auto currentTimeString = currentTime.toString (includeDate, includeTime); // [5]

timeLabel.setText (currentTimeString, juce::dontSendNotification); // [6]
}
}
  • [3]ここでは、関数に渡されたポインタとボタンのアドレスを比較して、それが一致するかどうかを確認する。今回のようにボタンが1つしかない場合でも、この処理を行う必要がある。ポインタとベースとなるButtonクラスのインスタンスを持つButtonのようなサブクラスがあります。TextButtonクラスは次のようになる。
  • [4]これはTimeクラスを使ってオペレーティング・システムから現在時刻を取得する。
  • [5]を変換する。Timeオブジェクトを読みやすい文字列に変換する。2つのboolのドキュメントを参照のこと)。Time::toString()関数を参照)。
  • [6]ここでは、ラベル内に表示されるテキストを更新する。
注記

についてdontSendNotification議論[7]は、ラベルがこの変更をリスナーに伝えるのを防ぎます。(Labelオブジェクトもリスナーを持つことができます。)この場合、リスナーを持つことができないことは分かっています(私たち自身のプライベート・メンバーだからです)。

放送局へのリスナー登録

ブロードキャストされたメッセージを受信するには、リスナー・オブジェクトを1つ以上のブロードキャスター・オブジェクトに登録する必要がある。この場合TextButtonオブジェクトを返します。通常、これはリスナー・サブクラスのコンストラクタ内で行われる。[7]:

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

ほとんどの放送局オブジェクトはaddListener()この目的のためにChangeBroadcasterオブジェクトは例外です。ChangeBroadcaster::addChangeListener()関数の代わりに)。

放送局へのリスナー登録解除

放送局もまたremoveListener()関数もある。例えばButton::removeListener()関数を使用します。このボタンは、リスニングを実行しているのと同じクラスが所有しているので、実際には必要ボタンがリスナーと同時に破壊されるので、リスナーを削除する。念のため可能性があるこれをデストラクタに追加する:

~MainContentComponent()
{
checkTheTimeButton.removeListener (this);
}
警告

リスナーを適切に削除することは、より複雑なブロードキャスターとリスナーのシステムをセットアップする場合に重要である。

アプリケーションをビルドして実行します。ボタンをクリックすると、ラベルに時間が表示されるはずです。

ボタンで現在時刻を表示する。
ボタンで現在時刻を表示する。
注記

このセクションの完成したコードはListenersAndBroadcastersTutorial_02.hファイルを参照してください。

エクササイズ

表示されるテキストのフォーマットを変更してみてください。これはTime::toString()関数を使います。また、ラベルが絶対時間ではなく、ボタンをクリックする間のミリ秒数を表示するようにコードを変更することもできる。

注記

この練習のコードの実装例はListenersAndBroadcastersTutorial_03.hファイルを参照してください。

Buttonコールバックの簡素化

このチュートリアルで示したようなリスナーやブロードキャスターのパラダイムを使う代わりに、最新のC++標準のラムダ関数を使うことで、ボタンのコールバックを単純化することができます。これは、複雑な実装を必要としない単純なコールバックには特に有効です。

まずはButton::Listenerクラスを作成し、次のようにMainContentComponentクラスの定義を復元する:

class MainContentComponent   : public juce::Component
{
public:

では、MainContentComponentをリスナーとして追加する代わりにButtonラムダ関数をButton::onClickヘルパーオブジェクト[8]以下の通りである:

    MainContentComponent()
{
addAndMakeVisible (checkTheTimeButton);
checkTheTimeButton.setButtonText ("Check the time...");
checkTheTimeButton.onClick = [this] { checkTime(); }; // [8]

これはButtonオブジェクトを呼び出します。Buttonがクリックされる。

最後に、コールバック関数の名前をcheckTime()に変更します。[9]へのポインタをチェックする if() ステートメントを削除する。Buttonオブジェクトをチェックする必要がないからだ。Buttonはもうその関数を呼び出さない:

    void checkTime() // [9]
{
auto currentTime = juce::Time::getCurrentTime();

auto includeDate = true;
auto includeTime = true;
auto currentTimeString = currentTime.toString (includeDate, includeTime);

timeLabel.setText (currentTimeString, juce::dontSendNotification);
}
注記

コードの実装はListenersAndBroadcastersTutorial_04.hファイルを参照してください。

概要

このチュートリアルでは、JUCEにおけるブロードキャスターとリスナーのシステムの基本を紹介しました。このチュートリアルではボタンに焦点を当てましたが、同じテクニックはJUCEコードの多くの領域に適用できます。特に、以下のことを学びました:

  • カスタム・クラスの1つをリスナー・タイプのオブジェクトにする方法
  • リスナーのコールバック関数の追加方法
  • ブロードキャスター・オブジェクトのリスナーとしての登録と登録解除の方法
  • を使って現在時刻にアクセスする方法Timeクラスである
  • ラムダ関数でコールバックを単純化する方法。

参照