Dynamic Image Scaling Widget
-
I want to create a widget that resizes the image to fit completely within it's boundaries, keeping aspect ratio.
This is what I am trying.It seems that the resize event is called infinitely, even if I do not actually resize the window. The widget just keeps scaling on its own. Is there a proper solution for creating a scalable image?
class ScalableImageLabel(QLabel): def __init__(self, icon: QIcon, parent=None): super().__init__(parent) self.setFrameStyle(QFrame.StyledPanel | QFrame.Plain) self.setLineWidth(1) self.__icon: QIcon = icon self.__pixmap = self.__icon.pixmap(self.size()) self.setPixmap(self.__pixmap) self.setAlignment(Qt.AlignCenter) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) def sizeHint(self): if self.__pixmap and not self.__pixmap.isNull(): return self.__pixmap.size() return super().sizeHint() def resizeEvent(self, event): self.__pixmap = self.__icon.pixmap(self.size()) self.setPixmap(self.__pixmap) super().resizeEvent(event)This is my grid layout
class GridView: __COLUMNS = 5 def __init__(self, paths: [str]): self.__layout: QGridLayout = QGridLayout() row_index: int = 0 col_index: int = 0 for path in paths: self.__layout.addWidget(ScalableImageLabel(QIcon(path)), row_index, col_index) col_index += 1 if col_index >= self.__COLUMNS: col_index = 0 row_index += 1 def get_grid(self) -> QGridLayout: return self.__layout class MainWindow(QMainWindow): def __init__(self): super().__init__() self.title = "Test" self.setWindowTitle(self.title) win = QWidget(self) paths = ["image1.png", "image2.png", "image3.png", "image4.png", "image5.png"] grid = GridView(paths).get_grid() win.setLayout(grid) self.setCentralWidget(win)I've tried using directly the paint event as well but it is incredibly slow, even for 20 images on display.
-
I want to create a widget that resizes the image to fit completely within it's boundaries, keeping aspect ratio.
This is what I am trying.It seems that the resize event is called infinitely, even if I do not actually resize the window. The widget just keeps scaling on its own. Is there a proper solution for creating a scalable image?
class ScalableImageLabel(QLabel): def __init__(self, icon: QIcon, parent=None): super().__init__(parent) self.setFrameStyle(QFrame.StyledPanel | QFrame.Plain) self.setLineWidth(1) self.__icon: QIcon = icon self.__pixmap = self.__icon.pixmap(self.size()) self.setPixmap(self.__pixmap) self.setAlignment(Qt.AlignCenter) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) def sizeHint(self): if self.__pixmap and not self.__pixmap.isNull(): return self.__pixmap.size() return super().sizeHint() def resizeEvent(self, event): self.__pixmap = self.__icon.pixmap(self.size()) self.setPixmap(self.__pixmap) super().resizeEvent(event)This is my grid layout
class GridView: __COLUMNS = 5 def __init__(self, paths: [str]): self.__layout: QGridLayout = QGridLayout() row_index: int = 0 col_index: int = 0 for path in paths: self.__layout.addWidget(ScalableImageLabel(QIcon(path)), row_index, col_index) col_index += 1 if col_index >= self.__COLUMNS: col_index = 0 row_index += 1 def get_grid(self) -> QGridLayout: return self.__layout class MainWindow(QMainWindow): def __init__(self): super().__init__() self.title = "Test" self.setWindowTitle(self.title) win = QWidget(self) paths = ["image1.png", "image2.png", "image3.png", "image4.png", "image5.png"] grid = GridView(paths).get_grid() win.setLayout(grid) self.setCentralWidget(win)I've tried using directly the paint event as well but it is incredibly slow, even for 20 images on display.
@andrei_cp said in Dynamic Image Scaling Widget:
It seems that the resize event is called infinitely, even if I do not actually resize the window. The widget just keeps scaling on its own.
Print out what the size was and is now in
resizeEvent(). Does it remain the same? Does it grow/shrink continuously? Does it maybe toggle between bigger and smaller? You may need to save the old size or look at the current size --- of the widget or the bitmap --- and if it remains the same or only differs by a tiny amount perhaps you need to not resize again at that point? -
Have you tried QLabel.setScaledContents(), see https://doc.qt.io/qt-6/qlabel.html#scaledContents-prop ?
-
@andrei_cp said in Dynamic Image Scaling Widget:
It seems that the resize event is called infinitely, even if I do not actually resize the window. The widget just keeps scaling on its own.
Print out what the size was and is now in
resizeEvent(). Does it remain the same? Does it grow/shrink continuously? Does it maybe toggle between bigger and smaller? You may need to save the old size or look at the current size --- of the widget or the bitmap --- and if it remains the same or only differs by a tiny amount perhaps you need to not resize again at that point?@JonB Yes. I print the size, and it seems it grows constantly. If I resize the window once, it will just keep resizing forever. Even if I do make a change to not resize if there isn't a big difference between old and new size, the function still seems to be called infinitely and I don't understand why. Shouldn't the resize be called once for every element? There seems to be a recursive call somewhere.
-
@JonB Yes. I print the size, and it seems it grows constantly. If I resize the window once, it will just keep resizing forever. Even if I do make a change to not resize if there isn't a big difference between old and new size, the function still seems to be called infinitely and I don't understand why. Shouldn't the resize be called once for every element? There seems to be a recursive call somewhere.
@andrei_cp
Maybe your resetting the pixmap to a new size inresizeEvent()in turn causes a new size event, and a bit bigger than before? That is the recursion.
In any case I imagine you want to use @friedemannkleint's suggestion, then you only need the label to resize, see if that helps.