Search code examples
c++qtqgraphicsview

Qt: QWidget with a child on QGraphicsView/QGraphicsScene not working


I'm looking to create a view with a base image in the background and draggable widgets over the top.

The setup I have is like so:

MainWindow::MainWindow(QWidget * parent) : QMainWindow(parent) {
    ui->graphicsView->setScene(new QGraphicsScene(nullptr));
    ui->graphicsView->scene()->addWidget(new BackgroundWidget(nullptr));
}

This works fine. So does:

MainWindow::MainWindow(QWidget * parent) : QMainWindow(parent) {
    ui->graphicsView->setScene(new QGraphicsScene(nullptr));
    BackgroundWidget * bgWidget = new BackgroundWidget(nullptr);
    new ForegroundWidget(bgWidget);
    ui->graphicsView->scene()->addWidget(bgWidget);
}

However, I want to add foreground widgets dynamically, and it doesn't work. What I've noticed is that the following doesn't add the foreground widget at all:

MainWindow::MainWindow(QWidget * parent) : QMainWindow(parent) {
    ui->graphicsView->setScene(new QGraphicsScene(nullptr));
    BackgroundWidget * bgWidget = new BackgroundWidget(nullptr);
    ui->graphicsView->scene()->addWidget(bgWidget);
    new ForegroundWidget(bgWidget);
}

And this adds the foreground widget, but doesn't allow for semi-transparency with the background (which is needed for the project):

MainWindow::MainWindow(QWidget * parent) : QMainWindow(parent) {
    ui->graphicsView->setScene(new QGraphicsScene(nullptr));
    BackgroundWidget * bgWidget = new BackgroundWidget(nullptr);
    ui->graphicsView->scene()->addWidget(bgWidget);
    ui->graphicsView->scene()->addWidget(new ForegroundWidget(nullptr));
}

Any ideas as to why adding a child widget after adding the background widget isn't working? If so, any ideas how to fix it?

Thanks.

EDIT: Corrected some silly typing errors in the code blocks.

Image of the problem

The image is a reduced version of the issue; the widgets are both set to be semi-transparency (alpha at 100 out of 255), yet one widget seems to be above the other. I get this if I add the 'foreground' widget in any way. Below is what I was expecting to get:

Ok version

As I say, if I add them before attaching to the scene, it works fine, but I need to be able to add to the scene at run time.


Solution

  • You have several memory leak problems in your code.

    Depending on BackgroundWidget and ForegroundWidget implementation, you either want

    MainWindow::MainWindow(QWidget * parent) : QMainWindow(parent) {
        ui->graphicsView->setScene(new QGraphicsScene(nullptr));
        BackgroundWidget * bgWidget = new BackgroundWidget(nullptr);
        ForegroundWidget * fgWidget = new ForegroundWidget(bgWidget);
        ui->graphicsView->scene()->addWidget(fgWidget);
    }
    

    or

    MainWindow::MainWindow(QWidget * parent) : QMainWindow(parent) {
        ui->graphicsView->setScene(new QGraphicsScene(nullptr));
        BackgroundWidget * bgWidget = new BackgroundWidget(nullptr);
        ForegroundWidget * fgWidget = new ForegroundWidget(nullptr);
        ui->graphicsView->scene()->addWidget(bgWidget);
        ui->graphicsView->scene()->addWidget(fgWidget);
    }
    

    Complete example:

    #include <QtGui>
    
    class MainWindow : public QMainWindow
    {
    public:
        MainWindow(QWidget *parent = 0) : QMainWindow(parent) {
            QGraphicsView *graphicsView = new QGraphicsView;
            setCentralWidget(graphicsView);
    
            QGraphicsScene *scene = new QGraphicsScene;
            graphicsView->setScene(scene);
    
            QWidget *fgWidget = new QWidget;
            fgWidget->setStyleSheet("background: rgba(255, 0, 0, 100)");
            fgWidget->setMinimumSize(100, 100);
            fgWidget->setMaximumSize(100, 100);
    
            QWidget *bgWidget = new QWidget;
            bgWidget->setStyleSheet("background: rgba(0, 0, 255, 100);");
            bgWidget->setMinimumSize(100, 100);
            bgWidget->setMaximumSize(100, 100);
            bgWidget->move(50, 50);
    
            scene->addWidget(fgWidget);
            scene->addWidget(bgWidget);
        }
    };
    
    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
    
        MainWindow mainWindow;
        mainWindow.show();
    
        return app.exec();
    }
    

    enter image description here

    If you want fgWidget to be parent of bgWidget:

        QWidget *bgWidget = new QWidget(fgWidget);
        ....
        scene->addWidget(fgWidget);
        //scene->addWidget(bgWidget); // don't add it to the scene
    

    enter image description here