Getting close to final GUI solution. No help from StackOverflow. Anyone know the final fix?


#1

It looks like I got the basic principle for my flexible FlexBox GUI working. Here is what it currently looks like:

If you expand the window horizontally, the two groups will go onto one row together. Ie. Flexbox.

Here is the full code (single file css):

/*
==============================================================================

This file was auto-generated and contains the startup code for a PIP.

==============================================================================
*/

#include "../JuceLibraryCode/JuceHeader.h"

///============================
///BEGINNING OF USUAL PROJECT HEADER


#pragma once

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 LabeledGroup : public GroupComponent

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

		addAndMakeVisible(dummy1);
		addAndMakeVisible(dummy2);
		addAndMakeVisible(dummy3);
		addAndMakeVisible(dummy4);

	}

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

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

		Array<LabeledSlider*> knobs1;
		knobs1.add(&dummy1, &dummy2, &dummy3, &dummy4);

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

		FlexBox fb1;
		fb1.flexDirection = FlexBox::Direction::column;
		fb1.items.add(FlexItem(knobBox1).withFlex(2.5));
		fb1.performLayout(getLocalBounds().reduced(15).toFloat());

		

	}


private:
	LabeledSlider dummy1{ "Dummy 1" };
	LabeledSlider dummy2{ "Dummy 2" };
	LabeledSlider dummy3{ "Dummy 3" };
	LabeledSlider dummy4{ "Dummy 4" };

};


//==============================================================================
//MAINCONTENTCOMPONENT
//==============================================================================

class MainContentComponent : public Component

{
public:
	MainContentComponent()

	{
		addAndMakeVisible(group1);
		addAndMakeVisible(group2);
	
		level.slider.setRange(0.0, 1.0);
		level.slider.setNumDecimalPlacesToDisplay(1);
		level.slider.onValueChange = [this] { targetLevel = (float)level.slider.getValue(); };
		addAndMakeVisible(level);


		setSize(600, 600);
	}

	~MainContentComponent()
	{
		//		shutdownAudio();
	}


	void resized() override
	{
	    //group1.setBounds(getLocalBounds().expanded(10));
		//group2.setBounds(getLocalBounds().expanded(10));
		
		FlexBox groupBox1;
		groupBox1.flexWrap = FlexBox::Wrap::wrap;
		groupBox1.justifyContent = FlexBox::JustifyContent::flexStart;
		groupBox1.alignContent = FlexBox::AlignContent::flexStart;
		

		Array<LabeledGroup*> groups1array;
		groups1array.add(&group1, &group2);

		for (auto *g : groups1array)
		groupBox1.items.add(FlexItem(*g).withMinHeight(100.0f).withMinWidth(350.0f).withFlex(3).withMargin(5));

		FlexBox fb1;
		fb1.flexDirection = FlexBox::Direction::column;
		fb1.items.add(FlexItem(groupBox1).withFlex(3));
		fb1.performLayout(getLocalBounds().toFloat());
	
		
	}




private:

	float currentLevel = 0.1f, targetLevel = 0.1f;

	LabeledGroup group1{ "Group 1" };
	LabeledGroup group2{ "Group 2" };
	LabeledSlider level{ "Level" };


	JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MainContentComponent)
};





///============================
///BEGINNING OF USUAL MAIN.CPP
class Application : public JUCEApplication
{
public:

	Application() {}

	const String getApplicationName() override { return "SineSynthTutorial"; }
	const String getApplicationVersion() override { return "3.0.0"; }

	void initialise(const String&) override { mainWindow.reset(new MainWindow("SineSynthTutorial", new MainContentComponent(), *this)); }
	void shutdown() override { mainWindow = nullptr; }

private:
	class MainWindow : public DocumentWindow
	{
	public:
		MainWindow(const String& name, Component* c, JUCEApplication& a)
			: DocumentWindow(name, Desktop::getInstance().getDefaultLookAndFeel()
				.findColour(ResizableWindow::backgroundColourId),
				DocumentWindow::allButtons),
			app(a)
		{
			setUsingNativeTitleBar(true);
			setContentOwned(c, true);

#if JUCE_ANDROID || JUCE_IOS
			setFullScreen(true);
#else
			setResizable(true, false);
			setResizeLimits(300, 250, 10000, 10000);
			centreWithSize(getWidth(), getHeight());
#endif

			setVisible(true);
		}

		void closeButtonPressed() override
		{
			app.systemRequestedQuit();
		}

	private:
		JUCEApplication & app;

		//==============================================================================
		JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MainWindow)
	};

	std::unique_ptr<MainWindow> mainWindow;
};

//==============================================================================
START_JUCE_APPLICATION(Application)

The problem is I am declaring variables three times directly inside the class definition for LaeledGroup:

    addAndMakeVisible(dummy1);
	addAndMakeVisible(dummy2);
	addAndMakeVisible(dummy3);
	addAndMakeVisible(dummy4);

    knobs1.add(&dummy1, &dummy2, &dummy3, &dummy4);

    LabeledSlider dummy1{ "Dummy 1" };
	LabeledSlider dummy2{ "Dummy 2" };
	LabeledSlider dummy3{ "Dummy 3" };
	LabeledSlider dummy4{ "Dummy 4" };

I need a way of replacing these three portions to references to arrays or vectors, that I can then specify for each object of LabeledGroup, so each LabeledGroup can be generated with its own number and names of knobs accordingly (from its own arrays).

I have tried this many times with arrays and vectors but I do not seem to be succeeding. Can anyone help?

I’m getting much closer to my goal! Just need some help with the vector/array references . . .

Thanks.


#2

For example, I tried the implementation suggested here:

But it leads at best to this error:

So I really don’t know what the solution is. seems like a really simple challenge anyone who speaks C++ fluently could fix rather effortlessly. Any help?


#3

Until C++17 (excluded), emplace_back returns void, so you can’t use its return value and pass it to addAndMakeVisible, unless you compile with C++17.

Without C++17, you can write:

for (const auto& name: {"dummy1", "dummy2", "dummy3", "dummy4"})
{
    _sliders.emplace_back(name);
    addAndMakeVisible(_sliders.back());
}

You also need to be careful about the C++ syntax. For instance, you wrote the following

LabeledGroup addAndMakeVisible(...);

which, in this context, means: instantiate a variable named addAndMakeVisible of type LabeledGroup.