Qt - render QFrame with image as background withou

2019-08-05 09:13发布

问题:

I need to set a QFrame with a background image: http://imgur.com/RnSghvV. This is what I tried:

setAutoFillBackground(true);
setWindowFlags(Qt::FramelessWindowHint);
setStyleSheet("background: transparent;");
QPalette p = this->palette();
p.setBrush(QPalette::Base, QPixmap("ipad.png"));
this->setPalette(p);

This is what I am getting:

As you can see, there is an annoying black frame along the edges, which I want to remove, and view just the image. How do I do that?

P.S, it is possible to make it work by using the property Qt:: WA_TranslucentBackground, as seen here. However, in my case, the QFrame will contain other subwidgets, some of them being QImages rendered through OpenGL, and setting Qt:: WA_TranslucentBackground renders those images invisible on Windows. So I am looking for a solution which does not use this property.

Edit:

Based on a solution proposed by Evgeny, I tried this (I used 325 by 400 as dimensions for the widget because those are the dimensions of the image):

#include <QApplication>
#include <QLabel>
#include <QBitmap>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QLabel l;
    l.setWindowFlags(Qt::FramelessWindowHint);
    QPixmap p(":/img/ipad.png");
    l.setPixmap(p);
    l.setScaledContents(true);
    l.resize(300, 500); //just to test my idea
    l.setMask(p.scaled(l.width(),l.height(),Qt::IgnoreAspectRatio,
    Qt::SmoothTransformation).mask());
    l.show();
    return a.exec();
}

With this, it appears like this:

The right side and bottom are still showing grey background. If I add setStyleSheet("background: transparent"), the grey background becomes black.

回答1:

Ok, I finally got a completely working example with use of setMask. The main problem is that your image has extra space at the border. This is the problem for OSX. At windows it works fine with original image, but for mac I had cut it. You can get it here:

Then I could get working example on mac with QFrame.

At .h file:

#include <QFrame>
#include <QPixmap>

class TestFrame : public QFrame
{
    Q_OBJECT
public:
    TestFrame(QWidget* p = 0);

protected:
    void resizeEvent(QResizeEvent* e) override;

private:
    QPixmap _pix;
};

At .cpp file:

#include <QBitmap>

TestFrame::TestFrame(QWidget *p) :
    QFrame(p, Qt::FramelessWindowHint | Qt::WindowSystemMenuHint),
    _pix(":/img/i2.png")
{
    QPalette pal = palette();
    pal.setBrush(QPalette::Background, QBrush(_pix));
    setPalette(pal);
    resize(_pix.width(), _pix.height());
}

void TestFrame::resizeEvent(QResizeEvent *e)
{
    QFrame::resizeEvent(e);
    setMask(_pix.scaled(size()).mask());
}

Here is screenshot on OS X

The second solution is use QLabel instead of QFrame like this:

#include <QApplication>
#include <QLabel>
#include <QBitmap>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QLabel l;
    l.setWindowFlags(Qt::FramelessWindowHint);
    QPixmap p(":/img/ipad.png");
    l.setPixmap(p);
    l.setScaledContents(true);
    l.resize(300, 500); //just to test my idea
    l.setMask(p.scaled(l.width(),l.height(),Qt::IgnoreAspectRatio,
    Qt::SmoothTransformation).mask());
    l.show();
    return a.exec();
}


回答2:

The foreground image on main window (in our case with transparency bits) can be applied like that:

#include "mainwindow.h"
#include <QLabel>
#include <QPixmap>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent, Qt::FramelessWindowHint)
{
    setAttribute(Qt::WA_TranslucentBackground, true);
    setStyleSheet("background-color: rgba(255, 255, 255, 255);"); // preventing child widgets from not being drawn

    QLabel* pImageLabel = new QLabel;
    QPixmap pixmap(":/RnSghvV.png");
    pImageLabel->setPixmap(pixmap);

    setCentralWidget(pImageLabel);
}

And QLabel is derived from QFrame, so it can be applied in that same placeholder. Mind that having the main program window you need also to apply setAttribute(Qt::WA_TranslucentBackground, true),