如何嵌套这些类和FlexBox函数?

时间:2018-09-02 19:40:51

标签: c++ class flexbox nested juce

我正在JUCE内工作,试图为音频合成器创建一个灵活的面板结构。通常,目标是创建看起来像这样的东西:

Panel Look

有标记的旋钮组的地方。

我正在使用JUCE和C ++,它具有FlexBox功能,该功能允许自动组织屏幕上的元素,这是理想的选择。我目前有这个结果: FlexBox Simple Panel Working

所有这些标记的旋钮都可以灵活地布置在屏幕上。

它的工作方式是每个旋钮都是JUCE类中内置的“滑块”,并由名为“ LabeledSlider”的GroupComponent类标记。然后,ownedarray会拾取LabeledSlider的所有对象,内置的FlexBox函数会在屏幕上自动排列此数组。

这是该工作代码,其中仅包含一个基于频率和幅度旋钮的简单正弦波发生器:

class LabeledSlider : public GroupComponent

{
    public:
    LabeledSlider (const String& name)
    {
        setText (name);
        setTextLabelPosition (Justification::centredTop);
        addAndMakeVisible (slider);
    }

    void resized() override
    {
        slider.setBounds (getLocalBounds().reduced (10));
    }

    Slider slider 
    { 
        Slider::RotaryHorizontalVerticalDrag, Slider::TextBoxBelow 
    };


};



class MainContentComponent : public AudioAppComponent
{
public:
    MainContentComponent()

    {

        LabeledSlider* control = new LabeledSlider("Frequency");
        control->slider.setRange(20.0, 20000.0);
        control->slider.setSkewFactorFromMidPoint(500.0);
        control->slider.setNumDecimalPlacesToDisplay(1);
        control->slider.setValue(currentFrequency, dontSendNotification);
        control->slider.onValueChange = [this] { targetFrequency = frequency.slider.getValue(); };
        control->slider.setTextBoxStyle(Slider::TextBoxBelow, false, 100, 20);
        control->slider.setRange(50.0, 5000.0);
        control->slider.setSkewFactorFromMidPoint(500.0);
        control->slider.setNumDecimalPlacesToDisplay(1);
        addAndMakeVisible(knobs.add(control));

        control = new LabeledSlider("Level");
        control->slider.setRange(0.0, 1.0);
        control->slider.onValueChange = [this] { targetLevel = (float)level.slider.getValue(); };
        addAndMakeVisible(knobs.add(control));

        control = new LabeledSlider("Dummy1");
        addAndMakeVisible(knobs.add(control));

        control = new LabeledSlider("Dummy2");
        addAndMakeVisible(knobs.add(control));

        control = new LabeledSlider("Dummy3");
        addAndMakeVisible(knobs.add(control));

        control = new LabeledSlider("Dummy4");
        addAndMakeVisible(knobs.add(control));

        control = new LabeledSlider("Dummy5");
        addAndMakeVisible(knobs.add(control));

        control = new LabeledSlider("Dummy6");
        addAndMakeVisible(knobs.add(control));

        control = new LabeledSlider("Dummy7");
        addAndMakeVisible(knobs.add(control));

        control = new LabeledSlider("Dummy8");
        addAndMakeVisible(knobs.add(control));

        control = new LabeledSlider("Dummy9");
        addAndMakeVisible(knobs.add(control));


    setSize (600, 600);
    setAudioChannels (0, 2); // no inputs, two outputs
    }

    ~MainContentComponent()
    {
        shutdownAudio();
    }

    void resized() override
    {

        //==============================================================================
        FlexBox knobBox;
        knobBox.flexWrap = FlexBox::Wrap::wrap;
        knobBox.justifyContent = FlexBox::JustifyContent::flexStart;
        knobBox.alignContent = FlexBox::AlignContent::flexStart;


        for (auto* k : knobs)
            knobBox.items.add(FlexItem(*k).withMinHeight(80.0f).withMinWidth(80.0f).withFlex(1));

        //==============================================================================
        FlexBox fb;
        fb.flexDirection = FlexBox::Direction::column;
        fb.items.add(FlexItem(knobBox).withFlex(2.5));
        fb.performLayout(getLocalBounds().toFloat());


    }

    inline void updateAngleDelta()
    {
        auto cyclesPerSample = currentFrequency / currentSampleRate;
        angleDelta = cyclesPerSample * 2.0 * MathConstants<double>::pi;
    }

    void prepareToPlay (int, double sampleRate) override
    {
        currentSampleRate = sampleRate;
        updateAngleDelta();
    }

    void releaseResources() override {}

    void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) override
    {
        auto* leftBuffer  = bufferToFill.buffer->getWritePointer (0, bufferToFill.startSample);
        auto* rightBuffer = bufferToFill.buffer->getWritePointer (1, bufferToFill.startSample);

        auto localTargetFrequency = targetFrequency;

        if (targetFrequency != currentFrequency)
        {
            auto frequencyIncrement = (targetFrequency - currentFrequency) / bufferToFill.numSamples;

            for (auto sample = 0; sample < bufferToFill.numSamples; ++sample)
            {
                auto currentSample = (float) std::sin (currentAngle);
                currentFrequency += frequencyIncrement;
                updateAngleDelta();
                currentAngle += angleDelta;
                leftBuffer[sample]  = currentSample;
                rightBuffer[sample] = currentSample;
            }

            currentFrequency = localTargetFrequency;
        }
        else
        {
            for (auto sample = 0; sample < bufferToFill.numSamples; ++sample)
            {
                auto currentSample = (float) std::sin (currentAngle);
                currentAngle += angleDelta;
                leftBuffer[sample]  = currentSample;
                rightBuffer[sample] = currentSample;
            }
        }

        auto localTargetLevel = targetLevel;
        bufferToFill.buffer->applyGainRamp (bufferToFill.startSample, bufferToFill.numSamples, currentLevel, localTargetLevel);
        currentLevel = localTargetLevel;
    }

private:
    double currentSampleRate = 0.0, currentAngle = 0.0, angleDelta = 0.0;
    double currentFrequency = 500.0, targetFrequency = 500.0;
    float currentLevel = 0.1f, targetLevel = 0.1f;
    int rotaryDiam = 100;

    LabeledSlider frequency{ "Frequency" };
    LabeledSlider level{ "Level" };
    LabeledSlider dummy1{ "Dummy 1" };
    LabeledSlider dummy2{ "Dummy 2" };
    LabeledSlider dummy3{ "Dummy 3" };
    LabeledSlider dummy4{ "Dummy 4" };
    LabeledSlider dummy5{ "Dummy 5" };
    LabeledSlider dummy6{ "Dummy 6" };
    LabeledSlider dummy7{ "Dummy 7" };
    LabeledSlider dummy8{ "Dummy 8" };
    LabeledSlider dummy9{ "Dummy 9" };

    OwnedArray<LabeledSlider> knobs;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
};

我现在想通过将旋钮分组到更大的类“ LabeledGroup”中来添加第二层FlexBox,以便每个“ LabeledSlider”在定义时都应属于LabeledGroup。

然后,可以使用相同的FlexBox功能自动组织LabeledGroups中的旋钮,还可以组织LabeledGroups本身。

尽管我对这一切还是陌生的,所以尽管我现在已经花了数小时来阅读有关嵌套类的信息,但我仍然不知道该怎么做。

这是我重组上述代码的粗略尝试,尽管显然不起作用:

class LabeledGroup : public GroupComponent

{

public:

    LabeledGroup(const String& name)
    {
        setText(name);
        setTextLabelPosition(Justification::centredTop);


        class LabeledSlider : public GroupComponent
        {
        public:
            LabeledSlider(const String& name)
            {
                setText(name);
                setTextLabelPosition(Justification::centredTop);
                addAndMakeVisible(slider);
            }

            void resized() override
            {
                slider.setBounds(getLocalBounds().reduced(10));
            }

            Slider slider
            {
                Slider::RotaryHorizontalVerticalDrag, Slider::TextBoxBelow
            };

        };

    }

private:
    void resized() override
    {

        OwnedArray<LabeledSlider> knobs;

        //==============================================================================
        FlexBox knobBox;
        knobBox.flexWrap = FlexBox::Wrap::wrap;
        knobBox.justifyContent = FlexBox::JustifyContent::flexStart;
        knobBox.alignContent = FlexBox::AlignContent::flexStart;

        for (auto* k : knobs)
            knobBox.items.add(FlexItem(*k).withMinHeight(80.0f).withMinWidth(80.0f).withFlex(1));

        //==============================================================================
        FlexBox fb;
        fb.flexDirection = FlexBox::Direction::column;
        fb.items.add(FlexItem(knobBox).withFlex(2.5));
        fb.performLayout(getLocalBounds().toFloat());

    }

};




class MainContentComponent : public AudioAppComponent
{
public:
    MainContentComponent()

    {
        addAndMakeVisible(group1);

        LabeledSlider* control = new LabeledSlider("Frequency");
        control->slider.setRange(20.0, 20000.0);
        control->slider.setSkewFactorFromMidPoint(500.0);
        control->slider.setNumDecimalPlacesToDisplay(1);
        control->slider.setValue(currentFrequency, dontSendNotification);
        control->slider.onValueChange = [this] { targetFrequency = frequency.slider.getValue(); };
        control->slider.setTextBoxStyle(Slider::TextBoxBelow, false, 100, 20);
        control->slider.setRange(50.0, 5000.0);
        control->slider.setSkewFactorFromMidPoint(500.0);
        control->slider.setNumDecimalPlacesToDisplay(1);
        addAndMakeVisible(knobs.add(control));

        control = new LabeledSlider("Level");
        control->slider.setRange(0.0, 1.0);
        control->slider.onValueChange = [this] { targetLevel = (float)level.slider.getValue(); };
        addAndMakeVisible(knobs.add(control));

        control = new LabeledSlider("Dummy1");
        addAndMakeVisible(knobs.add(control));

        control = new LabeledSlider("Dummy2");
        addAndMakeVisible(knobs.add(control));

        control = new LabeledSlider("Dummy3");
        addAndMakeVisible(knobs.add(control));

        control = new LabeledSlider("Dummy4");
        addAndMakeVisible(knobs.add(control));

        control = new LabeledSlider("Dummy5");
        addAndMakeVisible(knobs.add(control));

        control = new LabeledSlider("Dummy6");
        addAndMakeVisible(knobs.add(control));

        control = new LabeledSlider("Dummy7");
        addAndMakeVisible(knobs.add(control));

        control = new LabeledSlider("Dummy8");
        addAndMakeVisible(knobs.add(control));

        control = new LabeledSlider("Dummy9");
        addAndMakeVisible(knobs.add(control));

    setSize (600, 600);
    setAudioChannels (0, 2); // no inputs, two outputs
    }

    ~MainContentComponent()
    {
        shutdownAudio();
    }

    void resized() override
    {

        //==============================================================================
        FlexBox knobBox;
        knobBox.flexWrap = FlexBox::Wrap::wrap;
        knobBox.justifyContent = FlexBox::JustifyContent::flexStart;
        knobBox.alignContent = FlexBox::AlignContent::flexStart;

        for (auto* k : knobgroup)
            knobBox.items.add(FlexItem(*k).withMinHeight(80.0f).withMinWidth(80.0f).withFlex(1));

        //==============================================================================
        FlexBox fb;
        fb.flexDirection = FlexBox::Direction::column;
        fb.items.add(FlexItem(knobBox).withFlex(2.5));
        fb.performLayout(getLocalBounds().toFloat());


    }

    inline void updateAngleDelta()
    {
        auto cyclesPerSample = currentFrequency / currentSampleRate;
        angleDelta = cyclesPerSample * 2.0 * MathConstants<double>::pi;
    }

    void prepareToPlay (int, double sampleRate) override
    {
        currentSampleRate = sampleRate;
        updateAngleDelta();
    }

    void releaseResources() override {}

    void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) override
    {
        auto* leftBuffer  = bufferToFill.buffer->getWritePointer (0, bufferToFill.startSample);
        auto* rightBuffer = bufferToFill.buffer->getWritePointer (1, bufferToFill.startSample);

        auto localTargetFrequency = targetFrequency;

        if (targetFrequency != currentFrequency)
        {
            auto frequencyIncrement = (targetFrequency - currentFrequency) / bufferToFill.numSamples;

            for (auto sample = 0; sample < bufferToFill.numSamples; ++sample)
            {
                auto currentSample = (float) std::sin (currentAngle);
                currentFrequency += frequencyIncrement;
                updateAngleDelta();
                currentAngle += angleDelta;
                leftBuffer[sample]  = currentSample;
                rightBuffer[sample] = currentSample;
            }

            currentFrequency = localTargetFrequency;
        }
        else
        {
            for (auto sample = 0; sample < bufferToFill.numSamples; ++sample)
            {
                auto currentSample = (float) std::sin (currentAngle);
                currentAngle += angleDelta;
                leftBuffer[sample]  = currentSample;
                rightBuffer[sample] = currentSample;
            }
        }

        auto localTargetLevel = targetLevel;
        bufferToFill.buffer->applyGainRamp (bufferToFill.startSample, bufferToFill.numSamples, currentLevel, localTargetLevel);
        currentLevel = localTargetLevel;
    }

private:
    double currentSampleRate = 0.0, currentAngle = 0.0, angleDelta = 0.0;
    double currentFrequency = 500.0, targetFrequency = 500.0;
    float currentLevel = 0.1f, targetLevel = 0.1f;
    int rotaryDiam = 100;

    LabeledSlider frequency{ "Frequency" };
    LabeledSlider level{ "Level" };
    LabeledSlider dummy1{ "Dummy 1" };
    LabeledSlider dummy2{ "Dummy 2" };
    LabeledSlider dummy3{ "Dummy 3" };
    LabeledSlider dummy4{ "Dummy 4" };
    LabeledSlider dummy5{ "Dummy 5" };
    LabeledSlider dummy6{ "Dummy 6" };
    LabeledSlider dummy7{ "Dummy 7" };
    LabeledSlider dummy8{ "Dummy 8" };
    LabeledSlider dummy9{ "Dummy 9" };

    LabeledGroup group1{ "Group 1" };

    OwnedArray<LabeledGroup> knobgroup;
  JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)

我是C ++和JUCE的新手,所以这对我来说很棘手。

我目前的主要问题(如果原则是合理的)是我不知道如何在LabeledGroup类中运行“ ownedarray”,因此给定LabeledGroup中定义的所有LabeledSliders都会自动被拾取因此由内置的FlexBox进行组织。

我也不知道如何将旋钮定义为属于给定LabeledGroup的LabeledSliders。即。如何重新编写滑块声明,以便指定组。

感谢您阅读所有这些内容。任何帮助将不胜感激。当您是新手并且以前从未见过该应用程序的真实示例时,很难弄清这些事情。

0 个答案:

没有答案