JUCE unable to insert button on audio plugin - c++

I'm attempting to add a button in an audio plugin, but can't seem to get it to display when testing.
I'm using the plugin host to test, and view the GUI. pad1 is defined in PluginEditor.h:
private:
// This reference is provided as a quick way for your editor to
// access the processor object that created it.
CPAudioProcessor& processor;
TextButton pad1;
I've placed the following code in PluginEditor.cpp:
CPAudioProcessorEditor::CPAudioProcessorEditor (CPAudioProcessor& p)
: AudioProcessorEditor (&p), processor (p)
{
pad1.setColour(TextButton::buttonColourId, Colours::lime);
pad1.setButtonText("Press Me!");
addAndMakeVisible(pad1);
// Make sure that before the constructor has finished, you've set the
// editor's size to whatever you need it to be.
setSize (400, 300);
}
I was following this tutorial as a guide on how to add the button: https://www.juce.com/doc/tutorial_rectangle_advanced
Is there anything I'm missing? It looks the same as the code in the guide.

The problem was I forgot to set the width/height in the overridden resized method.
void CPAudioProcessorEditor::resized()
{
// This is generally where you'll want to lay out the positions of any
// subcomponents in your editor..
pad1.setBounds(10, 10, 100, 100);
}

Related

How to set a custom font size on a widget that adapts accordingly after an application font size change?

I am using Qt4 (I know), and have a custom widget that sets a bold font, with a point size that is 1.5 times the point size of the application font. This works without problems.
The problem now is that in case the application font size is changed, the widget's font size is not updated accordingly (as expected). My initial though was to do something along the following lines:
void MyCustomWidget::changeEvent(QEvent* e)
{
if (e->type() == QEvent::FontChange)
{
setFont(boldAndBigFont());
}
return QWidget::changeEvent(e);
}
This does not work, since the setFont() call will trigger a FontChange event resulting in endless calls to the change event handler. I noticed there is also ApplicationFontChange, which is promising, however that event is not delivered to my custom widget (I verified using an event listener). Looking at the Qt code, the code responsible for propagating the ApplicationFontChange event will only deliver this event to a few select widgets (the main window for example).
So my question is; how to solve this in a nice way? One limitation I have is that I cannot use style sheets.
My current solution leans towards a custom font change event, fired from the main window after receiving ApplicationFontChange, but surely, I cannot be the first person to have this problem...?
Update: I found that calling QApplication::setFont(bigAndBoldFont(), "MyCustomWidget"); works as well. I do not particularly like it since I would rather keep this styling behavior tied to the implementation of the custom widget.
I can't vouch for Qt4 but the following changeEvent implementation appears to work as expected with Qt5...
virtual void changeEvent (QEvent *event) override
{
if (event->type() == QEvent::FontChange) {
/*
* Run the default handler for the event.
*/
super::changeEvent(event);
/*
* Now get the application font and create the desired font based on
* that.
*/
auto app_font = qApp->font();
auto desired_font = QFont(app_font.family(), 1.5 * app_font.pointSize(), QFont::Bold);
/*
* If the font we now have is the desired font then fine, otherwise
* set it.
*/
if (font() != desired_font) {
setFont(desired_font);
}
event->accept();
}
super::changeEvent(event);
}

Set custom chipDrawable background to Chip

I want to set custom drawable background to Chip, just like that chip.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.bg_cutom_drawable));
But it is not working.It gives an error
java.lang.UnsupportedOperationException: Do not set the background resource; Chip manages its own background drawable.
It required a chipDrawable. How to create chipDrawable for same. I tried but not able to find out solution.
Please suggest me it would be appreciate.
if you want change background color, you can try:
ChipDrawable chipDrawable = (ChipDrawable)chip.getChipDrawable();
chipDrawable.setChipBackgroundColorResource(R.color.colorPrimary);
Using this code you can generate multicolor chip.
add this code in oncreate() or anywhere in function
// "i" is integer value and it will be unique for every chip. In my case I have put in chip in FOR loop that why "i" is there
Chip chip = (Chip) LayoutInflater.from(getActivity()).inflate(R.layout.item_content_lang_chip, null);
chip.setText(contentLangModels.get(i).getContentDisplay());
chip.setId(i);
chip.setChipBackgroundColor(buildColorStateList(getActivity(),"#1e61d5","#2e2e37"));
chipGrpContentType.addView(chip);
Add below function in your activity
public ColorStateList buildColorStateList(Context context, String pressedColorAttr, String defaultColorAttr){
int pressedColor = Color.parseColor(pressedColorAttr);
int defaultColor = Color.parseColor(defaultColorAttr);
return new ColorStateList(
new int[][]{
new int[]{android.R.attr.state_checked},
new int[]{} // this should be empty to make default color as we want
}, new int[]{
pressedColor,
defaultColor
}
);
}
Do not use the android:background attribute. It will be ignored because Chip manages its own background Drawable
chip document
If someone is using a material chip inside a dialog and getting a crash with same above error then you need to remove background attribute for your dialog set from styles.

C++ GTKMM gui circular dependencies

I have been attempting to write a GTKMM gui application in C++. In my earlier projects in Java I started by making so-called 'Screen' objects which would each contain the layout of, and objects in, different screens. So I tried that in C++ as well, I derived these different Screen objects from the Gtk::Box so that I could easily append them to a Gtk::Notebook.
However I found out that this approach results in circular dependencies, and after a lot of browsing I couldn't find people with other approaches. I currently have a screen to display data retrieved from a database, and wanted to add filters to that.
I managed to allow the swapping of screens by giving each screen a pointer to the Gtk::Notebook they are in, but I hit a roadblock when I couldn't figure out how to make two screens interact with each other (eg. filter the data in another screen).
The general problem appears like this:
Gui.h:
class Gui {
protected:
// Child object pointers.
Gtk::Notebook *m_screens;
DbConnector *m_db;
// Screen object pointers.
MainScreen *m_mainScreen;
FilterScreen *m_filterScreen;
public:
// Constructors & destructor.
Gui();
virtual ~Gui();
};
Gui.cpp:
Gui::Gui() {
// Create application.
auto app = Gtk::Application::create();
// Db connector
m_db = new DbConnector();
// Create & configure window.
Gtk::Window m_window;
// Window configs.....
// Create notebook & screen objects.
m_screens = new Gtk::Notebook();
m_screens->set_show_tabs(false);
m_mainScreen = new MainScreen(*m_screens);
m_filterScreen = new FilterScreen(*m_screens);
// Add notebook to window.
m_window.add(*m_screens);
//Insert pages.
m_screens->append_page(*m_mainScreen);
m_screens->append_page(*m_filterScreen);
// Show all children & run app.
m_window.show_all_children();
app->run(m_window);
}
MainScreen.h:
class MainScreen : public Gtk::Box {
protected:
// Parent notebook pointer.
Gtk::Notebook* parent;
// Child widgets.
Gtk::Button m_toFilterScreenButton = Gtk::Button("To Filter Screen");
// Constructors & desctructor.
MainScreen(Gtk::Notebook& par);
virtual ~MainScreen();
// Methods.
void addFilter(std::string filterText);
void toFilterScreen();
};
MainScreen.cpp:
MainScreen::MainScreen(Gtk::Notebook& par) : parent(&par) {
// Build screen.
// Packing contents.....
// Configure widgets.
// Things like widget border width.....
// Signal handlers.
m_toFilterScreenButton.signal_clicked().connect(sigc::mem_fun(*this, &MainScreen::toFilterScreen));
}
void MainScreen::addFilter(std::string filterText) {
// Add filter
}
void MainScreen::toFilterScreen() {
notebook->set_current_screen(pagenum_of_filterscreen);
}
The problem I ran into now is when the FilterScreen is up, a filter is selected, and that filter should be applied to the MainScreen. The FilterScreen can't reach the MainScreen via the Gui object because that would require the screens to include Gui.h, which would result in a circular dependency. Trying to retrieve the MainScreen from the Gtk::Notebook returns a Widget&, which will tell you a Gtk::Widget has no function called addFilter(std::string filterText);.
Is anybody aware of a pattern I could use that would allow this type of behavior? So far the only option I can think of is one giant class that sets the screens using functions instead of premade objects, which would be far from optimal...
With the advice given by Sam Varshavchik in the comments I made a tiny example app that can handle multiple screens and switch easily. For those interested: source can be found here: ExampleApp

JUCE - Making a New Window

Coming from making single-page applications with the visual WYSISWYG editor in JUCE, I'm having a bit of trouble figuring out how to invoke new windows (outside of the main GUI window). I made a test application that just has a small minimal main GUI that I created with the visual editor. It has a button "Make New Window." My goal is to be able to click that button and have a new window pop up and that this new window is a JUCE "GUI component," (AKA, the graphical / visual GUI editor file). Now, I actually have sort of achieved this, however, its throwing errors and assertions, so it would be great to get a very simple, step-by-step tutorial.
I studied the main.cpp file that the Projucer automatically created in order to get a feel for how they are creating a window. Here's what I did.
1) In my project, I added a new GUI Component (which becomes a class) and called it "InvokedWindow."
2) In my main GUI component class header, I added a new scoped pointer of type InvokedWindow: ScopedPointer<InvokedWindow> invokedWindow;
3) I created a new button in the main GUI editor called "Make New Window" and added this to the handler code:
newWindowPtr = new InvokedWindow; so that any time the button is hit, a new object of type InvokedWindow is created.
4) In the InvokedWindow class, in the constructor, on top of the automatically generated code, I added:
setUsingNativeTitleBar (true);
setCentrePosition(400, 400);
setVisible (true);
setResizable(false, false);
Which I sort of got from the main file of the JUCE application.
I also added a slider to this new window just to add functionality to it.
5) I added an overloaded function to let me close the window:
void InvokedWindow::closeButtonPressed()
{
delete this;
}
So, now when I run the app and click the make new window button, a new window does pop up, but I get an assertion:
/* Agh! You shouldn't add components directly to a ResizableWindow - this class
manages its child components automatically, and if you add your own it'll cause
trouble. Instead, use setContentComponent() to give it a component which
will be automatically resized and kept in the right place - then you can add
subcomponents to the content comp. See the notes for the ResizableWindow class
for more info.
If you really know what you're doing and want to avoid this assertion, just call
Component::addAndMakeVisible directly.
*/
Also, I'm able to close the window once and hit the button in the main GUI to create another instance of a newWindow, but closing it a second time leads to an error:
template <typename ObjectType>
struct ContainerDeletePolicy
{
static void destroy (ObjectType* object)
{
// If the line below triggers a compiler error, it means that you are using
// an incomplete type for ObjectType (for example, a type that is declared
// but not defined). This is a problem because then the following delete is
// undefined behaviour. The purpose of the sizeof is to capture this situation.
// If this was caused by a ScopedPointer to a forward-declared type, move the
// implementation of all methods trying to use the ScopedPointer (e.g. the destructor
// of the class owning it) into cpp files where they can see to the definition
// of ObjectType. This should fix the error.
ignoreUnused (sizeof (ObjectType));
delete object;
}
};
This is all a bit over my head. I was figuring it wouldn't be too bad to be able to create a new window, via a button. A new window that I could edit with the graphical GUI editor, but I'm not able to fully figure it out all on my own, through I did try. Could anyone post a step-by-step guide to doing this the correct way? I did post this at the JUCE forums, but due to my lack of GUI programming, I was unable to understand the solutions posted (my own fault), so I'm hoping to get a very simple guide to this. It would be very much appreciated. Thank you.
I figured it out. I needed to create:
A new GUI component (Remember, this is the visual editor in JUCE)
A class (I called it BasicWindow, based on the JUCE demo code) that acts as a shell to run this new window and holds the GUI component.
A JUCE SafePointer that makes a new object of type BasicWindow whenever the button is clicked and sets the attributes to that window.
Here is my code:
Referring to line 3) Inside the handler section of the button to create the new window:
basicWindow = new BasicWindow("Information", Colours::grey, DocumentWindow::allButtons);
basicWindow->setUsingNativeTitleBar(true);
basicWindow->setContentOwned(new InformationComponent(), true);// InformationComponent is my GUI editor component (the visual editor of JUCE)
basicWindow->centreWithSize(basicWindow->getWidth(), basicWindow->getHeight());
basicWindow->setVisible(true);
Referring to line 2) A .cpp file that defines what the BasicWindow is:
#include "../JuceLibraryCode/JuceHeader.h"
class BasicWindow : public DocumentWindow
{
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BasicWindow)
public:
BasicWindow (const String& name, Colour backgroundColour, int buttonsNeeded)
: DocumentWindow (name, backgroundColour, buttonsNeeded)
{
}
void closeButtonPressed() override
{
delete this;
}
};
And referring to line 1) Make the GUI editor component, which this is easy to do. You just right add a new file in the JUCE file manager. "Add New GUI Component," then visually add all your elements and handler code.
My biggest issue was that I was using a JUCE ScopedPointer, so after deleting the object, the pointer pointing to it wasn't being set back to NULL. The SafePointer does this. If any more explanation is needed, I'm happy to help, as this was terrible for someone with not much GUI development "under his belt."

How to set text below the QToolButton in QT not below the icon

I'm using QToolButton and I set the icon.
Now I want Text "below the QToolButton", "Not below the icon".
Is there any way to achieve this in C++,QT in Linux ?
I've found myself in the same position a while back ago while I was making an application for an embedded Linux system.
I haven't found a straight forward solution (I was searching for a way to achieve it with CSS).
What I ended up doing, was creating a new QWidget (using the designer). Then placing the button in it with a QLabel under it.
Then added a simple static function
static void wdgCustomButton::create(const QString iconPath, const QString text)
{
// create a new button here, create some modification functions for
// text, image and optionally QStyleSheets.
// Call those here (pass the arguments)
// Then return the button
// pseudo code, (not tested):
wdgCustomButton button = new wdgCustomButton( /* could pass a parent */ );
button->setIcon( iconPath ); // function simply calls the ui->button->setIcon
button->setText( text ); // function simply calls the ui->label->setText
return button;
}
And then add those new QWidgets to your pannel using code (maybe someone knows how to get it in the default toolbar, but I haven't searched for that myself yet since I never needed it).
this->menuButtons[menuBtnsCount] = wdgCustomButton::create( ":/Images/Warning.png", "Delete everything" );
this->menuButtons[menuBtnsCount]->setGeometry( QRect( /* size and position here */ ) );
this->menuButtons[menuBtnsCount]->show();
I hope this might give you an idea to fix it in an easy way!
Edit:
I'm sorry, I forgot to add something about the click event. The click event was mainly why I made a QWidget out of it!
I just used the connect function [I belive on the whole button like: connect(this->menuButtons[0], ...]