コンポーネントのイベントハンドラのようなものですね〜
定義の仕方も2通りあるみたいだね
JUCEプログラミング、「Interface Design」の「Listeners and Broadcasters」チュートリアルをやっていきます。リスナーやブロードキャスターについては、過去のチュートリアルでも何気なく利用してきましたが、ここで、再度ちゃんと勉強したいとおもいます。
公式のチュートリアルページはこちらになります。
こんな人の役に立つかも
・JUCEプログラミングを勉強している人
・JUCEチュートリアル「Listeners and Broadcasters」をやっている人
・JUCEコンポーネントのリスナーについて勉強している人
基本となるアプリの準備
チュートリアルでは、基本となるアプリに変更を加えていくことで進みますので、まずは最初の基本となるアプリを準備します。
Projucerの「GUI」テンプレートをもとに作成していきます。
MainComponent.h
MainComponent.hには、次のように、テキストボタンと、ラベルを準備しておきます。
class MainComponent : public juce::Component
{
//...略...
private:
//次のコンポーネントを準備しておきます。
juce::TextButton checkTheTimeButton;
juce::Label timeLabel;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};
MainComponent.cpp
「GUI」テンプレートの次の部分を変更していきます。
コンストラクタ
ボタンとテキストの初期化を行います。
MainComponent::MainComponent()
{
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);
}
resized関数
ボタンとテキストの配置を行うように変更します。
void MainComponent::resized()
{
checkTheTimeButton.setBounds(10, 10, getWidth() - 20, 40);
timeLabel.setBounds(10, 60, getWidth() - 20, 40);
}
paint関数
paint関数は、何もしないように変更します。
void MainComponent::paint (juce::Graphics& g)
{}
これでチュートリアルの最初の状態ができました。
実行すると、次のようなGUIのアプリが出てきます。
リスナーの追加
各コンポーネントのリスナークラスを継承することで、コンポーネントの変化を取得することができるようになります。
Listenerクラスの継承
まずは、ボタンの変化を取得してみます。MainComponent.hのMainComponetnクラスに、「Button::Listener」クラスを継承させます。
class MainComponent : public juce::Component
, public juce::Button::Listener//継承を追加しました。
{
public:
//...略...
Listenerクラスは、それぞれのコンポーネントに存在しています。Sliderコンポーネントは「Slider::Listener」クラスのように、コンポーネントに合わせたListenerクラスを継承することで、いろいろなコンポーネントの変化を取得できます。
リスナー関数のオーバーライド
Button::Listenerクラスの関数、「buttonClicked」関数をオーバーライドして実装します。
MainComponent.hに次のようにオーバーライドします。
public:
//...略...
void resized() override;
void buttonClicked(juce::Button* button) override;
private:
//...略...
そして、cppに処理内容を実装していきます。MainComponent.cppファイルの一番下に次のようにbuttonClicked関数を追加しました。
void MainComponent::buttonClicked(juce::Button* button)
{
if (button == &checkTheTimeButton)//[1]
{
auto currentTime = juce::Time::getCurrentTime();//[2]
//[3]
auto includeDate = true;
auto includeTime = true;
auto currentTimeString = currentTime.toString(includeDate, includeTime);
timeLabel.setText(currentTimeString, juce::dontSendNotification);//[4]
}
}
[1]のように、どのボタンの処理かを判定します。button引数にボタンのポインタが渡されるので、checkTheTimeButtonコンポーネントであることを確認します。[2]では、Timeクラスで現在時間を取得します。[3]では、Timeクラスの「toString」関数で文字列に変換しています。[4]で、Labelクラスの「setText」関数でラベルオブジェクトtimeLabelへ文字列をセットします。
リスナー関数の紐づけ
リスナー関数を初期化時に紐づけします。コンストラクタで次の処理を追加しました。
MainComponent::MainComponent()
{
addAndMakeVisible(checkTheTimeButton);
checkTheTimeButton.setButtonText("Check the time...");
checkTheTimeButton.addListener(this);//←追加しました。
//...略...
また、デストラクタでリスナーを取り除く処理を追記しました。
MainComponent::~MainComponent()
{
checkTheTimeButton.removeListener(this);//追加しました。
}
シンプルな方法でリスナーを実装する
Button::Listenerクラスを継承する方法でリスナー関数を実装しましたが、ラムダ式を利用した方法でシンプルにリスナー関数を実装できます。
MainComponent.h
class MainComponent : public juce::Component
//, public juce::Button::Listener//[1]継承を削除します。
{
public:
//...略...
void resized() override;
//[2]buttonClicked関数を削除します。
//void buttonClicked(juce::Button* button) override;
private:
juce::TextButton checkTheTimeButton;
juce::Label timeLabel;
//[3]checkTime関数を追加しました。
void checkTime() {
auto currentTime = juce::Time::getCurrentTime();
auto includeDate = true;
auto includeTime = true;
auto currentTimeString = currentTime.toString(includeDate, includeTime);
timeLabel.setText(currentTimeString, juce::dontSendNotification);
};
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};
今まで作成してきたものを削除([1]と[2])、[3]のように、buttonClicked関数で行ってきた処理をcheckTime関数というものに定義しました。
MainComponent.cpp
デストラクタの内容を削除、buttonClicked関数を削除します。そして、コンストラクタに以下のようにonClicked関数でラムダ式を定義します。
MainComponent::MainComponent()
{
addAndMakeVisible(checkTheTimeButton);
checkTheTimeButton.setButtonText("Check the time...");
//checkTheTimeButton.addListener(this);//←[1]削除します。
checkTheTimeButton.onClick = [this] { checkTime(); };//[4]追加しました。
//...略...
//デストラクタ
MainComponent::~MainComponent()
{
//checkTheTimeButton.removeListener(this);//←[2]削除します。
}
//↓[3]削除します。
/*void MainComponent::buttonClicked(juce::Button* button)
{
if (button == &checkTheTimeButton)
{
//...略...
[1]と[2]と[3]の、いままで使用していた処理を削除しました。[4]では、ButtonクラスのonClicked関数を使用して、ラムダ式に処理を記述することで、リスナーを定義することができます。
on〇〇関数を利用することで、シンプルにリスナーを定義できるようです。例えば、sliderクラスにも同様の関数が定義してあります。