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

チュートリアルスライダークラス

This tutorial introduces the スライダー class, shows how to respond to slider movements, and how to obtain values from a slider. The tutorial also introduces some essential customisation techniques for displaying values with a slider.

レベル:初級

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

クラス: スライダー, スライダー::リスナー, ラベル

はじめる

注記

This tutorial leads on from チュートリアルリスナーとブロードキャスター, which you should have read and understood first.

Download the demo project for this tutorial here: ピップ | ジップ. Unzip the project and open the first header file in the Projucer.

If you need help with this step, see チュートリアルProjucerパート1:Projucerを始める.

The demo project

The demo project shows two linear horizontal sliders. One slider is labelled 頻度 and the other is labelled 期間 as shown in the following screenshot:

The demo project user interface showing two sliders and their values.
The demo project user interface showing two sliders and their values.

The idea is that both sliders essentially display the same underlying value since frequency (f) is the reciprocal of duration (d):

f = 1⁄d

どちらかのスライダーを動かすと、もう一方のスライダーも更新され、変更が反映される。

The JUCE Slider class.

This tutorial shows how to create the sliders, configure their range, listen for changes in value, and update the slider value programmatically. You will notice in the demo application, when it runs, that both sliders include a text box, and this text box also includes the units for frequency (ヘルツ, Hertz) and duration (s, seconds).

Adding the sliders

The sliders have been added as private members to our メインコンテンツコンポーネント class:

private:
juce::Slider frequencySlider;
juce::Label frequencyLabel;
juce::Slider durationSlider;
juce::Label durationLabel;

//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
};

Notice that we also add a ラベル object for each スライダー object. These are to display the text 頻度 and 期間 to the left of the sliders. The boxes immediately to the left of the slider controls, which show the current slider values, are actually part of the スライダー objects.

We have also added the スライダー::リスナー class as base class, so that we can register our class to receive slider changes

class MainContentComponent : public juce::Component、
public juce::Slider::Listener
{
public:

In our メインコンテンツコンポーネント constructor, we add the sliders as child components (see チュートリアル親子コンポーネント), make them visible, and configure the range of values that the slider can represent. First we configure the 周波数スライダー member:

MainContentComponent()
{
addAndMakeVisible (frequencySlider);
frequencySlider.setRange (50, 5000.0); // [1].
frequencySlider.setTextValueSuffix (" Hz"); // [2].
frequencySlider.addListener (this); // [3].
  • [1]: The range of the slider is set using the スライダー::setRange() function.
  • [2]: We add a suffix to the text display in the slider's text box to show the value's units.
  • [3]: We add our メインコンテンツコンポーネント object as a listener to the slider.

対応するラベルは以下のように設定されている:

addAndMakeVisible (frequencyLabel);
frequencyLabel.setText ("Frequency", juce::dontSendNotification);
frequencyLabel.attachToComponent (&frequencySlider, true); // [4].

The [ラベル::attachToComponent()](classLabel.html#a3c2397c0da1249f9e27e2279e0f2d4eb "Makes this label "stick to" another component.") function [4] is really useful for placing a label adjacent to another component. The second argument, 真の, positions the label to the left of the other component (擬似 would position it above). As we will see shortly, this avoids us having to position the labels manually in the MainContentComponent::resized() function.

The デュレーションスライダー and the デュレーションラベル members are set up similarly, but the range of this slider is set to be the reciprocal of the range of the 周波数スライダー member:

addAndMakeVisible (durationSlider);
durationSlider.setRange (1.0 / frequencySlider.getMaximum()、
1.0 / frequencySlider.getMinimum());
durationSlider.setTextValueSuffix (" s");
durationSlider.addListener (this);

addAndMakeVisible (durationLabel);
durationLabel.setText ("Duration", juce::dontSendNotification);
durationLabel.attachToComponent (&durationSlider, true);

Positioning the slider

The sliders are positioned in the MainContentComponent::resized() function. Since we used the [ラベル::attachToComponent()](classLabel.html#a3c2397c0da1249f9e27e2279e0f2d4eb "Makes this label "stick to" another component.") function to attach the labels to the sliders, these are positioned to the left of the sliders automatically.

void resized() override
{
auto sliderLeft = 120;
frequencySlider.setBounds (sliderLeft, 20, getWidth() - sliderLeft - 10, 20);
durationSlider .setBounds (sliderLeft, 50, getWidth() - sliderLeft - 10, 20);
}

Responding to slider changes

次のコードは、スライダーのリスナーがスライダーの値の変化に反応するようにします。

void sliderValueChanged (juce::Slider* slider) override
{
if (slider == &frequencySlider)
durationSlider.setValue (1.0 / frequencySlider.getValue(), juce::dontSendNotification);
else if (slider == &durationSlider)
frequencySlider.setValue (1.0 / durationSlider.getValue(), juce::dontSendNotification);
}

This is the スライダー::リスナー::sliderValueChanged() function that we must override if we add スライダー::リスナー as a base class. Here we simply pass the reciprocal of the slider to the other slider by calling the スライダー::setValue() function. We also tell the slider not to broadcast its change. This is because there is the potential for an infinite feedback loop to occur in cases such as this, where two sliders depend upon each other. The 通知を送信しない value breaks this potential loop. Assuming the arithmetic is accurate, and the the conversions in both directions produce identical results, then this shouldn't be needed. This is because the slider will only broadcast to its listeners if the value has actually changed. (Problems can occur where there are slight rounding errors in the conversions in situations like this.) You can try omitting the 通知を送信しない value which causes the default behaviour where the slider 意志 broadcast changes. You really need to think carefully about whether to use 通知を送信しない, or not, for specific use-cases in your own applications.

Setting the initial value

In the constructor the 周波数スライダー slider is set to a value of 500. This in turn will cause the デュレーションスライダー slider to update, since we omit the 通知を送信しない value this time:

Some customisations

インターフェイスをより効果的にするために、ここにいくつかの簡単なカスタマイズを加えることができる。

Making the text box wider

The text box for the デュレーションスライダー slider, in particular, needs many digits to display its value satisfactorily. To do this we can use the スライダー::setTextBoxStyle() function. Add the following two lines of code to the メインコンテンツコンポーネント constructor:

frequencySlider.setTextBoxStyle (juce::Slider::TextBoxLeft, false, 160, frequencySlider.getTextBoxHeight());
durationSlider .setTextBoxStyle (juce::Slider::TextBoxLeft, false, 160, durationSlider .getTextBoxHeight());

This sets the text box to be 160 pixels in each case (but maintaining the height by using the スライダー::getTextBoxHeight() function).

The sliders with wider text boxes.
The sliders with wider text boxes.

Skewing the slider values

By default, the slider track is linear in the sense that the slider's value is proportional to the position of the slider thumb along the slider track. It is clear from manipulating the interface that this doesn't quite feel right. We can adjust the slider スキュー to make the slider track logarithmic. To do this we can use the スライダー::setSkewFactorFromMidPoint() function. Try this out by adding the following two lines of code to the メインコンテンツコンポーネント constructor after the sliders have been configured:

frequencySlider.setSkewFactorFromMidPoint (500);
durationSlider .setSkewFactorFromMidPoint (0.002);

This places a value of 500 at the mid-point of the slider track for the 周波数スライダー slider, and 0.002 for the デュレーションスライダー slider. Effectively, the sliders will now seem to move equally but in opposite directions. A non-linear slider track like this works well for parameters such as time and frequency where we tend to want finer control over smaller values but need less fine control over larger values.

注記

The completed code for this section can be found in the スライダー値チュートリアル_02.h file of the demo project for this tutorial.

Try out different values for the calls to the スライダー::setSkewFactorFromMidPoint() function and try out different text box sizes. Have a look at the API reference for the スライダー class and try out some other customisations.

Simplifying the Slider callback

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

First, let's remove the inheritance from the スライダー::リスナー class and restore the MainContentComponent class definition like this:

class MainContentComponent : public juce::Component
{
public:

Then, instead of adding the MainContentComponent as a listener to the スライダー, assign a lambda function to the スライダー::onValueChange helper object as follows:

MainContentComponent()
{
addAndMakeVisible (frequencySlider);
frequencySlider.setRange (50, 5000.0);
frequencySlider.setTextValueSuffix (" Hz");
frequencySlider.onValueChange = [this] { durationSlider.setValue (1.0 / frequencySlider.getValue(), juce::dontSendNotification); };

addAndMakeVisible (frequencyLabel);
frequencyLabel.setText ("Frequency", juce::dontSendNotification);
frequencyLabel.attachToComponent (&frequencySlider, true);

addAndMakeVisible (durationSlider);
durationSlider.setRange (1.0 / frequencySlider.getMaximum()、
1.0 / frequencySlider.getMinimum());
durationSlider.setTextValueSuffix (" s");
durationSlider.onValueChange = [this] { frequencySlider.setValue (1.0 / durationSlider.getValue(), juce::dontSendNotification); };

This tells the スライダー object which function to call when the スライダー value is changed by the user.

注記

The implementation of the code can be found in the スライダー値チュートリアル_03.h file of the demo project for this tutorial.

概要

In this tutorial we have introduced the スライダー class. In particular we have learned:

  • スライダーが特定の範囲で動作するように設定する方法。
  • スライダーの値の変化にどう対応するか。
  • 対数目盛りを使用するようにスライダーの傾きを設定する方法。

関連項目