コンポーネントを親子に分けるといろいろと便利そうです。
GUIの描画という点でも実用的だね~
引き続き、JUCEチュートリアルの「Parent and child components」の項目をやっていきたいと思います。
チュートリアルページは、こちらになります。
前回の記事「親と子のコンポーネント1」もご参照ください。
こんな人の役に立つかも
・JUCEプログラミングを勉強している人
・JUCEプログラミングのチュートリアルを進めている人
・Parent and child componentsチュートリアルを進めている人
コンポーネントの親子関係
HouseComponent、RoofComponent、WallComponent、FloorComponentクラスを追加していきます。
クラスの親子関係は次のようになっています。HouseComponentの子としてRoof、Wallを作ります。
プログラミング
前回の記事で、「MainComponent」クラスと「SceneComponent」クラスにプログラムを分割しました。このプログラムをベースとして追加していきたいと思います。今回追加するのは、「SceneComponent.h」と「SceneComponentc.cpp」になります。全体として、MainComponentと、そのほかのクラス、というような分け方をすることになりました。
SceneComponent.h
WallとRoofは、Houseで使用するので、Houseより↑に記載、HouseとFloorはSceneで使用するので、Sceneより↑に記載するという点を注意してクラスの定義を行いました。
//WallComponentクラス
class WallComponent : public juce::Component
{
public:
WallComponent();
void paint(juce::Graphics& g) override;
void resized() override;
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(WallComponent)
};
//RoofComponentクラス
class RoofComponent : public juce::Component
{
public:
RoofComponent();
void paint(juce::Graphics& g) override;
void resized() override;
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(RoofComponent)
};
//FloorComponentクラス
class FloorComponent : public juce::Component
{
public:
FloorComponent();
void paint(juce::Graphics& g) override;
void resized() override;
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(FloorComponent)
};
//HouseComponentクラス
class HouseComponent : public juce::Component
{
public:
HouseComponent();
void paint(juce::Graphics& g) override;
void resized() override;
private:
//[1]WallとRoofのコンポーネントを定義します。
WallComponent wall;
RoofComponent roof;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(HouseComponent)
};
class SceneComponent : public juce::Component
{
public:
SceneComponent();
void paint(juce::Graphics& g) override;
void resized() override;
private:
//[2]FloorとHouseのコンポーネントを定義します。
FloorComponent floor;
HouseComponent house;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SceneComponent)
};
全部のクラスに共通する基本的な事項としては、
①コンストラクタ
②paint関数
③resize関数
を作成する、という点でした。
[1]と[2]にて、それぞれ子となるコンポーネントを定義しています。
SceneComponent.cpp
#include "SceneComponent.h"
//[1]SceneComponentクラス
SceneComponent::SceneComponent()
{
//[1-1]floorとhouseを可視化します。
addAndMakeVisible(floor);
addAndMakeVisible(house);
}
void SceneComponent::paint(juce::Graphics& g)
{
g.fillAll(juce::Colours::lightblue);
}
void SceneComponent::resized()
{
//[1-2]floorとhouseを配置します。
floor.setBounds(10, 297, 580, 5);
house.setBounds(300, 70, 200, 220);
}
//[2]FloorComponentクラス、描画関数のみ定義しておきます。
FloorComponent::FloorComponent(){}
void FloorComponent::paint(juce::Graphics& g)
{
g.setColour(juce::Colours::green);
g.drawLine(0.0f, (float)getHeight() / 2.0f, (float)getWidth(), (float)getHeight() / 2.0f, 5.0f);
}
void FloorComponent::resized(){}
//[3]HouseComponentクラス
HouseComponent::HouseComponent(){}
void HouseComponent::paint(juce::Graphics& g)
{
//wallとroofを可視化します。
addAndMakeVisible(wall);
addAndMakeVisible(roof);
}
void HouseComponent::resized()
{
//[3-1]roofとwallのマージンの幅を設定しています。
auto separation = juce::jlimit(2, 10, getHeight() / 20);
roof.setBounds(0, 0, getWidth(), (int)(getHeight() * 0.2) - separation / 2);
wall.setBounds(0, (int)(getHeight() * 0.20) + separation / 2, getWidth(), (int)(getHeight() * 0.80) - separation);
}
//[4]WallComponentクラス、paintのみ実装します。
WallComponent::WallComponent(){}
void WallComponent::paint(juce::Graphics& g)
{
g.fillCheckerBoard(getLocalBounds().toFloat(), 30, 10,
juce::Colours::sandybrown, juce::Colours::saddlebrown);
}
void WallComponent::resized(){}
//[5]RoofComponentクラス、paintのみ実装します。
RoofComponent::RoofComponent(){}
void RoofComponent::paint(juce::Graphics& g)
{
g.setColour(juce::Colours::red);
juce::Path roof;
roof.addTriangle(0.0f, (float)getHeight(), (float)getWidth(), (float)getHeight(), (float)getWidth() / 2.0f, 0.0f);
g.fillPath(roof);
}
void RoofComponent::resized(){}
[1]floorとhouseをコンストラクタで可視化して、resize関数で配置します。
[2]は、Floorを描画します。緑色の線です。getHeightとgetWidth関数でComponentの大きさを取得して、それをもとに配置しています。
[3]のHouseComponentクラスでは、roofとwallを子コンポーネントとして持つのでこれらを可視化して、配置しています。
resize関数でのroofとwallの配置では、まず「separation」という変数に、roofとwallをぴったりとくっつけないようにする空間の値を取得しています。jlimit関数は、(下限、上限、値)という引数で、値に上限と下限を設定して返しています。「値」の計算式の結果は最小値2と最大値10というようになります。
[4]のwallコンポーネントは、paint関数内でレンガ上の矩形を描画します。
[5]のroofコンポーネントは、paint関数内で三角形を描画しています。
子コンポーネントの仕組みがよくわかってきました。
次の記事、「親と子のコンポーネント3」はこちらです。