Custom QIcon using QIconEngine and transparency
Asked Answered
K

1

9

I'm trying to implement something like "composed icon" in Qt.

Target: I need to dynamicaly set color just for the portion of icon.

My idea: Compose this icon by two other. One icon that will be coloured as desired (perhaps by ColorizeEffect) and blend it under second icon that acts as overlay layer.

Issue: I tried QIconEngine and implementing its paint method. ColorizeEffect seems not to be working (even when I try the hack with temporary QLabel for that - when strength is set > 0.0, the QIcon formed by that is empty). But that's not the main problem. The thing is, no matter what I do, I get some default coloured background for this "composed" icon.
Two QToolButtons with QIcons, left icon is simple QIcon, right is my "Composed" icon


Here is fragment of my code:

class QComposedIconEngine: public QIconEngine
{
public:
   QComposedIconEngine();
   ~QComposedIconEngine();
   virtual void paint ( QPainter * painter, const QRect & rect, QIcon::Mode mode, QIcon::State state );
   virtual QIconEngine * clone(void) const;
public:
   QIcon m_qIconA;
   QIcon m_qIconB;
   QColor m_qColor;
};

And here is my implementation of paint(...):

void CLxQComposedIconEngine::paint ( QPainter * painter, const QRect & rect, QIcon::Mode mode, QIcon::State state )
{
   QBrush brush = painter->background();
   QColor color = brush.color();
   brush.setColor( Qt::transparent );
   painter->setBackground( brush );
   painter->eraseRect( rect );
   painter->setCompositionMode( QPainter::CompositionMode_SourceOver );
   m_qIconA.paint( painter, rect, Qt::AlignCenter, mode, state );
};

And here is how I create that "Composed" icon:

QComposedIconEngine * qIconEngine = new QComposedIconEngine();
QIcon i1;
QIcon i2;
i1.addPixmap(...);
i2.addPixmap(...);
qIconEngine->m_qIconA = i1;
qIconEngine->m_qIconB = i2;
QIcon i3( qIconEngine );

I expect i1 and i3 to look exactly the same. And besides the damn background it really is. But I need to make it transparent.

(even when I leave my paint(...) method empty, the damn background is there!)

Does anybody know how to make the background transparent? Thanks.

Kierkegaard answered 18/12, 2014 at 8:9 Comment(2)
Doc of QIconEngine says "use QIconEngineV2". Have you tried that ?Prude
Of course. No effect. Fortunatelly I solved this problem. It is in the way QIconEngine is called from outside. I'm going to compile the answer by myself... :-)Kierkegaard
K
7

I solved this. The problem was, that the reimplemented paint(...) method is almost every time called via pixmap(...) method - which can be reimplemented too. If you leave default implementation, this method creates new QPixmap, creates QPainter on it and calls paint(...) witch this painter. But that is the problem - since the created QPixmap contains no alpha channel it cannot be semi-transparent. So you need to reimplement pixmap(...) method like this:

QPixmap CLxQComposedIconEngine::pixmap ( const QSize & size, QIcon::Mode mode, QIcon::State state )
{   
   QImage img( size, QImage::Format_ARGB32 );
   img.fill(qRgba(0,0,0,0));
   QPixmap pix = QPixmap::fromImage(img, Qt::NoFormatConversion );
   {
      QPainter painter ( &pix );
      QRect r( QPoint(0.0,0.0), size );
      this->paint(&painter, r, mode, state);      
   }
   return pix;       
};

The key are the first two rows... Without the img.fill() it would be not transparent.

Kierkegaard answered 23/12, 2014 at 7:46 Comment(1)
QPixmap pix(size); pix.fill(Qt::transparent);is sufficient, you don't need to make a QImage.Tb

© 2022 - 2024 — McMap. All rights reserved.