1

I have a custom class in which I create a QFrame, with a QGrid Layout, that has a QMainWindow which has a QDockWidget which owns an OpenGLWidget. Now that I have all of that out of the way I can show you what it is like to create the class.

std::unique_ptr<QFrame, std::default_delete<QFrame>> MyProgram::createNewRenderWindow(bool hasFeatures)
{
    QGridLayout *baseLayout = new QGridLayout();
    auto newBaseFrame = std::make_unique<QFrame>(new QFrame);
    auto newRenderView = std::make_unique<RenderView>(hasFeatures);

    newBaseFrame->setFrameStyle(QFrame::StyledPanel);
    newBaseFrame->setFrameShadow(QFrame::Sunken);

    baseLayout->addWidget(newRenderView.release());
    newBaseFrame->setLayout(baseLayout);

    return newBaseFrame;

}

The class RenderView is the class that has a QMainWindow with a QDockWidget that owns an OpenGLWidget. I then set that in a QFrame with a QGridLayout. Once that is returned, I set it in my gui by calling the following in my constructor:

auto mainRenderView = createNewRenderWindow(false);
ui->splitter->addWidget(mainRenderView.release());

The reason, in this case, that I pass false is because my main render view should have no features enabled in it's dock widget. So I set this one to false because it is my main render window. When I create a new render view, I set this argument to true so that I have all the features of a dock widget.

In my program, I have created a way to create more than one render view, essentially, the ability to split the render view into 4 different windows. However, the main render view is always the same. So if the user wants to add two more windows they can. I do this with the following:

std::unique_ptr<QSplitter, std::default_delete<QSplitter>> MyProgram::createNewSplitter(Qt::Orientation orientation)
{
    auto newSplitter = std::make_unique<QSplitter>(new QSplitter);
    auto newTopWindow = createNewRenderWindow(true);
    auto newBottomWindow = createNewRenderWindow(true);

    newSplitter->setOrientation(orientation);
    newSplitter->addWidget(newTopWindow.release());
    newSplitter->addWidget(newBottomWindow.release());

    newSplitter->setSizes(QList<int>({HALFRENDERVIEWSIZE, HALFRENDERVIEWSIZE}));

    return newSplitter;
}

And then I add it to the splitter like this:

auto newWindows = createNewSplitter(Qt::Vertical);

ui->splitter->setOrientation(Qt::Horizontal);
ui->splitter->addWidget(newWindows.release());
ui->splitter->setSizes(QList<int>({HALFRENDERVIEWSIZE, HALFRENDERVIEWSIZE}));

This will split the main view in half, and then add two render windows on the right hand side in another QSplitter. Okay, now that I have explain all of that (hopefully well enough, the program is huge and I don't know how to create a minimal example of this). I can explain the real problem.

I can go from one render view, to two, or to three, or to four if I want to. I can go from four to three or two. However, I cannot go from four to one, three to one, or two to one. And this is a problem with the Copy Constructor as stated in the post I just linked. My first idea, was to extract the main render window from the ui->splitter, assign it to a new object, erase all of the children, and place the extracted main window back into the ui->splitter. However, trying that I quickly learned that once I delete the children from the ui->splitter, I delete the children from the extracted main window.

 void MyProgram::on_actionOne_View_triggered()
{

    auto mainRenderView = std::move(ui->splitter->widget(MAINRENDERINDEX));

    std::cout << mainRenderView.children().count() << " extracted children" << std::endl;

    std::cout << ui->splitter->children().count() << std::endl;
    qDeleteAll(ui->splitter->findChildren<QSplitter*>());
    std::cout << ui->splitter->children().count() << std::endl;
    qDeleteAll(ui->splitter->findChildren<QFrame*>());
    std::cout << ui->splitter->children().count() <<std::endl;

    std::cout << mainRenderView.children().count() << " extracted children" << std::endl;

    ui->splitter->addWidget(mainRenderView.release());


}

The first print statement will print out 2, which tells me that I have successfully extracted the widget that I wanted. I then print out the total number of children that ui->splitter has. Which tells me it has 4 children. I then delete all of the QSplitters and print out the number, which leaves the QFrames, that reports there are two QFrames left. I then delete the QFrames and it reports back 0 children left in the ui->splitter. However, I then print out the children mainRenderView has and it reports back 0. Then it tries to insert the extracted widget into the ui->splitter and crashes the program since there is nothing to insert.

What is the best way to do this? I have toyed with the idea of creating my own copy method, however I have read you just don't do that. Is there anyway to delete all of the children and go back to the starting state that the program launches in?

Sailanarmo
  • 1,139
  • 15
  • 41
  • Never done this myself with Qt but I would expect that you need to use `setParent` on your first child to move it from the splitter to another parent (do not delete your first child). – Eelke Mar 26 '19 at 05:48

0 Answers0