見た目の作り方を少しスマートにできるようです。
レイアウト、大事だね~
JUCEプログラミング、「Interface Design」の「Advanced GUI layout techniques」チュートリアルを進めていきます。JUCEアプリケーションで、コンポーネントの配置について、少し便利なテクニックなどを勉強できるようです。
公式のチュートリアルページはこちらになります。
こんな人の役に立つかも
・JUCEプログラミングを勉強している人
・JUCEチュートリアル「Advanced GUI layout techniques」をやっている人
・JUCEのGUIレイアウトについて勉強している人
作成するGUIレイアウトと準備
このチュートリアルでは、次のようなGUIレイアウトを作成していきます。
そして、よりスマートなコンポーネントの配置方法を学んでいきます。まずは、基本となるデモアプリを準備します。
Projucerの「GUI」レイアウトから作成していきます。
基本となるプログラムの準備
まずは、MainComponent.hに配置するコンポーネントを準備します。
class MainComponent : public juce::Component
{
public:
//...略...
private:
//以下のコンポーネントを準備しました。
juce::TextButton header;
juce::TextButton sidebar;
juce::TextButton limeContent;
juce::TextButton grapefruitContent;
juce::TextButton lemonContent;
juce::TextButton orangeContent;
juce::TextButton footer;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};
次に、MainComponent.cppのコンストラクタの内容を次のように変更しました。それぞれのコンポーネントの初期化設定と可視化です。
MainComponent::MainComponent()
{
header.setColour(juce::TextButton::buttonColourId, juce::Colours::cornflowerblue);
header.setButtonText("Header");
addAndMakeVisible(header);
footer.setColour(juce::TextButton::buttonColourId, juce::Colours::cornflowerblue);
footer.setButtonText("Footer");
addAndMakeVisible(footer);
sidebar.setColour(juce::TextButton::buttonColourId, juce::Colours::grey);
sidebar.setButtonText("Sidebar");
addAndMakeVisible(sidebar);
limeContent.setColour(juce::TextButton::buttonColourId, juce::Colours::lime);
addAndMakeVisible(limeContent);
grapefruitContent.setColour(juce::TextButton::buttonColourId, juce::Colours::yellowgreen);
addAndMakeVisible(grapefruitContent);
lemonContent.setColour(juce::TextButton::buttonColourId, juce::Colours::yellow);
addAndMakeVisible(lemonContent);
orangeContent.setColour(juce::TextButton::buttonColourId, juce::Colours::orange);
addAndMakeVisible(orangeContent);
setSize(400, 400);
}
ここまでで、チュートリアルをやっていく準備ができました。
シンプルなコンポーネントの配置方法
一番シンプルなコンポーネントの配置方法は、ひとつづつのコンポーネントにたいしてsetBoundsで座標やサイズを指定していく方法です。resized関数に記載することでGUI上に配置します。
例えば、4つのボタンを同じサイズで、順番に配置していく場合、MainComponent.cppのresized関数に次のように記載します。
void MainComponent::resized()
{
limeContent.setBounds(0, 0, 200, 24);
grapefruitContent.setBounds(0, 24, 200, 24);
lemonContent.setBounds(0, 48, 200, 24);
orangeContent.setBounds(0, 72, 200, 24);
}
実行すると、次のような画面になります。
シンプルな方法の問題点
一方で、この方法は、ひとつづつのコンポーネントのすべての座標やサイズを自分で計算して入力しなければいけないので、ミスも起こりますし、管理上、とても手間がかかります。2番目のボタンが不要となったとき、3番目と4番目のボタンの座標のY座標を計算しなおして入力しなければいけません。大きなアプリとなると、もっとたくさんのコンポーネントがはいってきますので、現実的ではありません。
矩形分割による配置方法
矩形分割での配置方法は、Rectangleクラスの「removeFromTop」「removeFromBottom」といった「removeFrom○○」系の関数で配置していく方法です。「removeFrom○○」系の関数の挙動は、例えば「removeFromTop(24)」では、矩形領域の上部24の高さの矩形を設定して、自分自身を残りの下の矩形領域に設定する、という動作をします。
詳細な図での説明は、以前の記事で記載しましたので、そちらもご参照ください。この記事ではremoveFromLeftを参考にしています。
実際にこの方法でコンポーネントを配置していくことにします。
paint関数内を次のように変更してみます。
void MainComponent::resized() override
{
//[1]MainConponentの描画領域を取得します。
auto area = getLocalBounds();
//[2]ヘッダーとフッターを設置します。
auto headerFooterHeight = 36;
header.setBounds (area.removeFromTop (headerFooterHeight));
footer.setBounds (area.removeFromBottom (headerFooterHeight));
//[3]サイドバーを設置します。
auto sidebarWidth = 80;
sidebar.setBounds (area.removeFromLeft (sidebarWidth)); // [2]
//[4]カラフルなボタンを設置します。
auto contentItemHeight = 24;
limeContent.setBounds (area.removeFromTop (contentItemHeight));
grapefruitContent.setBounds (area.removeFromTop (contentItemHeight));
lemonContent.setBounds (area.removeFromTop (contentItemHeight));
orangeContent.setBounds (area.removeFromTop (contentItemHeight));
}
[1]では、getLocalBounds関数で、MainComponentの描画領域を取得しています。
[2]では、headerとfooterを設置します。
上と下の青い部分です。
removeFromTop(36)関数を実行することで、関数の返り値はHeader部分の高さ36の矩形領域を返します。そのため、headerのsetBoundsの引数には高さ36の青色の部分の矩形領域が渡されます。一方で、area自体は下の赤枠の部分の矩形領域に更新されます。
そのため、次のfooterの設定時には、areaの矩形領域は赤枠の部分の矩形領域に設定されています。footerも同様に、removeFromBottom(36)で、今度は矩形領域の下から高さ36の矩形領域を返します。area自身はその上の部分の矩形領域となります。
[3]で、引き継いだareaの矩形領域の左80の幅をサイドバーとして設定します。
[4]には、さらに残された中央部分の矩形領域に小さなボタンを上から24の高さで設置していきます。
この方法のメリット
GUIのコンポーネントの入れ替えを簡単に行うことができます。
また、コンポーネントの削除も、他のコンポーネントの座標情報を計算していちいち入力することなく可能です。
このアプリのサイドバーをremoveFromRight関数に変更するだけで、右に持ってくることもすぐにできます。
この方法でコンポーネントを配置すれば、後からのGUIの変更も柔軟に対応できそうです。