0

I have a QScrollArea containing some labels and one of them has a QPixmap. I want that QPixmap within a label to be resizable and I also want to show QScrollBar only when QScrollArea contents go out of viewport, so I would do setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded). The problem I'm having is that whenever QScrollArea has to either show or hide QScrollBar, the application crashes with an output: Process finished with exit code -1073740771 (0xC000041D). That's what will happen if you run code below. When I try doing the same thing within my main application and the rest of my widgets I get: Process finished with exit code -1073741571 (0xC00000FD). I've done some googling and found out that it's a stack overflow (https://www.programmersought.com/article/94146097232/, Process finished with exit code -1073741571), but I have no idea how to fix it nor why is it happening here.Here's the code:

import sys

from PyQt6 import QtGui
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QPixmap
from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QFrame, QScrollArea, QLabel, QSpacerItem, \
    QSizePolicy


class SpecificImageLabel(QLabel):
    def __init__(self, pixmap: QPixmap, parent=None):
        super().__init__(parent)
        self.pixmap = pixmap
        self.setStyleSheet("background-color: green;")
        size_policy = QSizePolicy(QSizePolicy.Policy.Ignored, QSizePolicy.Policy.Expanding)  # Very important!
        # size_policy.setHeightForWidth(True)
        size_policy.setWidthForHeight(True)
        self.setSizePolicy(size_policy)

        if self.pixmap.width() != 0:
            self.pixmap = self.pixmap.scaledToWidth(self.width(), Qt.TransformationMode.SmoothTransformation)

        self.setPixmap(self.pixmap)
        self.setAlignment(Qt.AlignmentFlag.AlignTop)

    def resizeEvent(self, ev: QtGui.QResizeEvent) -> None:
        if self.pixmap is None:
            return
        if self.pixmap.width() != 0 and self.width() != 0:
            displayed_pixmap = self.pixmap.scaledToWidth(self.width(), Qt.TransformationMode.SmoothTransformation)
            self.setPixmap(displayed_pixmap)

    # def heightForWidth(self, width: int) -> int:
    #     return width

    def setPixmap(self, new_pixmap: QPixmap) -> None:
        super().setPixmap(new_pixmap.scaledToWidth(self.width(), Qt.TransformationMode.SmoothTransformation))


class TestWindowUi(QMainWindow):
    def __init__(self):
        super().__init__()

        self.central_widget = QWidget(self)
        self.central_widget_layout = QVBoxLayout(self.central_widget)

        self.track_info_widget = QFrame(self)
        self.track_info_widget_layout = QVBoxLayout(self.track_info_widget)
        self.track_info_widget_layout.setContentsMargins(0, 0, 0, 0)
        self.track_info_scroll_area = QScrollArea(self)
        self.track_info_scroll_area.setWidgetResizable(True)
        self.track_info_scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
        self.track_info_scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
        self.track_info_scroll_area_widget = QWidget(self)
        self.track_info_scroll_area_widget_layout = QVBoxLayout(self.track_info_scroll_area_widget)
        self.track_info_scroll_area_widget_layout.setContentsMargins(0, 0, 0, 0)
        self.track_info_scroll_area_widget_layout.setAlignment(Qt.AlignmentFlag.AlignTop)
        self.track_info_scroll_area.setWidget(self.track_info_scroll_area_widget)

        self.currently_playing_track_image_label = SpecificImageLabel(QPixmap("Path/to/your/image.png"))
        self.currently_playing_track_image_label.setUpdatesEnabled(True)
        self.currently_playing_track_image_label.setAlignment(Qt.AlignmentFlag.AlignTop)


        self.track_info_scroll_area_widget_layout.addWidget(QLabel("Random Title"))
        self.track_info_scroll_area_widget_layout.addWidget(QLabel("Random Info"))
        self.track_info_scroll_area_widget_layout.addSpacerItem(QSpacerItem(20, 40))
        self.track_info_scroll_area_widget_layout.addWidget(self.currently_playing_track_image_label)

        self.track_info_widget_layout.addWidget(QLabel("Track Information"))
        self.track_info_widget_layout.addWidget(self.track_info_scroll_area)

        self.central_widget_layout.addWidget(self.track_info_widget)

        self.setCentralWidget(self.central_widget)

        # self.resize(500, 200)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = TestWindowUi()
    main_window.show()
    sys.exit(app.exec())

(also the resizable label is simplified because I only want it to fit the width of QScrollArea, and show QScrollBar when it goes out of viewport vertically)

N1teShad0w
  • 53
  • 1
  • 5
  • 1
    That's a recursion. `setPixmap()` forces the scrollarea to resize the contents, which causes `resizeEvent()` again, and so on. – musicamante Mar 11 '22 at 19:13
  • @musicamante ohhhhh so that was the recursion, never though of that... I at least managed to prevent it from crashing by adding resize_counter and incrementing it by 1 in resizeEvent, if it got higher than 100 it won't resize and it would reset it back to 0. It's a dirty fix, and I still hear a short "buzz" when it happens (pretty weird, it affects my headphones audio output lol). Is there perhaps a better solution? – N1teShad0w Mar 11 '22 at 19:40
  • Also, I tried slowlyy resizing QScrollArea, in my application the label starts to move without resizing to leave free space for QScrollBar when it will appear, and in this example, when QScrollArea is slowly getting smaller, you can notice that the label is behind QScrollBar for some time. Is it possible to avoid such things, to make the label fill the entire space the whole time and just resize to the right size when the QScrollBar appears/disappears, so that there are not moments when it's behind QScrollBar or leaving that ugly free white space for it? – N1teShad0w Mar 11 '22 at 19:45
  • 1
    Unfortunately, there are no easy solutions for this, as the problem comes from a *conceptual* recursion: the image is resized to fill all available horizontal space, but it's tall enough to require a vertical scroll bar; then the image is resized again because the scroll bar reduces the horizontal space; but the new image is now short enough to *not* require the scroll bar anymore, so it will be resized again to fill the new available space, and we're back to the top. The standard solution for this is to set the scroll bar to always off or on, or eventually *always* make the image narrower. – musicamante Mar 12 '22 at 00:33

0 Answers0