【问题标题】:Qt Translucent background causes child widget to be 'imprinted' in parentQt半透明背景导致子小部件在父小部件中“印记”
【发布时间】:2016-01-17 19:20:46
【问题描述】:

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

然后当我切换到“横向”模式时,它确实发生了变化,但原来的“纵向”模式保持不变:

这是我的代码:

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 上问题仍然存在。

【问题讨论】:

    标签: c++ qt qwidget translucency


    【解决方案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 操作系统呢?使用 Qt 5.5.1 的结果比使用 5.3.1 的结果要好一些,这是一个屏幕截图(Mac OS 10.11):

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

    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 版本 Qt 5.3.1。 对于这个 Qt 版本,需要另一个修复(从this 错误报告中提取)。 NB 修复抑制 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 上的工作代码(例如),您必须同时使用这两种技巧。

    【讨论】:

    • 例如QPainter::fillRect
    • 是的,fillRect 用什么?请提供一个最小的工作示例。我假设您正在谈论覆盖MyCartParentWidgetpaintEvent
    • 类似fillRect( rect(), QColor(0, 0, 0, 0) );
    • 不。不工作。我在MyCartParentWidget 中添加了paintEvent 方法,我所做的只是QPainter p(this); p.fillRect( rect(), QColor(0, 0, 0, 0) );。而在resetCartStyle方法中,调用this-&gt;update();之后,我调用了this-&gt;parentWidget()-&gt;update();。结果相同。
    • 在绘制像素图之前,不是针对父绘制事件,而是针对购物车绘制事件。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-30
    • 2018-09-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多