Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JUCE - Making a New Window

Tags:

c++

juce

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.

like image 517
joe_04_04 Avatar asked May 04 '17 00:05

joe_04_04


1 Answers

I figured it out. I needed to create:

  1. A new GUI component (Remember, this is the visual editor in JUCE)
  2. 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.
  3. 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."

like image 172
joe_04_04 Avatar answered Nov 15 '22 19:11

joe_04_04