简体   繁体   English

Qt半透明背景导致子窗口小部件在父窗口中被“打印”

[英]Qt Translucent background causes child widget to be 'imprinted' in parent

I have a parent container ( MyCartParentWidget ) with translucent background, inside which I have to draw a child widget ( MyCart ) with an image background ( this image is in portrait, this image is in landscape), also drawn with translucent background, and both being QLabels . 我有一个半透明背景的父容器( MyCartParentWidget ),我必须在其中绘制一个带有图像背景的子窗口小部件( MyCart )( 此图像是纵向的, 此图像是横向的),也是用半透明背景绘制的,两者都是是QLabels There is a button clicking on which, the child widget toggles its dimensions ( resetCartStyle ), ie it goes from portrait to landscape mode and vice versa. 点击一个按钮,子窗口小部件切换其尺寸( resetCartStyle ),即从纵向模式切换到横向模式,反之亦然。 Problem is, when it toggles, the original imprint stays back, ie, this is the original pic where it is in 'portrait' mode: 问题是,当它切换时,原始印记保持不变,即,这是原始图片,它处于“纵向”模式:

在此输入图像描述

Then when I switch to 'landscape' mode, it does shift, but the original 'portrait' mode stays back: 然后,当我切换到“横向”模式时,它确实会移动,但原始的“纵向”模式会保持不变:

在此输入图像描述

This is my code: 这是我的代码:

main.cpp: main.cpp中:

#include <QApplication>
#include "MyCartParentWidget.hpp"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MyCartParentWidget p;
    p.move(370,10);
    p.show();
    return a.exec();
}

MyCart.cpp: MyCart.cpp:

 #include "MyCart.hpp"
 #include <QPainter>

MyCart::MyCart(QWidget *parent): QLabel(parent)
{
    setAttribute(Qt::WA_TranslucentBackground);
    fPixMap.load("/Users/attitude/Desktop/RnSghvV.png");
    setStyleSheet("background-color: rgba(0,0,0,255);");
    setFixedSize(325,400);

}

void MyCart::paintEvent(QPaintEvent *)
{
    QPainter p(this);
    p.setRenderHint(QPainter::SmoothPixmapTransform);
    p.drawPixmap(0,0,width(),height(),fPixMap);
}

void MyCart::resetCartStyle(QString url, int w, int h)
{
    setFixedSize(w,h);
    fPixMap.load(url);
    this->update();
}

MyCart.hpp: MyCart.hpp:

#pragma once

#include <QLabel>
#include <QPaintEvent>
#include <QPixmap>


class MyCart: public QLabel
{
public:
    MyCart(QWidget*);
    virtual void paintEvent(QPaintEvent *);
    QPixmap fPixMap;
    void resetCartStyle(QString, int w, int h);
};

MyCartParentWidget.cpp: MyCartParentWidget.cpp:

#include "MyCartParentWidget.hpp"
#include <QPushButton>

MyCartParentWidget::MyCartParentWidget()
{

    setFixedSize(800,700);
    setWindowFlags(Qt::FramelessWindowHint);
    setAttribute(Qt::WA_TranslucentBackground);
    setStyleSheet("background-color: none;");

    fLayout = new QHBoxLayout();
    setLayout(fLayout);
    fLayout->setContentsMargins(0,0,0,0);
    fLayout->setSpacing(0);
    fLayout->setMargin(0);
    fLayout->setAlignment(Qt::AlignLeft | Qt:: AlignTop);
    i = 0;

    fCart = new MyCart(this);
    fLayout->addWidget(fCart);

    QPushButton* p = new QPushButton(this);
    p->setText("Toggle");
    p->move(0,650);
    connect(p,SIGNAL(clicked(bool)),this,SLOT(clickedSlot()));
}

void MyCartParentWidget::clickedSlot()
{
    if (i == 0)
    {
        //enter landscape mode
        i = 1;
        fCart->resetCartStyle("/Users/attitude/Desktop/foo.png",400,325);
    }
    else
    {
        //enter portrait mode
        i = 0;
        fCart->resetCartStyle("/Users/attitude/Desktop/RnSghvV.png",325,400);
    }
}

MyCartParentWidget.hpp: MyCartParentWidget.hpp:

#pragma once

#include <QLabel>
#include <QHBoxLayout>
#include "MyCart.hpp"


class MyCartParentWidget: public QLabel
{
    Q_OBJECT
public:
    MyCartParentWidget();

    QHBoxLayout* fLayout;
    MyCart *fCart;
    int i;

private slots:
    void clickedSlot();
};

This problem does not happen when I set the background of the parent widget to something like green and comment out the setAttribute(Qt::WA_TranslucentBackground); 当我将父窗口小部件的背景设置为green并注释掉setAttribute(Qt::WA_TranslucentBackground);时,不会发生此问题setAttribute(Qt::WA_TranslucentBackground); part, this happens only with setAttribute(Qt::WA_TranslucentBackground); 部分,这只发生在setAttribute(Qt::WA_TranslucentBackground); part. 部分。

How do I fix this? 我该如何解决?

Platform - OS X Yosemite, Qt 5.3.1, 32 bit. 平台 - OS X Yosemite,Qt 5.3.1,32位。

Ilya's solution below works fine on Windows, but the problem persists on Mac. 以下Ilya的解决方案在Windows上运行良好,但问题仍然存在于Mac上。

Instead of painting/updating manually, just call the setPixmap method, the QLabel should manage itself. 而不是手动绘制/更新,只需调用setPixmap方法, QLabel应该自行管理。 The code is working fine, except on Mac OS X : 代码工作正常, 除了在Mac OS X上

MyCart.cpp: MyCart.cpp:

#include "MyCart.hpp"

MyCart::MyCart(QWidget *parent): QLabel(parent)
{
   resetCartStyle("C:/dev/cart/portrait.png");
}

void MyCart::resetCartStyle(QString url)
{
   fPixMap.load(url);
   setPixmap(fPixMap);
}

MyCart.hpp: MyCart.hpp:

#pragma once

#include <QLabel>
#include <QPaintEvent>
#include <QPixmap>


class MyCart: public QLabel
{
public:
    MyCart(QWidget*);
    QPixmap fPixMap;
    void resetCartStyle(QString);
};

MyCartParentWidget.cpp: MyCartParentWidget.cpp:

#include "MyCartParentWidget.hpp"
#include <QPushButton>

MyCartParentWidget::MyCartParentWidget()
{

    setFixedSize(800,700);
    setWindowFlags(Qt::FramelessWindowHint);
    setAttribute(Qt::WA_TranslucentBackground);

    fLayout = new QHBoxLayout();
    setLayout(fLayout);
    fLayout->setContentsMargins(0,0,0,0);
    fLayout->setSpacing(0);
    fLayout->setMargin(0);
    fLayout->setAlignment(Qt::AlignLeft | Qt:: AlignTop);
    i = 0;

    fCart = new MyCart(this);
    fLayout->addWidget(fCart);

    QPushButton* p = new QPushButton(this);
    p->setText("Toggle");
    p->move(0,650);
    connect(p,SIGNAL(clicked(bool)),this,SLOT(clickedSlot()));
}

void MyCartParentWidget::clickedSlot()
{
    if (i == 0)
    {
        //enter landscape mode
        i = 1;
        fCart->resetCartStyle("C:/dev/cart/landscape.png");
    }
    else
    {
        //enter portrait mode
        i = 0;
        fCart->resetCartStyle("C:/dev/cart/portrait.png");
    }
}

So what about Mac OS ? 那么Mac OS呢? The result is a bit better with Qt 5.5.1 than with 5.3.1, here's a screenshot (Mac OS 10.11): 使用Qt 5.5.1比使用5.3.1更好一些,这是一个截图(Mac OS 10.11):

在此输入图像描述

So, there's a ghost of the image remaining. 所以,剩下的是图像的幽灵。 To get to a fully correct display, the simplest and most effective trick is to hide/show the parent widget before/after toggling: 要获得完全正确的显示,最简单和最有效的技巧是在切换之前/之后隐藏/显示父窗口小部件:

void MyCartParentWidget::clickedSlot()
{
    hide();
    if (i == 0)
    {
        //enter landscape mode
        i = 1;
        fCart->resetCartStyle("C:/dev/cart/landscape.png");
    }
    else
    {
        //enter portrait mode
        i = 0;
        fCart->resetCartStyle("C:/dev/cart/portrait.png");
    }
    show();
}

For completeness, below are two other tricks found while searching for a fix, that have fixed the code of the MCV exemple but not the production application. 为了完整起见,下面是在搜索修复时发现的另外两个技巧,它修复了MCV示例的代码,但没有修复生产应用程序。

First trick: 第一招:

MyCart.cpp MyCart.cpp

MyCart::MyCart(QWidget *parent): QLabel(parent)
{
   // do nothing in the constructor
}

MyCartParentWidget.cpp MyCartParentWidget.cpp

MyCartParentWidget::MyCartParentWidget()
{
    ...previous code    

    // add this line...
    QTimer::singleShot( 0, this, SLOT(onclicked() ); // ...to show the widget
}

This code still doesn't work with Qt 5.3.1, the OP's version. 该代码仍然不适用于OP的版本Qt 5.3.1。 For this Qt version, another fix is necessary (lifted from this bug report). 对于这个版本的Qt,另一种解决方法是必要的(从解除这个错误报告)。 NB that fix doesn't suppress the ghost image for Qt 5.5.1. 注意,修复不会抑制Qt 5.5.1的重影图像。

void MyCartParentWidget::paintEvent(QPaintEvent *)
{
    QPainter p( this );    
    p.setCompositionMode( QPainter::CompositionMode_Clear );
    p.fillRect( this->rect(), Qt::transparent );
}

So for a working code (for the exemple) on Mac OS with both Qt versions (5.3.1 and 5.5.1), you have to use both tricks. 因此,对于具有两个Qt版本(5.3.1和5.5.1)的Mac OS上的工作代码(例如),您必须使用这两个技巧。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM