diff --git a/app/gui.py b/app/gui.py index 85f9528..2ae9c0f 100644 --- a/app/gui.py +++ b/app/gui.py @@ -2044,7 +2044,6 @@ class StorePage(QWidget): self._cover_attempted.clear() for loader in self._loaders: loader.cancel() - self._loaders = [] self.grid.clear() self.table.setRowCount(0) self.status.setText("Loading…") @@ -2220,10 +2219,12 @@ class StorePage(QWidget): self._cover_attempted.clear() self._placeholder = QIcon(_placeholder_pixmap(self.ICON_W, self.ICON_H)) - # Cancel any in-flight cover loaders (stale generation). + # Cancel any in-flight cover loaders (stale generation). Each loader + # removes itself from ``_loaders`` via its own ``finished`` handler once + # its thread winds down — dropping the list here would garbage-collect + # live QObjects and crash Qt. for loader in self._loaders: loader.cancel() - self._loaders = [] self.grid.clear() self.grid.setUpdatesEnabled(False) @@ -2401,6 +2402,7 @@ class StorePage(QWidget): thread.started.connect(loader.run) loader.loaded.connect(self._on_date_loaded) loader.finished.connect(self._on_date_batch_done) + loader.finished.connect(self._on_loader_finished) loader.finished.connect(thread.quit) thread.finished.connect(self._on_thread_finished) self._threads.append(thread) @@ -2425,6 +2427,21 @@ class StorePage(QWidget): if cell is not None: cell.setText(date) + def _on_loader_finished(self): + """Drop a finished cover/date loader from tracking. + + Loaders stay in ``_loaders`` until their thread finishes so their + QObject wrapper is never garbage-collected while its thread is still + winding down (that left a dangling thread affinity and crashed Qt on + filter/refresh). + """ + loader = self.sender() + if loader is None: + return + if loader in self._loaders: + self._loaders.remove(loader) + loader.deleteLater() + def _start_cover_loader(self, gen, tasks): if self._closing or not tasks: return @@ -2434,6 +2451,7 @@ class StorePage(QWidget): thread.started.connect(loader.run) loader.loaded.connect(self._on_cover_loaded) loader.finished.connect(self._on_cover_batch_done) + loader.finished.connect(self._on_loader_finished) loader.finished.connect(thread.quit) thread.finished.connect(self._on_thread_finished) self._threads.append(thread)