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

时间:2016-01-17 19:20:47

标签: c++ qt qwidget translucency

我有一个半透明背景的父容器(MyCartParentWidget),我必须在其中绘制一个带有图像背景的子窗口小部件(MyCart)(this image是纵向的,{ {3}}在风景中),也是用半透明背景绘制的,都是QLabels。点击一个按钮,子窗口小部件切换其尺寸(resetCartStyle),即从纵向模式到横向模式,反之亦然。问题是,当它切换时,原始印记会保持不变,即这是原始图片,它处于“纵向”模式:

this image

然后,当我切换到“横向”模式时,它确实会移动,但原始的“纵向”模式会保持不变:

enter image description here

这是我的代码:

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:

 #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:

#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:

#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:

#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();
};

当我将父窗口小部件的背景设置为green并注释掉setAttribute(Qt::WA_TranslucentBackground);部分时,不会发生此问题,这只发生在setAttribute(Qt::WA_TranslucentBackground);部分。

我该如何解决这个问题?

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

以下Ilya的解决方案在Windows上运行良好,但Mac上仍然存在问题。

1 个答案:

答案 0 :(得分:1)

不是手动绘制/更新,只需调用setPixmap方法,QLabel应该自行管理。代码工作正常,除了Mac OS X

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:

#pragma once

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


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

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");
    }
}

那么Mac OS呢?使用Qt 5.5.1比使用5.3.1更好一些,这里是截图(Mac OS 10.11):

enter image description here

所以,剩下的是影像的幽灵。要获得完全正确的显示, 最简单和最有效的技巧是在切换之前/之后隐藏/显示父窗口小部件:

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();
}

为了完整性,下面是在搜索修复时发现的另外两个技巧,它修复了MCV示例的代码,但没有修复生产应用程序。

第一招:

MyCart.cpp

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

MyCartParentWidget.cpp

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

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

此代码仍然不适用于OP的5.3版本Qt 5.3.1。 对于这个Qt版本,需要另一个修复(从this错误报告中取消)。注意,修复不会抑制Qt 5.5.1的重影图像。

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

因此,对于具有Qt版本(5.3.1和5.5.1)的Mac OS上的工作代码(例如),您必须使用这两种技巧。