コンボボックスも見た目をカスタマイズできるみたいですね。
やりたいことの多くはコンポーネントの設定でできそうだね~
JUCE、「Interface Design」の「The ComboBox class」チュートリアルの続き、「Using item ID numbers」の項目から進めていきます。コンボボックス実装の際の可読性UPにつながるテクニックに関するチュートリアルです。enumクラスでの項目定義と、項目を見出しで表示させるような内容を勉強していきます。前回の記事の続きとなります。
公式のチュートリアルページはこちらになります。
https://docs.juce.com/master/tutorial_combo_box.html
こんな人の役に立つかも
・JUCEプログラミングを勉強している人
・JUCEチュートリアル「The ComboBox class」をやっている人
・JUCEのコンボボックスの使い方について知りたい人
enumで可読性UP
コンボボックスに登録する項目をあらかじめenumとしてクラスに登録しておき、利用することで、プログラムの可読性が向上します。デフォルトだと、1から順番に項目のID番号として登録されていきますが、より大きなプログラムになると、整数で管理するより、言葉で管理した方がわかりやすくなります。
次の変更でプログラムをファクタリングをしていきます。
MainComponent.h
次のように「fontStyle」というenumを追加しました。
//...略...
private:
//...略...
//以下のenumを追加しました。
enum FontStyles
{
stylePlain = 1,
styleBold,
styleItalic,
numberOfStyles
};
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};
この場合は、stylePlaneが整数の1、styleBoldが整数の2、styleItalicが整数の3、numberOfStylesが整数の4と紐づけられます。
ちなみに、このenumは、enumクラスといって、C++の機能です。C言語のenumとは違うようです。
https://monozukuri-c.com/langcpp-funclist-enum-class/
JUCEのコンボボックスの整数0番は、何も選択されていないことを示す特別な番号なので、項目に0を使ってはいけません。とのことでした。
MainComponent.cpp
cppファイルの次の点を変更しました。
コンストラクタ
MainComponent::MainComponent()
{
//...略...
styleMenu.onChange = [this] { styleMenuChanged(); };
//styleMenu.setSelectedId(1);
//↑を下のように変更しました。
styleMenu.setSelectedId(stylePlain);
setSize(400, 200);
}
コンストラクタのsetSelectedId関数に与える数値を先ほどenumで定義した文字列にしています。
styleMenuChanged関数
void MainComponent::styleMenuChanged()
{
switch (styleMenu.getSelectedId())
{
/*
case 1: textFont.setStyleFlags(juce::Font::plain); break;
case 2: textFont.setStyleFlags(juce::Font::bold); break;
case 3: textFont.setStyleFlags(juce::Font::italic); break;
default: break;
*/
//上のcaseに与える変数をenum定義の項目としました。
case stylePlain: textFont.setStyleFlags(juce::Font::plain); break;
case styleBold: textFont.setStyleFlags(juce::Font::bold); break;
case styleItalic: textFont.setStyleFlags(juce::Font::italic); break;
default: break;
}
textLabel.setFont(textFont);
}
単純に、コンボボックスのIDを利用していた点をenumで定義した項目に置き換えました。
こうすることで、ヘッダーに定義されたenumとしてそれぞれの項目を管理することができます。
プログラミングのテクニック的な感じだね〜
コンボボックス内に見出しを作る
次のように、一番上のラベルの色を変更するコンボボックスを追加します。また、このコンボボックスは見出しと区切り線で項目の種類毎にまとめるようなスタイルにしています。
MainComponent.h
MainComonentクラスのprivateなメンバとして以下のものを追加しました。
private:
//...略...
juce::ComboBox coloursMenu;//[1]
void coloursMenuChanged();//[2]
//[3]
enum TextColours
{
black = 1,
white,
red,
darkred,
indianred,
green,
darkgreen,
lightgreen,
blue,
darkblue,
lightblue,
numberOfColours
};
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};
[1]は、新しく追加するコンボボックスコンポーネントです。[2]は、コンボボックスの選択が変更されたときに処理をする内容を記載する関数です。[3]は、コンボボックスに格納する項目を羅列したenumとなります。
MainComponent.cpp
コンストラクタ
コンストラクタでcoloursMenuの初期化を行います。
MainComponent::MainComponent()
{
//...略...
//以下から追加しました。
addAndMakeVisible(coloursMenu);
coloursMenu.addItem("Black", black);
coloursMenu.addItem("White", white);
coloursMenu.addSeparator();
coloursMenu.addSectionHeading("Reds");
coloursMenu.addItem("Red", red);
coloursMenu.addItem("Dark Red", darkred);
coloursMenu.addItem("Indian Red", indianred);
coloursMenu.addSeparator();
coloursMenu.addSectionHeading("Greens");
coloursMenu.addItem("Green", green);
coloursMenu.addItem("Dark Green", darkgreen);
coloursMenu.addItem("Light Green", lightgreen);
coloursMenu.addSeparator();
coloursMenu.addSectionHeading("Blues");
coloursMenu.addItem("Blue", blue);
coloursMenu.addItem("Dark Blue", darkblue);
coloursMenu.addItem("Light Blue", lightblue);
coloursMenu.onChange = [this] { coloursMenuChanged(); };
coloursMenu.setSelectedId(black);
coloursMenu.setEditableText(true);
setSize(400, 200);
}
addItem関数で順次項目を追加していきます。コンボボックスクラスのaddSeparator関数は項目との間に区切り線を追加します。わかりやすいです。addSectionHeading関数は、項目の見出しにするための関数です。
そして、onChange関数でラムダ式にcoloursMenuChanged関数を実行する用に定義しています。
最後のsetEditableText関数は、コンボボックスのテキストをユーザー入力で変更することができるようなものです。
見た目と対応していて、シンプルに使えますね。
coloursMenuChanged関数
cppファイルに以下のcoloursMenuChanged関数を追加します。
void MainComponent::coloursMenuChanged()
{
juce::Colour textColour;
switch (coloursMenu.getSelectedId())
{
case black: textColour = juce::Colours::black; break;
case white: textColour = juce::Colours::white; break;
case red: textColour = juce::Colours::red; break;
case darkred: textColour = juce::Colours::darkred; break;
case indianred: textColour = juce::Colours::indianred; break;
case green: textColour = juce::Colours::green; break;
case darkgreen: textColour = juce::Colours::darkgreen; break;
case lightgreen: textColour = juce::Colours::lightgreen; break;
case blue: textColour = juce::Colours::blue; break;
case darkblue: textColour = juce::Colours::darkblue; break;
case lightblue: textColour = juce::Colours::lightblue; break;
}
textLabel.setColour(juce::Label::textColourId, textColour);
}
これは、coloursMenuコンボボックスの項目選択が変更されたときに実行されます。スイッチ文でcoloursMenuの選択されている項目を取得して、textLabelの色をsetColour関数で変更するという処理をおこないます。
resized関数
最後に、resized関数でcoloursMenuコンボボックスをGUIに配置しておきます。
void MainComponent::resized()
{
textLabel.setBounds(10, 10, getWidth() - 20, 20);
styleMenu.setBounds(10, 40, getWidth() - 20, 20);
coloursMenu.setBounds(10, 70, getWidth() - 20, 20);//追加しました。
}