目录
1、不规则异形窗口和控件的代码原理
2、主窗口全透明
3、主窗口半透明(以白里透红为例)
4、不规则异形窗口
5、不规则异形按钮
6、使用样式表实现透明与半透明
步骤①:载入一个QPixmap图片,如果图片中某些位置带有全透明alpha通道,那么QPixmap::mask()就会根据全透明的位置生成掩码(注:生成的掩码类型为QBitmap),然后把掩码设置给QWidget控件,这时QWidget就会变成不规则的异形。
步骤②:这时的QWidget只是异形,背景还是原生的灰色,这时我们只需把前面用到的QPixmap作为背景图设置给QWidget即可。需要注意的是,显然我们应当保证背景图的大小和掩码的大小一致。
注意:一般我们使用的QPixmap图片与我们的窗体或控件,大小是不一致的,这时我们既可以让窗口或控件去适应图片的大小:QWidget.resize(pixmap.size()),也可以让图片去适应窗口或控件的大小:pixmap = pixmap.scaled(widget.size()),具体使用哪种,看你的需求。
设置背景图,推荐使用资源文件与样式表:border-image:url(:pic/a.png),在本文的应用场景中,同样是设置背景图,border-image 比 background-image 更合适,因为border-image会自动把图片拉伸充满控件,而background-image会把图片保持为原大小。
给不同控件设置背景图,QPushButton、QLabel等各有不同的方法,例如QPushbutton::setIcon()、QLabel::setPixmap(), QLabel::setPicture(),用起来不具备通用性,只有样式表是通用的。
如果背景图的显示效果,无法满足你的需求,请自行百度搜索:《QT实现背景图片多种填充方式:居中、平铺、缩放、拉伸》
直接在UI的主窗口中,拖出几个控件,下图我放置了一个QPushButton按钮、QCheckBox复选框、设置了蓝色背景的QWidget。
然后用代码设置主窗体的透明:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
setWindowFlags(windowFlags() | Qt::FramelessWindowHint);//无边框
this->setAttribute(Qt::WA_TranslucentBackground, true);//窗体背景全透明
// setWindowOpacity(0.5);//这行代码会使主窗体及其所有的子控件整体半透明,见下图右
}
MainWindow::~MainWindow()
{
delete ui;
}
运行效果如下,左图所示。
可以看到,整个窗体背景实现了完全透明,只有控件是不透明的。如果我们设置了整体半透明(也即这行代码:setWindowOpacity(0.5)),那么控件窗口与控件都会呈现半透明,效果如上图右图所示。
总结:由上述示例代码可见,实现主窗体全透明,必须要同时做以下2项,缺一不可:①设置窗口无边框,②设置背景全透明
本文由【暴躁的野生猿】发表于CSDN,非法转载请帮忙举报谢谢。
只需覆盖QWidget的paintEvent函数即可:
void MainWindow::paintEvent(QPaintEvent*event)
{
QPainter p(this);
//边框黑色不透明 (因为设置了窗体无边框,这行代码可能没有效果)
p.setPen(QColor(0, 255, 0, 255));
p.setBrush(QColor(255, 0, 0, 150));//填充红色半透明
p.drawRect(this->rect());//绘制半透明矩形,覆盖整个窗体
QWidget::paintEvent(event);
}
效果如下所示,代码原理就是,在主窗体背景全透的基础上,在主窗体上绘制了一个与之等大的半透明矩形。
总结:由上述示例代码可见,实现主窗体半透明,必须要同时做以下2项,缺一不可:①设置窗口无边框,②设置背景全透明,③覆盖QWidget的paintEvent函数并写半透明代码。
准备一张带透明通道的PNG图片,(不会PS制作PNG的朋友可以用光影魔术手制作),下面我的示例中,我准备了2张PNG图片分别如下所示,其中第一张:局部全透明、整体半透明,第二张:局部全透明、其余位置不透明。
然后在设计师界面随意拖出两个控件。
#include "form.h"
#include "ui_form.h"
#include
#include
#include
#include
Form::Form(QWidget *parent) :
QWidget(parent),
ui(new Ui::Form)
{
ui->setupUi(this);
this->setWindowFlags(Qt::FramelessWindowHint);//设置窗体无边框
this->setAttribute(Qt::WA_TranslucentBackground);//设置窗体全透明
pix.load(":/pic/qt2.png");//从资源文件载入图片
pix = pix.scaled(size());//把载入的PNG图片缩放到与窗体一样大
}
void Form::paintEvent(QPaintEvent *e)
{
Q_UNUSED(e)
QPainter painter(this);//画笔以this窗体作为画布
painter.drawPixmap(0, 0, pix);//从(0,0)开始在画布上绘制PNG图片
}
有上述代码可见,要实现不规则窗体,原理无非就是,先把窗口弄成全透明,然后在全透明的这个画布上绘制PNG图片。
可以看到,窗体整体呈现为不规则形状,而且透过上图的QT空心位置,可以点击到后面的文件,说明窗口真的是空心的。
如下所示,随意拖出两个控件:一个QPushButton,一个QLabel。在本例中,给这2个控件设置异形,我将演示两种不同的方案:①让控件自适应图片的大小,②让图片自适应控件的大小.。这两种方案分别呈现的效果见下文图片。
素材为:,这种带透明通道的简易图形素材,用wps/word配合光影魔术手,很容易制作。
QPixmap arrowPix(":/pic/arrow.png");//从资源文件载入图片
ui->pushButton->resize(arrowPix.size());//把按钮调整为和图片一样大
ui->pushButton->setMask(arrowPix.mask());//根据alpha通道生成掩码,掩码让控件形成不规则形状(该行不会添加背景图)
ui->pushButton->setStyleSheet("background-image或border-image: url(:/pic/arrow.png)");//给按钮设置背景图
arrowPix = arrowPix.scaled(ui->label->size());//把图片调整为和控件一样大
ui->label->setMask(arrowPix.mask());
ui->label->setStyleSheet("border-image: url(:/pic/arrow.png);");
效果:
所谓顶级窗口,就是其parent是nullptr的QWidget或其子类。
如果控件不是顶级窗口,直接使用样式表,就能实现各种透明和半透明。
如果控件是顶级窗口,要想用样式表实现透明或半透明效果,则必须做以下4项工作,缺一不可:① 无边框, ②背景全透, ③设置qss ,④覆盖painterEvent
XXX::XXX(QWidget *parent) : //构造
QWidget(parent)
{
setWindowFlags(windowFlags() | Qt::FramelessWindowHint);//无边框
this->setAttribute(Qt::WA_TranslucentBackground, true);//窗体背景全透明
this->setStyleSheet("border:none; background-color: rgba(255,0,0,200);");//设置样式表
}
/*继承了QWidget的控件,要使用qss,必须覆盖该函数*/
void XXX::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event)
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
样式表语法支持alpha通道:
任意一个QWidget,都可以直接设置:
background-color: rgba(10,20,30,40);
rgba的4个参数分别为Red Green Blue Alpha(0 =全透, 255=不透)
对于自己写的继承QWidget的子类,要使用样式表,必须要覆盖painterEvent,这是官方手册要求的,直接抄就行了: