Qt 半透明背景(遮罩)

簡述

前些天從嵌入式Linux Qt4 切換到嵌入式Linux Qt5 開發平臺,發現遮罩不能用了,原本半透明的背景變成了黑色,全網找遍資料,沒有特別好的解決方案,無奈自己手擼擼一個,且測親測好用。

測試環境

  • Qt5.6.2
  • Linux 4.1
  • Arm

方案一

透明背景只是顯示在父窗口上,不能遮住整個屏幕,不理想

QFrame *f = new QFrame(this);
f->setGeometry(100,100,100,1280);
f->setStyleSheet("QFrame{background-color: rgba(0,0,0, 177);}");
f->show();

方案二

這種在amr 上不生效,在pc 上沒問題,不過這個是整個QFrame 對象,包括子窗口統一透明處理

#ifndef __arm__

QFrame *f = new QFrame ();
f->setGeometry(200,100,100,1280);
QPalette p = f->palette();
p.setBrush(QPalette::Background, QColor(0,0,0));
f->setPalette(p);
f->setWindowOpacity(0.7f);
f->show();

#endif

方案三

這種和第一種差不多,但是透明背景是用的Dialog
並且 this 的第一個祖先必須是全屏的,否則遮罩(Dialog)顯示區域就是遮罩父對象的區域

// arm pc 都有效
QDialog d(this->topLevelWidget()); //獲得這個窗口最頂層的父對象
//d.setGeometry(300,100,100,1280);
d.setWindowFlags(Qt::FramelessWindowHint); //在arm 上,如果不去掉標題欄,背景會變成黑色
d.setStyleSheet("QDialog{background-color: rgba(0,0,0,50%);}");
d.exec();

方案四

arm linux 有效,pc 未測試,不過應該大同小異,思路如下

  • 截取全屏,用黑色半透明筆刷給圖片上色
  • 根據遮罩的幾何位置,顯示對應圖片的位置
// ShadowFrame.h
#ifndef SHADOWFRAME_H
#define SHADOWFRAME_H

#include <QWidget>

class ShadowFrame : public QWidget
{
    Q_OBJECT

    explicit ShadowFrame(QWidget *parent = nullptr);
    ~ShadowFrame();
public:
    static ShadowFrame *instance();
    //設置遮罩位置和遮罩大小,並刷新遮罩
    void updateShadow();
    void updateShadow(int x, int y, int w, int h);
    void updateShadow(const QRect &rect);

    // QWidget interface
protected:
    virtual void paintEvent(QPaintEvent *event);
    QPixmap mPixmap;
};

#endif // SHADOWFRAME_H

// ShadowFrame.cpp
#include "ShadowFrame.h"

#include <QPainter>
#include "MyDebug.h"
#include <QApplication>
#include <QDesktopWidget>
#include <QScreen>

ShadowFrame::ShadowFrame(QWidget *parent) :
    QWidget(parent)
{
    this->setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
    this->mPixmap = QPixmap(qApp->desktop()->size());
    this->mPixmap.fill(Qt::red);
}

ShadowFrame::~ShadowFrame()
{
}

ShadowFrame *ShadowFrame::instance()
{
    static ShadowFrame w;
    return &w;
}

void ShadowFrame::updateShadow()
{
    QSize size = qApp->desktop()->size();
    updateShadow(0, 0, size.width(), size.height());
}

void ShadowFrame::updateShadow(int x, int y, int w, int h)
{
    updateShadow(QRect(x, y, w, h));
}

void ShadowFrame::updateShadow(const QRect &rect)
{
    this->setGeometry(rect);
    QScreen *screen = QApplication::primaryScreen();
    QPixmap pixmap = screen->grabWindow(0); //截屏全屏
    QPainter p(&mPixmap);
    {
#if 01  // 由於我的應用程序在顯示時旋轉了270度,所以獲取到的圖片是橫向的,需要調整座標並旋轉。沒有這個需求的將編譯選項就改爲 0 可正常使用
        p.save();
        p.translate(pixmap.height(), 0);
        p.rotate(90);
        p.drawPixmap(0,0, pixmap);
        p.restore();
#else
        p.drawPixmap(0,0, pixmap);
#endif
    }
    p.fillRect(mPixmap.rect(), QColor(0, 0, 0, 150)); //黑色半透明筆刷

    update();
}

void ShadowFrame::paintEvent(QPaintEvent *)
{
    QPainter p(this);
    p.drawPixmap(QPoint(0, 0), mPixmap, geometry());
    p.setBrush(Qt::blue);
}

#include "MainWindow.h"

#include <QApplication>
#include <QPushButton>
#include "ShadowFrame.h"

int main(int argc, char *argv[])
{
	QApplication a(argc, argv);
	
    ShadowFrame::instance()->updateShadow();
    ShadowFrame::instance()->show();
    
    QWidget *w = new QWidget(/*ShadowFrame::instance()*/);
    w->setAttribute(Qt::WA_DeleteOnClose);
    //w->setStyleSheet("background-color: rgb(114, 159, 207);");
    w->setGeometry(200, 300, 400, 400);
    
    QPushButton *btn = new QPushButton(w);
    btn->setGeometry(100, 100, 100, 100);
    btn->setText("點我在");
    connect(btn, &QPushButton::clicked, []{
        qDebug("點擊成功");
    });    
    w->show();
    w->raise(); //將窗口置頂
	
	return a.exec();
}

示例圖

示例圖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章