QWidget::render() in custom QWidget



  • Hello everyone,

    I made a custom QStackedWidget with the purpose of an animated transition from one widget to another - Slide in and out.

    I had issues with moving the QWidgets directly so I decided to make a screenshot of the new and old widget, show those, and move them with a QParallelAnimationGroup.

    I did this the following way:

        QPoint pNext = widget(slideTo)->pos();
        pNow = widget(iCIndex)->pos();
    
        QPixmap pmCurrent = QPixmap(widget(iCIndex)->size());
        widget(iCIndex)->render(&pmCurrent);
        QPixmap pmSlideTo = QPixmap(widget(slideTo)->size());
        widget(slideTo)->render(&pmSlideTo);
    
        QLabel *lblCurrent = new QLabel(this);
        QLabel *lblSlideTo = new QLabel(this);
        lblCurrent->resize(widget(iCIndex)->size());
        lblSlideTo->resize(widget(slideTo)->size());
        lblCurrent->show(); lblSlideTo->show();
        
        lblCurrent->setPixmap(pmCurrent);
        lblSlideTo->setPixmap(pmSlideTo);
        lblCurrent->raise();     lblSlideTo->raise();
    
        lblCurrent->move(0,0);
        lblSlideTo->move(pNext.x() - iOffsetX, pNext.y()-iOffsetY);
    
        QPropertyAnimation *anCurrent = new QPropertyAnimation(lblCurrent,"pos");
        QPropertyAnimation *anSlideto = new QPropertyAnimation(lblSlideTo,"pos");
        QParallelAnimationGroup *anGroup = new QParallelAnimationGroup;
    ....
    ....
        connect(anGroup, &QParallelAnimationGroup::finished, lblCurrent, &QLabel::deleteLater);
        connect(anGroup, &QParallelAnimationGroup::finished, lblSlideTo, &QLabel::deleteLater);
    
        connect(anGroup, &QParallelAnimationGroup::finished, [=]{
           setCurrentIndex(iNext);
           widget(iNow)->hide();
           widget(iNow)->move(pNow);
           bActive = false;
           emit AnimationFinished();
        });
        anGroup->start();
    

    The problem is, QWidget::render() completely ignores the stylesheet of the cStackedWidget. I applied it with

    ui->cStackedMain->setStyleSheet("cStackedWidget{background-color:white;}");
    

    from the GUI-Class. The white background does not show in the QDesigner, but it is correctly painted when I start the program.

    If I set a global StyleSheet like

    centralWidget->setStyleSheet{background-color:white;}
    

    then render() accepts the white background. However I don't want to/can't use that , because it would overwrite the children of the whole ui.

    From the docu I know, that I have the overwrite the paintEvent in my custom widget class, which I did:

    void cStackedWidget::paintEvent(QPaintEvent *)
    {
        QStyleOption opt;
        opt.init(this);
        QPainter p(this);
        style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
    }
    

    So, I'm kinda lost and out of ideas, if anyone could help me, I would be very grateful.

    If needed/asked for, I'll look in uploading the class so it can be tested easily!?


  • Qt Champions 2016

    @J.Hilk

    Hi
    I think the issue is just who is parent ?
    The stylesheet will affect children so if it works with the custom widget when
    centralWidget->setStyleSheet{background-color:white;}
    has the style so to speak
    then it sounds like your custom is just owned by something not affected and hence its children will no either.

    I use only a single stylesheet on mainwindow. Not pr control as i think it becomes uncontrollable very fast.

    Maybe i misunderstand your issue and what works and what do not work.
    Your paint looks correct :)



  • To add to @mrjj

    @J.Hilk said in QWidget::render() in custom QWidget:

    However I don't want to/can't use that , because it would overwrite the children of the whole ui.

    You can use object name specific stylesheet see id selector in http://doc.qt.io/qt-5/stylesheet-syntax.html#selector-types

    I had issues with moving the QWidgets directly

    I implemented something similar here SelettoreImmagini.h SelettoreImmagini.cpp it's from one of the very first programs I wrote in Qt (a snake game) so it's VERY far from good (and the variable names are in italian) but gives you an idea, basically you keep 1 widget always visible then, you add the widgets that you want to scroll as its children but you never add them to a layout but instead manually resize them to the parent widget, at this point you are free to animate the "pos" property of the child widgets. In the linked example I move 2 QLabels



  • @VRonin @mrjj

    Hi, sorry for the delay, was a crazy weekend on my side. Thanks for the fast replies

    I think I'll have to be more precise with my description.

    First off, you may find a small example project here.

    So, let's say I set a single StyleSheet on the QMainWindow, like this:

    this->setStyleSheet("QMainWindow{background-color:white;}\
                            cStackedWidget{background-color:red;}\
                            QLabel{background-color:blue;}");
    

    I get a exactly what I want, white background/Mainwindow, red Stackedwidget and blue labels.
    As soon as I use render() on the first QWidget of the QStackedWidget. the red is completly ignored, I get the default light grey for the stacked widget and blue QLabels

    When I set the StyleSheet like this:

    this->setStyleSheet("background-color:red;");
    

    Everything is Red but, render() actually captures the QStackedWidget color correctly.

    LineBreak

    As I'm writing this, I actually find the crux of the problem.

    this:

    this->setStyleSheet("QMainWindow{background-color:white;}\
                            cStackedWidget{background-color:red;}\
                            QLabel{background-color:blue;}");
    

    Paints the ui, like I whoud expect it to but its apparently not doing the job thoroughly enough.
    Each "page" of the QStackedWidget is a QWidget, and using the above code paints the QWidgets red as well but not for the QWidget::render() function.

    Using this StyleSheet:

    this->setStyleSheet("QMainWindow{background-color:white;}\
                            cStackedWidget{background-color:red;}\
                            QWidget{background-color:red;}\
                            QLabel{background-color:blue;}");
    

    I see no difference for when the widget is painted, but now QWidget::render actually accepts the red background.

    So, is this a bug ot intended behaviour?


  • Qt Champions 2016

    @J.Hilk
    Super with a sample. +5
    I see what you mean.
    Its a bit odd. So first it accepts the stylesheet but when
    you render an image for slide animation it is
    not applied. I thought it would be exactly the
    same in and render() would just call paint.

    Interesting :)



  • Just realized, that I had still thread still open.

    I'll share how I managed to circumvent the problem. Sadly I haven't found a real solution as of now.

    In the function that makes the screenshot, I added this line just before calling QWidget::render

    this->setStyleSheet("cStackedWidget {background-color:white;}"
                            "QWidget#LiveStatus{background-color:white;}"
                            ...
                            //List of all  QStackedwidget Pages
                            ...
                            "QWidget#FanThreshhold{background-color:white;}");
    

    For some reason I have to set the stylesheet new for each time. Simply setting this once will not work.

    Anyway, I'll mark it as solved,
    unless someone else has a new idea !?



Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.