1

I need to set a QFrame with a background image: https://i.stack.imgur.com/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.

Community
  • 1
  • 1
SexyBeast
  • 7,913
  • 28
  • 108
  • 196

2 Answers2

4

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();
}
Evgeny
  • 3,910
  • 2
  • 20
  • 37
  • Thanks. I will verify this. Can you provide a screenshot of your application as per this code? – SexyBeast Jan 06 '16 at 21:39
  • I think the problem you have is that label size and image size is differs. So I have update my answer with scaled image support. You don't need scale your label, but you should set mask with scaled pixmap. Try this. – Evgeny Jan 07 '16 at 07:49
  • That's odd. I still have the exact same problem. Which version of Qt are you testing with? Mine is 5.3.1, 32 bit, on OS X, Yosemite. The aspect ratio may distort the image, but that should not have any effect on the background being set like you said. – SexyBeast Jan 07 '16 at 08:19
  • By the way, your solution is not fully accurate, the background is fairly visible around the bottom and right edges, not as smooth as using `WA_TranslucentBackground`. This is the smoothness I need to achieve: http://stackoverflow.com/a/31010821/1469954 – SexyBeast Jan 07 '16 at 08:26
  • This is in Windows with Qt 5.5.1 – Evgeny Jan 07 '16 at 09:15
  • I was mistaken, the previous solution works like a charm on Windows (you can restore that solution as well for future reference for viewers), and on Mac, while this one will work, I can use `WA_TranslucentBackground`, i.e the authentic way to make it work. Thanks a lot! – SexyBeast Jan 09 '16 at 11:30
  • While we are at it, can you tell me how to draw a completely transparent `QFrame`/`QWidget` in Windows without `WA_TranslucentBackground`, i.e. with no image or anything as background, just transparent? I tried setting a blank `pixmap` and adding `setStyleSheet("background: transparent")`, it still shows up with a greyish white/black background rectangle. I can edit the question to include this a well (even though it was not originally mentioned). – SexyBeast Jan 09 '16 at 11:30
  • In translucent window, even though the widget is there, it can be seen through and the background can be touched, i.e as if the widget is not there at all. I don't need that use case, I just want it to be transparent.. – SexyBeast Jan 09 '16 at 11:59
  • @AttitudeMonger I had restored second solution in my answer. Also if you like this answer pleas mark it as valid. – Evgeny Jan 10 '16 at 07:07
  • Did that. Can you tell me is there any way a completely transparent window (no background image or anything) an be drawn in Windows? – SexyBeast Jan 10 '16 at 07:21
  • Afaik, this is impossible. This can be done on OS X. – Evgeny Jan 10 '16 at 07:24
  • With the `setMask`, you said that only those parts of the widget will be visible whose corresponding part is visible in the image. By that logic, why isn't the entire widget invisible when there is no image at all? – SexyBeast Jan 10 '16 at 07:27
  • Are you sure that this works for all images? I tried with this image on Windows: http://imgur.com/rf5d4cj, I am seeing white rounded outline at the rounded corners.. – SexyBeast Jan 16 '16 at 17:45
  • I think it should. But also I think that the best way is prepare mask separatly from image. Save pixmac.mask() to disk, open with image editor and make fixes. Then use this image as mask instead of pixmap.mask(). – Evgeny Jan 17 '16 at 09:14
  • How do I make fixes? The image itself is coming here with a white background around the corners.. – SexyBeast Jan 17 '16 at 11:59
1

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),

Alexander V
  • 8,351
  • 4
  • 38
  • 47
  • Umm, no. I said that the widget has to be a QFrame, so cannot set pixmap like that.. – SexyBeast Dec 19 '15 at 15:46
  • You can also make the frame corners round. – Alexander V Dec 19 '15 at 15:48
  • Just realized: QLabel is QFrame. You can create QLabel and assign the address of it to QFrame*. – Alexander V Dec 19 '15 at 15:50
  • Oh darn. I never knew that. I always thought `QLabel` inherits from `QWidget`. Trying it.. – SexyBeast Dec 19 '15 at 15:54
  • Strange. I made my widget inherit from QLabel instead of QFrame, and now the code is `setPixmap(QPixmap("ipad.png")); setWindowFlags(Qt::FramelessWindowHint);`. Removed setting stylesheets and all other things mentioned in question. Now I just get a rectangular widget with grey background! – SexyBeast Dec 19 '15 at 16:24
  • I am curious and will try some time later. – Alexander V Dec 19 '15 at 16:38
  • Okay, that was a formatting error. The image is coming now, but it looks the same as stated in the question - http://stackoverflow.com/questions/30965022/qframe-with-background-image-and-otherwise-transparent-background. And setting `background-color: none;` makes the edges black, as stated in this question.. In any case, the colored edges remain. :( – SexyBeast Dec 19 '15 at 17:32
  • The problem resolved by applying setAttribute(Qt::WA_TranslucentBackground, true); Now I guess you wonder how to make the window movable etc. but that is a separate question. – Alexander V Dec 19 '15 at 18:53
  • Umm not really. The question clearly states that using `Qt::WA_TranslucentBackground` makes it look as expected, but I cannot use it for reasons I stated in question, so I need another way of doing the same... – SexyBeast Dec 19 '15 at 19:14
  • I actually faced similar issue with WA_TranslucentBackground and the content of some child widgets was just black. The problem is solved with: setStyleSheet("background-color: rgba(255, 255, 255, 255);"); I updated my answer. Just a bit unsure whether applying that to global scope is sufficient but it should be. – Alexander V Dec 20 '15 at 03:05
  • QWidget::paintEvent() – Alexander V Jan 04 '16 at 02:59
  • Umm, yes, `paintEvent` is something I have already tried in conjunction with `WA_TranslucentBackground`. That is what which causes the problem to begin with. How do you propose to make it work with `paintEvent` without using `WA_TranslucentBackground`? – SexyBeast Jan 04 '16 at 04:16
  • http://stackoverflow.com/questions/1644514/qt-painting-without-clearing-the-background – Alexander V Jan 04 '16 at 06:29
  • Okay, there is a solution posted to my problem here: http://stackoverflow.com/questions/30965022/qframe-with-background-image-and-otherwise-transparent-background. You mean to say, I should remove the `WA_TranslucentBackground` property setting and call `setBackgroundMode` with `Qt::NoBackground`? – SexyBeast Jan 04 '16 at 07:49
  • That is what I meant and your question was already answered? Why then you asked that again? – Alexander V Jan 04 '16 at 19:05
  • No it wasn't answered exactly. Originally I asked how to draw the iPad image just a standalone widget, and learnt it can be done by using `WA_TranslucentBackground`. Then while using it I found out that the OpenGL issue with `WA_TranslucentBackground` is a known one, so I need a different solution. I asked the question in a comment there, no solution could be obtained, so because it is a known issue, I thought it warrants another question. – SexyBeast Jan 05 '16 at 00:24
  • Oh, I see. With QML window, for instance, that uses OpenGL for drawing, we use a container widget to embed it and avoid issues of intersecting with the rest of widgets. Maybe you could find a solution to your problem in a similar manner. – Alexander V Jan 05 '16 at 00:33
  • Okay. I am trying the `Qt::NoBackground` solution now. Will come back with the results.. – SexyBeast Jan 05 '16 at 00:40
  • It doesn't work as expected. I mean, the sub widget is displaying correctly, but the iPad image is not coming transparently, a white background is coming ai its sides, just like as shown in the image provided in the question. FYI, I did not find any enum `Qt::NoBackground`..so I am using `Qt::TransparentMode`... – SexyBeast Jan 05 '16 at 01:10