Как мне вложить эти классы и функцию FlexBox?

Я работаю в JUCE, чтобы попытаться создать гибкую структуру панели для использования аудио синтезатора. В общем, цель состоит в том, чтобы создать что-то вроде этого:

Внешний вид панели

Где есть помеченные группы помеченных ручек.

Я использую JUCE и C ++, которые имеют функцию FlexBox, которая позволяет автоматически организовывать элементы на экране, что идеально. У меня есть такой результат в настоящее время:
FlexBox Простая рабочая панель

Где все эти маркированные ручки гибко расположены на экране.

Он работает так, что каждая ручка является «ползунком», встроенным в класс JUCE, и помечается классом GroupComponent с именем «LabeledSlider». Затем собственный массив выбирает все объекты 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)
};

Теперь я хотел бы добавить второй слой FlexBox, сгруппировав ручки в больший класс с именем «LabeledGroup», чтобы каждый «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, так что это сложно для меня.

Моя главная проблема в настоящее время (если принцип здравый) заключается в том, что я не знаю, как заставить «ownarray» работать внутри класса LabeledGroup, чтобы любые LabeledSliders, определенные в данной LabeledGroup, автоматически выбирались им и таким образом организовывались. встроенным FlexBox.

Я также не знаю, как определить ручки как LabeledSliders, которые принадлежат данной LabeledGroup. то есть. Как переписать объявления слайдера, чтобы обозначить группу.

Спасибо, если вы все это прочитали. Любая помощь будет принята с благодарностью. Подобные вещи сложно понять, когда вы новичок, и вы еще не видели реальных примеров применения.

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]