Solved Scaling issue with high res QPixmaps in QGridLayout
-
Hi,
I'm building a chess application in C++ Qt, and I'm having some issues with QPixmap scaling and high resolution.
The general outline of my GUI: The chess board is a QGridLayout containing a 64 instances of a class called SquareWidget, which inherits from QLabel. Each SquareWidget has a pixmap (black or white square, which is sometimes highlighted in various ways), as well as some mouseEvents to handle performing moves. Each SquareWidget also has an inner layout in which I place the PieceWidgets, which also inherit from QLabel. I currently replace the pixmap of the PieceWidget with the square pixmap from the square under the piece when the user picks up a piece to drag it to a new square (and create a new PieceWidget under the user's mouse). I delete the PieceWidget from its original location after the user has completed the move.
My issue: I can't get the pixmaps in the SquareWidgets pixmaps to look correct when changing the window size. Each square should be resizable to as small as 50x50 px, while still looking good. The square image sources are 1000x1000 px.
If I set the pixmap size inside SquareWidget to 50x50 with this code:
this->setPixmap(_square_pixmap.scaled(50, 50, Qt::KeepAspectRatio)); this->setScaledContents(true);
the result is a low quality board:
However, if I set the size to 1000x1000, the widgets will not be scaled down when resizing the window:
this->setPixmap(_square_pixmap.scaled(1000, 1000, Qt::KeepAspectRatio)); this->setScaledContents(true);
but the quality of the squares looks good:
The pixmaps of the squares during moves with the PieceWidgets inside the inner layout in the SquareWidgets, using basically the same code (inside the PieceWidget class):
this->setPixmap(_piece_pixmap.scaled(1000, 1000, Qt::KeepAspectRatio)); this->setScaledContents(true);
Here, the origin square (d2) has the high resolution that I want for all squares at all times.
Has anyone got a good tip for how I can achieve this?
Thanks beforehand!
-
I don't quite understand that... What is SquareWidget and what is PieceWidgets?
But QLabel is not good at smooth scaling.
How about use a simple QWidget instead of QLabel, and set stylesheet to it?
Does your pixmap have a resource url?And if you want a original resolution for all squares.
Can't you just set a orignal size pixmap and not scale contents? -
@Bonnie said in Scaling issue with high res QPixmaps in QGridLayout:
I don't quite understand that... What is SquareWidget and what is PieceWidgets?
But QLabel is not good at smooth scaling.
How about use a simple QWidget instead of QLabel, and set stylesheet to it?
Does your pixmap have a resource url?And if you want a original resolution for all squares.
Can't you just set a orignal size pixmap and not scale contents?SquareWidgets and PieceWidgets are custom classes that inherit from QLabel. I don't want original resolution though. I want the pixmaps to look good when downscaled from 1000x1000 px to anything between 50x50 to 250x250 px.
The scaling looks good in the d2 square in the lower image (which is a PieceWidget in a layout inside a SquareWidget, i.e. it has automatically scaled to its parent in some way, without becoming pixelated), which leads me to think that there is some way to achieve the same scaling for the other squares.
How would one go about setting style sheets? I need to be able to create a piecewidget at the mouse cursor, so I don't know if that would be an optimal solution for the pieces, but maybe for the squares.
-
@Volde
Hi
Just as a note
You are using
QPixmap QPixmap::scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio, Qt::TransformationMode transformMode = Qt::FastTransformation) const
and default its FastTransformation so try with
this->setPixmap(_piece_pixmap.scaled(1000, 1000, Qt::KeepAspectRatio, Qt::SmoothTransformation));also
this->setScaledContents(true);
tends to make it blocky so maybe not use that and scale exactly to the size needed. -
@mrjj said in Scaling issue with high res QPixmaps in QGridLayout:
@Volde
Hi
Just as a note
You are using
QPixmap QPixmap::scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio, Qt::TransformationMode transformMode = Qt::FastTransformation) const
and default its FastTransformation so try with
this->setPixmap(_piece_pixmap.scaled(1000, 1000, Qt::KeepAspectRatio, Qt::SmoothTransformation));also
this->setScaledContents(true);
tends to make it blocky so maybe not use that and scale exactly to the size needed.Thanks for your reply. I managed to solve it with a bit of a (slightly ugly) workaround thanks to your tips. Removing setScaledContent didn't really do anything. However, FastTransformation removed the "blocky" effect on the pixmaps. There was still the issue of having it be many different sizes though, so my workaround was to manually change the SquareWidget sizes for each resizeEvent of the parent widget (which contains the QGridLayout with 10*10 grids including the col/row labels):
for(auto square: emit getSquareWidgets()){ square->setSquareScaleFactor(std::min(this->width()/10, this->height()/10)); square->populateWithPixmap(); }
inside the resizeEvent and
void SquareWidget::setSquareScaleFactor(int size){ _square_scale_factor = size; } void SquareWidget::populateWithPixmap(){ this->setPixmap(_square_pixmap.scaled(_square_scale_factor, _square_scale_factor, Qt::KeepAspectRatio, Qt::SmoothTransformation)); }
inside the SquareWidget did the trick.
This is of course very computationally heavy, but the user will hopefully not resize the window that often.