Custom QLabel returns null when refreshing images? (Or: how to handle file changes for images?)

36 Views Asked by At

I have a bunch of layouts and I'm trying to display two differently sized square images next to each other. My ImageLabel class should watch for file changes (when the image at the specific path is overwritten) and update/refresh the image(s) accordingly. When the application starts, the images are displayed correctly but when one (or more) image file is updated the pixmap returns QPixmap::scaled: Pixmap is a null pixmap.

...
class Ui_MainWindow(QMainWindow):
...
     # Set image and QR code based on path and size
     self.image_label.set_image(IMAGE_PATH, 500)
     ...
     self.qr_label.set_image(QR_PATH, 200)
...

# Create a QLabel that shows an image and watches for file changes.
# When a new image is generated, refresh the displayed image.
class ImageLabel(QLabel):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.watcher = QFileSystemWatcher()
        self.watcher.fileChanged.connect(self.refresh_image)
        self.setAlignment(Qt.AlignCenter)

    def set_image(self, image_path, width):
        self.image_path = image_path
        self.watcher.addPath(image_path)
                
        self.refresh_image(width)

    def refresh_image(self, width):
        pixmap = QPixmap(self.image_path)
        self.setPixmap(pixmap.scaled(width, width, Qt.KeepAspectRatio, Qt.SmoothTransformation))

...

I'm sure it worked before when I only needed to update one image.

I tried adding a timer to make sure the background process is finished before refreshing but it did not help.

Maybe I need an entirely different approach - one that adds a file watcher to each file individually or something?


UPDATE: I tried to isolate it and the following code works as expected. It just doesn't work in context of the rest of my GUI. Must be some other issue then. Oops.

from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QMainWindow, QLabel
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import QFileSystemWatcher, Qt

# Constants
IMAGE_PATH = "image.png"
QR_PATH = "qr.png"

# The main UI of the appication
class Ui_MainWindow(QMainWindow):
    # Setup the UI
    def setup_ui(self, MainWindow):
        self.central_widget = QtWidgets.QWidget(MainWindow)
        
        self.main_layout = QtWidgets.QHBoxLayout(self.central_widget)

        # Create image label        
        self.image_label = ImageLabel()
        self.image_label.setObjectName("imageLabel")
        
        # Create QR label
        self.qr_label = ImageLabel()
        self.qr_label.setObjectName("qr_label")

        # Set image and QR code
        self.image_label.set_image(IMAGE_PATH, 500)
        self.qr_label.set_image(QR_PATH, 200)
        
        self.main_layout.addWidget(self.image_label)
        self.main_layout.addWidget(self.qr_label)
        
        MainWindow.setCentralWidget(self.central_widget)
        
# Create a QLabel that shows an image and watches for file changes.
# When a new image is generated, refresh the displayed image.    
class ImageLabel(QLabel):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.watcher = QFileSystemWatcher()
        self.watcher.fileChanged.connect(self.refresh_image)
        self.setAlignment(Qt.AlignCenter)

    def set_image(self, image_path, width):
        self.image_path = image_path
        self.watcher.addPath(image_path)
        self.width = width
        self.refresh_image()

    def refresh_image(self):
        pixmap = QPixmap(self.image_path)
        self.setPixmap(pixmap.scaled(self.width, self.width, Qt.KeepAspectRatio, Qt.SmoothTransformation))  
    
# Setup the main window and application
if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()

    # Setup main window
    ui = Ui_MainWindow()
    ui.setup_ui(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())
0

There are 0 best solutions below