[Solved] QSplashScreen using a PNG with transparent areas



  • Should the QSplashScreen class support the use of a PNG with transparent areas?

    My code looks as follows:

    @
    QPixmap aPixmap(":/splash.png");
    aSplashScreen = new QSplashScreen(aPixmap);
    aSplashScreen->setMask(aPixmap.mask());
    aSplashScreen->show();
    @

    Instead of seeing the background in the transparent areas I just seem them white.

    Thank you in advance!



  • If the png is transparent, you will see the widget background (which might be white :-( ).
    You could try making the QSplashScreen object with "transparent background":https://developer.qt.nokia.com/forums/viewthread/1254



  • Did you set the correct window flags?

    @setWindowFlags(Qt::WindowStaysOnTopHint | Qt::SplashScreen)@



  • [quote author="ucomesdag" date="1294872786"]Did you set the correct window flags?
    @setWindowFlags(Qt::WindowStaysOnTopHint | Qt::SplashScreen)@[/quote]

    I double checked the QSplashScreen documentation (clearly test it as well) and it seems to me as if Qt::WindowStaysOnTopHint hint would be optional and Qt::SplashScreen redundant.



  • [quote author="Gerolf" date="1294865945"]If the png is transparent, you will see the widget background (which might be white :-( ).
    You could try making the QSplashScreen object with "transparent background":https://developer.qt.nokia.com/forums/viewthread/1254
    [/quote]

    I've tried to understand how the information in your link relates to QSplashScreen but I'm not sure on what to do. Would you be so kind and explain in more detail on how you think I can make the QSplashScreen object with "transparent background". A small example would be most appreciated.



  • I have in the meantime done some more testing and it is interesting to see what the different in using the
    @aSplashScreen->setMask(aPixmap.mask());@ line makes:

    without using setMask: !http://img407.imageshack.us/img407/738/hc014.png!

    when using setMask: !http://img163.imageshack.us/img163/9548/hc013.png!



  • That has a similar effect, but a mask does not make alpha, it makes transparent or not.

    A top level widget (QSplashScreen is a widget) can be transparent. Sorry, I didn't read the complete article before. Currently I can't test it, but you could play with the following things:

    • setWindowOpacity(xxx);
    • setAttribute(Qt::WA_NoBackground);
    • setAttribute(Qt::WA_NoSystemBackground);
    • setAttribute(Qt::WA_TranslucentBackground);


  • [quote author="Gerolf" date="1294907465"]That has a similar effect, but a mask does not make alpha, it makes transparent or not.

    A top level widget (QSplashScreen is a widget) can be transparent. Sorry, I didn't read the complete article before. Currently I can't test it, but you could play with the following things:

    • setWindowOpacity(xxx);
    • setAttribute(Qt::WA_NoBackground);
    • setAttribute(Qt::WA_NoSystemBackground);
      [/quote]

    Thank you for the additional information but unfortunately it seem not to solve my problem:

    setWindowOpacity(.75);
    Makes the complete widget 75% translucent but does not affect the area using the alpha channel.

    setAttribute(Qt::WA_NoBackground);
    setAttribute(Qt::WA_NoSystemBackground);
    setAttribute(Qt::WA_TranslucentBackground);
    All tree attributes just make the background of the window black and the area involved depends on the use of setMask.



  • what OS you're using?



  • Currently testing on OSX and Windows.





  • if the form transparency is the problem, there wont be difference in using objects.

    [quote author="peppe" date="1294920580"]Use a QLabel instead.

    http://bugreports.qt.nokia.com/browse/QTBUG-12820[/quote]



  • [quote author="peppe" date="1294920580"]Use a QLabel instead.
    http://bugreports.qt.nokia.com/browse/QTBUG-12820[/quote]

    Thank you for the hint! I really seem to have hit bug 12820.

    The following code seems to work as expected:
    @
    QPixmap aPixmap(":/splash.png");
    QLabel* aWidget = new QLabel(0, Qt::FramelessWindowHint|Qt::WindowStaysOnTopHint);
    aWidget->setAttribute(Qt::WA_TranslucentBackground);
    aWidget->setPixmap(aPixmap);
    aWidget->show();
    @

    I'm actually surprised to hit a bug in a rather prominent class like QSplashScreen. As there is no information on when this bug will be fixed it might make sense to vote for it.

    Does someone eventually have a workaround to get this working in a QSplashScreen?



  • I got it working by subclassing QSplashScreen, setting QSplashScreen::setPixmap(QPixmap splash); and setting the mask to the subclass, setMask(QPixmap mask); .

    Splash image with a text display:

    !http://img.mobypicture.com/aa470873918e7804b36e6fb037e5b0b0_view.jpg(screencap)!

    main:
    @QPixmap splashImage(":images/splash.png");
    QPixmap splashMask(":images/splashmask.png");

    customSplashScreen *splash = new customSplashScreen(splashImage);
    splash->setMessageRect(QRect::QRect(7, 253, 415, 14), Qt::AlignCenter); // Setting the message position.

    QFont splashFont;
    splashFont.setFamily("Arial");
    splashFont.setBold(true);
    splashFont.setPixelSize(9);
    splashFont.setStretch(125);

    splash->setFont(splashFont);
    splash->setMask(splashMask);
    splash->setWindowFlags(Qt::WindowStaysOnTopHint | Qt::SplashScreen);
    splash->show();

    /* To intercept mousclick to hide splash screen. Since the
    splash screen is typically displayed before the event loop
    has started running, it is necessary to periodically call. */
    app.processEvents();

    splash->showStatusMessage(QObject::tr("Initializing..."));@

    customSplashScreen.h:
    @#ifndef CUSTOMSPLASHSCREEN_H
    #define CUSTOMSPLASHSCREEN_H

    #include <QSplashScreen>
    #include <QPainter>

    class customSplashScreen
    :public QSplashScreen
    {

    public:
    customSplashScreen(const QPixmap& pixmap);
    ~customSplashScreen();
    virtual void drawContents(QPainter *painter);
    void showStatusMessage(const QString &message, const QColor &color = Qt::black);
    void setMessageRect(QRect rect, int alignment = Qt::AlignLeft);

    private:
    QString message;
    int alignement;
    QColor color;
    QRect rect;
    };

    #endif // CUSTOMSPLASHSCREEN_H@

    customSplashScreen.cpp:
    @#include "customSplashScreen.h"

    customSplashScreen::customSplashScreen(const QPixmap& pixmap)
    {
    QSplashScreen::setPixmap(pixmap);
    };

    customSplashScreen::~customSplashScreen()
    {
    };

    void customSplashScreen::drawContents(QPainter *painter)
    {
    QPixmap textPix = QSplashScreen::pixmap();
    painter->setPen(this->color);
    painter->drawText(this->rect, this->alignement, this->message);
    };

    void customSplashScreen::showStatusMessage(const QString &message, const QColor &color)
    {
    this->message = message;
    this->color = color;
    this->showMessage(this->message, this->alignement, this->color);
    };

    void customSplashScreen::setMessageRect(QRect rect, int alignement)
    {
    this->rect = rect;
    this->alignement = alignement;
    };@



  • [quote author="ucomesdag" date="1295004120"]I got it working by subclassing QSplashScreen, setting QSplashScreen::setPixmap(QPixmap splash); and setting the mask to the subclass, setMask(QPixmap mask); .

    Splash image with a text display:

    !http://img.mobypicture.com/aa470873918e7804b36e6fb037e5b0b0_view.jpg!
    [/quote]

    Thank you very much!
    Your approach look very promising.
    How exactly did you setup (alpha channel) the two images you are using?





  • Do you mind creating a wiki article in the "HowTo":http://developer.qt.nokia.com/wiki/Category:HowTo and/or "Code snippets":http://developer.qt.nokia.com/wiki/Category:snippets category? It would fit very well there!



  • [quote author="Volker" date="1295008017"]Do you mind creating a wiki article in the "HowTo":http://developer.qt.nokia.com/wiki/Category:HowTo and/or "Code snippets":http://developer.qt.nokia.com/wiki/Category:snippets category? It would fit very well there![/quote]

    Will do so!





    • I have an image with an Alpha channel: am I correct in the assumption that the image (splash.png) you've used has no alpha channel and the mask (splashmask.png) is the (1 bit) alpha channel?

    • If the above assumptions are correct I still seem to have problems with the semi-transparent parts of my image. In my case there is a shadow that uses a multibit alpha channel that is not shown correctly.

    • For now I'm only able to show my splash screen properly using the following code:
      @QPixmap aPixmap(":/splash.png");
      QLabel* aWidget = new QLabel(0, Qt::FramelessWindowHint|Qt::WindowStaysOnTopHint);
      aWidget->setAttribute(Qt::WA_TranslucentBackground);
      aWidget->setPixmap(aPixmap);
      aWidget->show();
      @

    • Is there maybe a way to have QSplashScreen show the images in the same way as QLabel does when using the Qt::WA_TranslucentBackground attribute ?

    • Is there maybe a way to to use QLabel as an alternative to QSplashScreen and add something similar to showMessage to the QLabel ?



  • [quote author="Dieter" date="1295332434"]

    • Is there maybe a way to have QSplashScreen show the images in the same way as QLabel does when using the Qt::WA_TranslucentBackground attribute ?[/quote]

    What do you mean? Did you read the BR I posted a link to?

    [quote]

    • Is there maybe a way to to use QLabel as an alternative to QSplashScreen and add something similar to showMessage to the QLabel ?
      [/quote]

    Use an ordinary QWidget with a QVBoxLayout holding two QLabels?



  • [quote author="peppe" date="1295366429"]What do you mean? Did you read the BR I posted a link to?[/quote]
    Absolutely! I'm just trying to find a solution to my specific problem.

    [quote author="peppe" date="1295366429"]Use an ordinary QWidget with a QVBoxLayout holding two QLabels?[/quote]
    I had some problems with the Qt::WA_TranslucentBackground attribute in QWidget but QFrame seems to work as expected and I will very soon post a solution that worked for me.



  • It took me a while but I have finally found a very simple and perfect solution for my problem with semitransparent images using an alpha channel with more then 1 bit.

    It all comes down to use a QFrame with the Qt::WA_TranslucentBackground attribute and emulate the functionality of QSplashScreen.

    I have tried to mimic as much as possible the functionality and apperance of the original QSplashScreen class but left out some methods to keep this example simple.

    • This is the new CSplashScreen class that must be used instead of QSplashScreen:

    @
    class CSplashScreen : public QFrame
    {
    public:
    CSplashScreen(const QPixmap& pixmap);

    void clearMessage();
    void showMessage(const QString& theMessage, int theAlignment = Qt::AlignLeft, const QColor& theColor = Qt::black);

    private:
    virtual void paintEvent(QPaintEvent* pe);

    QPixmap itsPixmap;
    QString itsMessage;
    int itsAlignment;
    QColor itsColor;
    };
    @

    • The methods in CSplashScreen:

    @
    CSplashScreen::CSplashScreen(const QPixmap& thePixmap)
    : QFrame(0, Qt::FramelessWindowHint|Qt::WindowStaysOnTopHint)
    , itsPixmap(thePixmap)
    {
    setAttribute(Qt::WA_TranslucentBackground);
    setFixedSize(itsPixmap.size());
    };

    void CSplashScreen::clearMessage()
    {
    itsMessage.clear();
    repaint();
    }

    void CSplashScreen::showMessage(const QString& theMessage, int theAlignment/* = Qt::AlignLeft*/, const QColor& theColor/* = Qt::black*/)
    {
    itsMessage = theMessage;
    itsAlignment = theAlignment;
    itsColor = theColor;
    repaint();
    }

    void CSplashScreen::paintEvent(QPaintEvent* pe)
    {
    QRect aTextRect(rect());
    aTextRect.setRect(aTextRect.x()+5, aTextRect.y()+5, aTextRect.width()-10, aTextRect.height()-10);

    QPainter aPainter(this);
    aPainter.drawPixmap(rect(), itsPixmap);
    aPainter.setPen(itsColor);
    aPainter.drawText(aTextRect, itsAlignment, itsMessage);
    }
    @

    A simple function to the CSplashSCreen:

    @
    void
    test_SplashScreen()
    {
    class SleeperThread : public QThread
    {
    public:
    static void msleep(unsigned long msecs) {QThread::msleep(msecs);}
    };

    QPixmap aSplashImage(":/splash.png");

    CSplashScreen* aSplashScreen = new CSplashScreen(aSplashImage);
    aSplashScreen->show();

    for (int i = 1; i <= 5; i++)
    {
    aSplashScreen->showMessage(QString("Processing %1...").arg(i), Qt::AlignTop | Qt::AlignLeft, Qt::white);
    SleeperThread::msleep(1000);
    }

    delete aSplashScreen;
    }
    @



  • Before marking this topic as solved, I have now also added a complete example "CSplashScreen":http://developer.qt.nokia.com/wiki/QSplashScreen_replacement_for_semitransparent_images" to the "Code snippets":http://developer.qt.nokia.com/wiki/Category:snippets WiKi.

    Thank you all for all your help!



  • Hi Dieter,

    just one note, I would make the QPainter instance an object on the stack.
    And second: are you sure you want to call the default implementation for the paint event? you do all painting yourselve, don't you?



  • [quote author="Gerolf" date="1295535937"]Hi Dieter,
    just one note, I would make the QPainter instance an object on the stack.
    And second: are you sure you want to call the default implementation for the paint event? you do all painting yourselve, don't you?[/quote]

    I agree (and have already changed the code snippets)




Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.