Search code examples
c++qtqframeqpalette

Qt - render QFrame with image as background without using WA_TranslucentBackground


I need to set a QFrame with a background image: https://i.sstatic.net/2I3aG.jpg. 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:

enter image description here

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:

enter image description here

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


Solution

  • 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: http://smages.com/images/pic2016010ata.png

    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

    enter image description here

    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();
    }