Qt 半透明背景导致子窗口小部件在父窗口中为 'imprinted'
Qt Translucent background causes child widget to be 'imprinted' in parent
我有一个半透明背景的父容器 (MyCartParentWidget
),我必须在其中绘制一个带有图像背景(this image is in portrait, this image 横向)的子小部件 (MyCart
) ), 也用半透明背景绘制,并且都是 QLabels
。单击一个按钮,子小部件将切换其尺寸 (resetCartStyle
),即从纵向模式变为横向模式,反之亦然。问题是,当它切换时,原始印记会保留下来,即这是处于 'portrait' 模式的原始图片:
然后当我切换到 'landscape' 模式时,它确实发生了变化,但原来的 'portrait' 模式仍然存在:
这是我的代码:
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.
上问题仍然存在
而不是手动 painting/updating,只需调用 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):
因此,图像残留了一个幻影。要获得完全正确的显示,
最简单和最有效的技巧是 hide/show 父部件 before/after 切换:
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 错误报告中删除)。注意,修复 不会 抑制 Qt 5.5.1 的幻影。
void MyCartParentWidget::paintEvent(QPaintEvent *)
{
QPainter p( this );
p.setCompositionMode( QPainter::CompositionMode_Clear );
p.fillRect( this->rect(), Qt::transparent );
}
因此,对于 Mac OS 上具有两个 Qt 版本(5.3.1 和 5.5.1)的工作代码(例如),您必须同时使用这两种技巧。
我有一个半透明背景的父容器 (MyCartParentWidget
),我必须在其中绘制一个带有图像背景(this image is in portrait, this image 横向)的子小部件 (MyCart
) ), 也用半透明背景绘制,并且都是 QLabels
。单击一个按钮,子小部件将切换其尺寸 (resetCartStyle
),即从纵向模式变为横向模式,反之亦然。问题是,当它切换时,原始印记会保留下来,即这是处于 'portrait' 模式的原始图片:
然后当我切换到 'landscape' 模式时,它确实发生了变化,但原来的 'portrait' 模式仍然存在:
这是我的代码:
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.
上问题仍然存在 而不是手动 painting/updating,只需调用 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):
因此,图像残留了一个幻影。要获得完全正确的显示, 最简单和最有效的技巧是 hide/show 父部件 before/after 切换:
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 错误报告中删除)。注意,修复 不会 抑制 Qt 5.5.1 的幻影。
void MyCartParentWidget::paintEvent(QPaintEvent *)
{
QPainter p( this );
p.setCompositionMode( QPainter::CompositionMode_Clear );
p.fillRect( this->rect(), Qt::transparent );
}
因此,对于 Mac OS 上具有两个 Qt 版本(5.3.1 和 5.5.1)的工作代码(例如),您必须同时使用这两种技巧。