PDA

View Full Version : Display image in Qt with rounder corners



Cupidvogel
20th November 2015, 02:34
I need to display an image in Qt with curved corners. This is the obvious thing I have tried:



QPixmap pix(":/1.png");
fLabel->setPixmap(pix);
fLabel->setStylesheet("border-radius: 5px;");


And it does not work. I came across a discussion https://forum.qt.io/topic/6880/image-with-radius-in-qml/6. It suggests a complicated solution which seems to work according to OP. However, we are not using QML in our code, so we are resigned to using stylesheets only. Is there any non-QML way to do what the code in the linked post does in QML? Or is there any other way we can show an image with rounded corners in Qt?

anda_skoa
20th November 2015, 09:15
You could draw a rounded rect into a QBitmap and use that as a mask on the pixmap.

Cheers,
_

Cupidvogel
20th November 2015, 16:32
Thanks. I tried this. Doesn't work.



QLabel *pic = new QLabel(fParentQframe);
pic->setGeometry(20,3,28,28);
QPixmap pix("<path_to_a_jpeg_image>");
QPixmap scaled = pix.scaled(28,28,Qt::KeepAspectRatio,Qt::SmoothTra nsformation);


QBitmap map(28,28);

QPainter painter( &map );
painter.setPen( Qt::transparent );

QRect rect( 0,0,28,28 );
painter.drawRoundRect( 0, 0, 28, 28,8,8);
painter.drawRoundRect( rect,8,8 );

pix.setMask(map);

pic->setPixmap(scaled);

ars
20th November 2015, 21:20
Hello,

First you should fill your map with 0
map.fill(Qt::color0);
Setting this map to the pixmap would make it completly transparent. Now set the regions that should be visible to 1. Do this by setting the painter brush to Qt::color1 and draw the rounded rectangle with this brush.

painter.setBrush(Qt::color1);
painter.drawRoundRect( 0, 0, 28, 28,8,8);

Last apply the map to the pixmap you set to the label

scaled.setMask(map);
pic->setPixmap(scaled);

In your code, you set the map to pix, but set scaled to the label.

Best regards
ars

Cupidvogel
20th November 2015, 22:50
Thanks. I tried it. Same result.



QLabel *pic = new QLabel(fParentQframe);
pic->setGeometry(20,3,28,28);
QPixmap pix("<path_to_a_jpeg_image>");
QPixmap scaled = pix.scaled(28,28,Qt::KeepAspectRatio,Qt::SmoothTra nsformation);


QBitmap map(28,28);
map.fill(Qt::color0);

QPainter painter( &map );
painter.setBrush(Qt::color1);
painter.drawRoundRect( 0, 0, 28, 28,8,8);


scaled.setMask(map);
pic->setPixmap(scaled);

ars
21st November 2015, 12:54
Hello,

use painter->roundedRect() instead of painter->roundRect(). Sorry for the typo in my previous post. I tried it on my PC and just copied text from your post and modified it :(

Here is my example code:

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QPixmap>
#include <QBitmap>
#include <QPainter>

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);

QPixmap pix(":./picture.png");
QPixmap scaled = pix.scaled(28,28,Qt::KeepAspectRatio,Qt::SmoothTra nsformation);
ui->square->setPixmap(scaled);


QBitmap map(28,28);
map.fill(Qt::color0);


QPainter painter( &map );
painter.setBrush(Qt::color1);
painter.drawRoundedRect( 0, 0, 28, 28,8,8);



scaled.setMask(map);
ui->rounded->setPixmap(scaled);
}

MainWindow::~MainWindow()
{
delete ui;
}


and here is the result of running it:
11528

Best regards
ars

Cupidvogel
21st November 2015, 13:24
He he. No problem. It works. But the rounded corners don't appear rounded like we can see with border-radius on normal elements. Instead they appear like an octagon here with eight sides..i.e the corners are not curved, but slanting down/up straight from one edge to the other. But I guess nothing can be done about it..

ars
21st November 2015, 15:01
Hello,

just looking at the relatively small pictures one could think that only straight lines are cut off. Increasing the size of the picture and the radius we see that the corners are rounded. If you do not like the way roundedRect() works, you could use a user defined polygon instead. With this approach you can create nearly every form you want. As an example, the code below rounds the upper right corner of the image:


QPainter painter( &map );
painter.setBrush(Qt::color1);
#if 0
painter.drawRoundedRect( 0, 0, s,s,radius, radius);
#else
QPolygonF points;
points.append(QPointF(0,0));
points.append(QPointF(s-radius,0));
for(int i=0; i<radius; ++i)
{
double x = s-radius+i;
double y = radius-std::sqrt(radius*radius-i*i);
points.append(QPointF(x,y));
}
points.append(QPointF(s, radius));
points.append(QPointF(s,s));
points.append(QPointF(0,s));

painter.drawPolygon(points);
#endif

scaled.setMask(map);

QPainter scaledPainter(&scaled);
scaledPainter.drawLine(QPointF(s-radius,radius), QPointF(s,radius));
scaledPainter.drawLine(QPointF(s-radius,0), QPointF(s-radius,radius));
ui->rounded->setPixmap(scaled);

It also draws vertical and horizontal lines for the corner radius (just for visualization). In the code above, s is the image size and radius the radius of the rounded corner.

Here is an example with s = 128 and radius=20:
11529

Best regards
ars

Cupidvogel
21st November 2015, 15:07
Ah. That was informative! Thank you mate!

anda_skoa
21st November 2015, 15:39
Btw, load into a QImage, then scale, then convert to QPixmap. Otherwise you have several conversion steps hidden in QPixmap::scaled()

Cheer,
_

Cupidvogel
21st November 2015, 15:41
Sorry, I didn't get you. What did you mean by several steps being hidden

anda_skoa
21st November 2015, 16:19
QPixmap::scaled() will convert to QImage, then scale, then convert back to QPixmap.

Cheers,
_

Cupidvogel
21st November 2015, 16:23
Oh okay. Sure.