diff --git a/package/PartSeg/common_gui/napari_image_view.py b/package/PartSeg/common_gui/napari_image_view.py index c9fe54b9f..54dc4ab22 100644 --- a/package/PartSeg/common_gui/napari_image_view.py +++ b/package/PartSeg/common_gui/napari_image_view.py @@ -17,7 +17,7 @@ from napari.utils.colormaps.colormap import ColormapInterpolationMode from nme import register_class from packaging.version import parse as parse_version -from qtpy.QtCore import QEvent, QPoint, Qt, QTimer, Signal +from qtpy.QtCore import QEvent, QPoint, Qt, QThread, QTimer, Signal from qtpy.QtWidgets import QApplication, QCheckBox, QHBoxLayout, QLabel, QMenu, QSpinBox, QToolTip, QVBoxLayout, QWidget from scipy.ndimage import binary_dilation from superqt import QEnumComboBox, ensure_main_thread @@ -177,6 +177,8 @@ def __init__( self.mask_label = QLabel("Mask:") self.mask_label.setVisible(False) + self.prepare_layers = thread_worker(_prepare_layers) + self.btn_layout = QHBoxLayout() self.btn_layout.addWidget(self.reset_view_button) self.btn_layout.addWidget(self.ndim_btn) @@ -386,6 +388,8 @@ def update_points(self): self.points_layer.data = np.empty((0, 4)) def set_roi(self, roi_info: Optional[ROIInfo] = None, image: Optional[Image] = None) -> None: + if QApplication.instance().thread() != QThread.currentThread(): + raise RuntimeError("This method should be called from main thread") image = self.get_image(image) if roi_info is None: roi_info = self.settings.roi_info @@ -601,6 +605,9 @@ def calc_filter(j, layer_): def _add_image(self, image_data: Tuple[ImageInfo, bool]): self._remove_worker(self.sender()) + if QApplication.instance().thread() != QThread.currentThread(): + raise RuntimeError("Not in main thread") + image_info, replace = image_data image = image_info.image if replace: @@ -674,7 +681,7 @@ def add_image(self, image: Optional[Image], replace=False): return image def _prepare_layers(self, image, parameters, replace): - worker = prepare_layers(image, parameters, replace) + worker = self.prepare_layers(image, parameters, replace) worker.returned.connect(self._add_image) self.worker_list.append(worker) worker.start() diff --git a/package/PartSeg/common_gui/napari_viewer_wrap.py b/package/PartSeg/common_gui/napari_viewer_wrap.py index c013fd0b3..5291a12d2 100644 --- a/package/PartSeg/common_gui/napari_viewer_wrap.py +++ b/package/PartSeg/common_gui/napari_viewer_wrap.py @@ -3,6 +3,7 @@ from napari import Viewer as NViewer from napari.utils.colormaps import Colormap +from qtpy.QtCore import QCoreApplication, QThread from qtpy.QtWidgets import QCheckBox, QFormLayout, QPushButton, QWidget from PartSeg.common_backend.base_settings import BaseSettings @@ -244,3 +245,13 @@ def create_initial_layers( self._sync_widget.sync_additional() if points: self._sync_widget.sync_points() + + def add_layer(self, layer): + if QCoreApplication.instance().thread() != QThread.currentThread(): + raise RuntimeError("add_layer must be called from the main thread") + super().add_layer(layer) + + def add_labels(self, *args, **kwargs): + if QCoreApplication.instance().thread() != QThread.currentThread(): + raise RuntimeError("add_labels must be called from the main thread") + return super().add_labels(*args, **kwargs)