Tips for creating a new window

projucer
gui

#1

I’m looking for tips on for creating a new window with a GUI component. The tutorial on the website is for making a window that you hand-code all the elements for, but I’d like to be able to use the GUI editor in the new window. Maybe a step-by-step guide would be nice. I’ll list what I’ve done so far. I’ve actually gotten to the point of being able to invoke a new window from my app, but there are some assertions and errors popping up here and there that I’m struggling with:

  1. In my project, I added a new GUI Component and called it “NewWindow.”

  2. In my main GUI component class header (an instance of JUCE’s visual editor), I added a new scoped pointer of type NewWindow: ScopedPointer<NewWindow> newWindowPtr;

  3. I created a new button in the main GUI editor called “New Window” and added to the handler code:
    newWindowPtr = new NewWindow; so that any time the button is hit, a new object of type NewWindow is created.

  4. In the NewWindow 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.

  1. I added an overloaded function to let me close the window:

    void NewWindow::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? It would be very much appreciated. Thank you.


#2

The ResizableWindow has already some (optional) child components, e.g. ResizableCorner.
If you inherit the Window, you have to make sure, that these are still handled correctly. That’s why it is intended to only contain one component, set with ResizableWindow::setContentOwned(). So you still can create your GUI component, but inherit it from a “normal” Component, and set it as content to the ResizableWindow.

So in step 4) instanciate a normal ResizableWindow and add the settings and the contentComponent:

ScopedPointer<ResizableWindow> window = new ResizableWindow ("New Window", true);
window->setUsingNativeTitleBar (true);
window->setCentrePosition(400, 400);
window->setVisible (true);
window->setResizable(false, false);
window->setContentOwned (new NewWindow());  // maybe rename that to NewGUI or similar

I hope that makes sense.


#3

I was very poor with my wording (mostly because I used terrible variable and class names since it was just supposed to be a quick exercise to figure out how to invoke a new window), so let me reword a bit of it for the sake of clarity, since I screwed that up initially.

After creating the session from the ProJUCEr, I added a GUI component (MainGUIWindow) so I could use the graphical editor. The next window, I’ll call InvokedGUIWindow, this is the one that is generated via the button click.

In step four, I’m working with the constructor on the InvokedGUIWindow, so based on your quote, I’m supposed to be declaring another scoped pointer there? I currently have only defined one scoped pointer, in the header of the MainGUIWindow and its of type InvokedGUIWindow, but based on your text, I should be declaring another scoped pointer inside the constructor of InvokedGUIWindow?

Basically my end goal is to be able to add a visual GUI editor component through the producer, then add the code needed to actually create this window dynamically, based on users request. I don’t want to make a component where I have to hand-code the details, I want to be able to use the JUCE WYSIWYG editor for all the windows I create.

I apologize for my horrible naming of classes, which probably threw you off, I wouldn’t use such terrible names in a real product. And I really appreciate the help.


#4

No worries, my comment about NewWindow was only, because you started it as a subclass of ResizableWindow, and I wanted to point out, that it should rather be a Component. So I proposed with the changing of parent class to change the name, because that’s what makes legacy code painfull…

I added the ScopedPointer to show, how you are supposed to keep track of the variable, i.e. take the ownership. How this is done in your program is really up to you. So by adding the window you can forget the actual gui. You can always retrieve that with window->getContentComponent().

So much for adding child components to ResizableWindow.

To create a dynamic gui have a look at ComponentBuilder. I was digging once into that for my dynamic layout class, but I ended up doing it by hand, so I can enhanche the factory more easily.
But ComponentBuilder it is the method the projucer uses.

Hope that helps.


#5

Thank you Daniel, I finally got a new screen to pop up with zero assertions and errors. Huge accomplishment for me :slight_smile:

Really appreciate all the help.