From 7e90c013ea74e19adee8c46a3eab7d2fde25b6f7 Mon Sep 17 00:00:00 2001 From: Patrick Avery Date: Tue, 19 Jul 2022 16:38:58 -0400 Subject: [PATCH] Remove use of QSignalBlocker in most code It appears that we can't always rely on python's reference counting system to delete `QSignalBlocker` (or lists of `QSignalBlocker`) at the end of method calls. As such, we should convert over to using the `block_signals()` context manager from `hexrd.ui.utils`. This commit moves all code over to that. Signed-off-by: Patrick Avery --- hexrd/ui/calibration_crystal_editor.py | 20 +-- hexrd/ui/calibration_crystal_slider_widget.py | 26 +-- hexrd/ui/dev-guide.md | 16 +- hexrd/ui/image_mode_widget.py | 93 ++++++----- .../ui/indexing/fit_grains_options_dialog.py | 85 +++++----- .../ui/indexing/fit_grains_results_dialog.py | 17 +- hexrd/ui/indexing/ome_maps_select_dialog.py | 27 +-- hexrd/ui/laue_overlay_editor.py | 40 +++-- hexrd/ui/material_properties_editor.py | 21 +-- hexrd/ui/material_structure_editor.py | 32 ++-- hexrd/ui/materials_panel.py | 35 ++-- hexrd/ui/matrix_editor.py | 11 +- hexrd/ui/overlay_manager.py | 57 +++---- hexrd/ui/overlay_style_picker.py | 33 ++-- hexrd/ui/powder_overlay_editor.py | 15 +- hexrd/ui/ranges_table_editor.py | 34 ++-- hexrd/ui/reflections_table.py | 158 +++++++++--------- 17 files changed, 359 insertions(+), 361 deletions(-) diff --git a/hexrd/ui/calibration_crystal_editor.py b/hexrd/ui/calibration_crystal_editor.py index 64768391c..82f7d0845 100644 --- a/hexrd/ui/calibration_crystal_editor.py +++ b/hexrd/ui/calibration_crystal_editor.py @@ -2,7 +2,7 @@ import numpy as np from numpy.linalg import LinAlgError -from PySide2.QtCore import QObject, QSignalBlocker, Signal +from PySide2.QtCore import QObject, Signal from PySide2.QtWidgets import QFileDialog from hexrd import instrument, matrixutil @@ -16,7 +16,7 @@ from hexrd.ui.select_grains_dialog import SelectGrainsDialog from hexrd.ui.select_items_widget import SelectItemsWidget from hexrd.ui.ui_loader import UiLoader -from hexrd.ui.utils import convert_angle_convention +from hexrd.ui.utils import block_signals, convert_angle_convention class CalibrationCrystalEditor(QObject): @@ -171,8 +171,8 @@ def update_duplicate(self, w): dup_ind = self.stretch_matrix_duplicates.get(ind) if dup_ind is not None: dup = getattr(self.ui, f'stretch_matrix_{dup_ind}') - blocker = QSignalBlocker(dup) # noqa: F841 - dup.setValue(w.value()) + with block_signals(dup): + dup.setValue(w.value()) def set_matrix_valid(self): self.set_matrix_style_sheet('background-color: white') @@ -215,8 +215,8 @@ def orientation(self, v): v = np.degrees(v) for i, w in enumerate(self.orientation_widgets): - blocker = QSignalBlocker(w) # noqa: F841 - w.setValue(v[i]) + with block_signals(w): + w.setValue(v[i]) @property def position(self): @@ -225,8 +225,8 @@ def position(self): @position.setter def position(self, v): for i, w in enumerate(self.position_widgets): - blocker = QSignalBlocker(w) # noqa: F841 - w.setValue(v[i]) + with block_signals(w): + w.setValue(v[i]) @property def inverse_stretch(self): @@ -245,8 +245,8 @@ def stretch_matrix(self): @stretch_matrix.setter def stretch_matrix(self, v): for i, w in enumerate(self.stretch_matrix_widgets): - blocker = QSignalBlocker(w) # noqa: F841 - w.setValue(v[i]) + with block_signals(w): + w.setValue(v[i]) @property def orientation_widgets(self): diff --git a/hexrd/ui/calibration_crystal_slider_widget.py b/hexrd/ui/calibration_crystal_slider_widget.py index 9b62145b3..6e46b4faa 100644 --- a/hexrd/ui/calibration_crystal_slider_widget.py +++ b/hexrd/ui/calibration_crystal_slider_widget.py @@ -1,9 +1,10 @@ from enum import IntEnum -from PySide2.QtCore import QObject, QSignalBlocker, Signal +from PySide2.QtCore import QObject, Signal from PySide2.QtWidgets import QProxyStyle, QStyle from hexrd.ui.ui_loader import UiLoader +from hexrd.ui.utils import block_signals class SpinBoxStyle(QProxyStyle): @@ -90,9 +91,9 @@ def on_mode_changed(self): # Update spinbox values for i, w in enumerate(self.spinbox_widgets): - blocker = QSignalBlocker(w) # noqa: F841 - w.setSuffix(suffix) - w.setValue(data[i]) + with block_signals(w): + w.setSuffix(suffix) + w.setValue(data[i]) # Update slider positions self.ui.slider_range.setValue(srange) @@ -123,10 +124,9 @@ def on_spinbox_changed(self, value): slider_value = value * self.CONF_VAL_TO_SLIDER_VAL w_name = f'slider_{index}' w = getattr(self.ui, w_name) - blocker = QSignalBlocker(w) # noqa: F841 - w.setValue(slider_value) - - self.changed.emit(mode.value, index, value) + with block_signals(w): + w.setValue(slider_value) + self.changed.emit(mode.value, index, value) def reset_ranges(self): self._orientation_range = self.DEFAULT_SLIDER_RANGE @@ -156,8 +156,8 @@ def update_gui(self, orientation, position): data = self._orientation if self.mode == WidgetMode.ORIENTATION \ else self._position for i, w in enumerate(self.spinbox_widgets): - blocker = QSignalBlocker(w) # noqa: F841 - w.setValue(data[i]) + with block_signals(w): + w.setValue(data[i]) self.update_ranges() def update_ranges(self): @@ -169,6 +169,6 @@ def update_ranges(self): sliders = self.slider_widgets for i, slider in enumerate(sliders): val = data[i] * self.CONF_VAL_TO_SLIDER_VAL - blocker = QSignalBlocker(slider) # noqa: F841 - slider.setRange(val - delta, val + delta) - slider.setValue(val) + with block_signals(slider): + slider.setRange(val - delta, val + delta) + slider.setValue(val) diff --git a/hexrd/ui/dev-guide.md b/hexrd/ui/dev-guide.md index 01c6dd766..cef5fd51d 100644 --- a/hexrd/ui/dev-guide.md +++ b/hexrd/ui/dev-guide.md @@ -109,6 +109,10 @@ class SomeWidget(QObject): For updating the GUI with internal config, the design pattern we typically use is as follows: ``` +from hexrd.ui.utils import block_signals + +... + @property def all_widgets(self): return [ @@ -118,16 +122,14 @@ use is as follows: ] def update_gui(self): - blockers = [QSignalBlocker(x) for x in self.all_widgets] # noqa: F841 - self.ui.widget1.setValue(...) - ... + with block_signals(*self.all_widgets): + self.ui.widget1.setValue(...) + ... ``` We need to block the widget signals when we are updating the values, so that -they do not modify the config as well. The reason we use a list of -QSignalBlockers is so that if an exception is raised, they will be unblocked -automatically. `# noqa: F841` is necessary to tell `flake8` to ignore the -fact that we don't use `blockers` (it is only being used in an RAII fashion). +they do not modify the config as well. The reason we use a context manager +is so that if an exception is raised, they will be unblocked automatically. Resources --------- diff --git a/hexrd/ui/image_mode_widget.py b/hexrd/ui/image_mode_widget.py index 670117f61..b254030f9 100644 --- a/hexrd/ui/image_mode_widget.py +++ b/hexrd/ui/image_mode_widget.py @@ -3,13 +3,14 @@ import multiprocessing import numpy as np -from PySide2.QtCore import QObject, QSignalBlocker, Signal +from PySide2.QtCore import QObject, Signal from hexrd.ui.constants import ViewType from hexrd.ui.create_hedm_instrument import create_hedm_instrument from hexrd.ui.create_raw_mask import apply_threshold_mask, remove_threshold_mask from hexrd.ui.hexrd_config import HexrdConfig from hexrd.ui.ui_loader import UiLoader +from hexrd.ui.utils import block_signals class ImageModeWidget(QObject): @@ -133,45 +134,45 @@ def all_widgets(self): return widgets def update_gui_from_config(self): - blocked = [QSignalBlocker(x) for x in self.all_widgets()] # noqa: F841 - self.ui.raw_threshold_comparison.setCurrentIndex( - HexrdConfig().threshold_comparison) - self.ui.raw_threshold_value.setValue( - HexrdConfig().threshold_value) - self.ui.raw_threshold_mask.setChecked( - HexrdConfig().threshold_mask_status) - self.ui.cartesian_pixel_size.setValue( - HexrdConfig().cartesian_pixel_size) - self.ui.cartesian_virtual_plane_distance.setValue( - HexrdConfig().cartesian_virtual_plane_distance) - self.ui.cartesian_plane_normal_rotate_x.setValue( - HexrdConfig().cartesian_plane_normal_rotate_x) - self.ui.cartesian_plane_normal_rotate_y.setValue( - HexrdConfig().cartesian_plane_normal_rotate_y) - self.ui.polar_pixel_size_tth.setValue( - HexrdConfig().polar_pixel_size_tth) - self.ui.polar_pixel_size_eta.setValue( - HexrdConfig().polar_pixel_size_eta) - self.ui.polar_res_tth_min.setValue( - HexrdConfig().polar_res_tth_min) - self.ui.polar_res_tth_max.setValue( - HexrdConfig().polar_res_tth_max) - self.ui.polar_res_eta_min.setValue( - HexrdConfig().polar_res_eta_min) - self.ui.polar_res_eta_max.setValue( - HexrdConfig().polar_res_eta_max) - self.ui.polar_snip1d_algorithm.setCurrentIndex( - HexrdConfig().polar_snip1d_algorithm) - self.ui.polar_apply_snip1d.setChecked( - HexrdConfig().polar_apply_snip1d) - self.ui.polar_snip1d_width.setValue( - HexrdConfig().polar_snip1d_width) - self.ui.polar_snip1d_numiter.setValue( - HexrdConfig().polar_snip1d_numiter) - self.ui.polar_apply_erosion.setChecked( - HexrdConfig().polar_apply_erosion) - - self.update_enable_states() + with block_signals(*self.all_widgets()): + self.ui.raw_threshold_comparison.setCurrentIndex( + HexrdConfig().threshold_comparison) + self.ui.raw_threshold_value.setValue( + HexrdConfig().threshold_value) + self.ui.raw_threshold_mask.setChecked( + HexrdConfig().threshold_mask_status) + self.ui.cartesian_pixel_size.setValue( + HexrdConfig().cartesian_pixel_size) + self.ui.cartesian_virtual_plane_distance.setValue( + HexrdConfig().cartesian_virtual_plane_distance) + self.ui.cartesian_plane_normal_rotate_x.setValue( + HexrdConfig().cartesian_plane_normal_rotate_x) + self.ui.cartesian_plane_normal_rotate_y.setValue( + HexrdConfig().cartesian_plane_normal_rotate_y) + self.ui.polar_pixel_size_tth.setValue( + HexrdConfig().polar_pixel_size_tth) + self.ui.polar_pixel_size_eta.setValue( + HexrdConfig().polar_pixel_size_eta) + self.ui.polar_res_tth_min.setValue( + HexrdConfig().polar_res_tth_min) + self.ui.polar_res_tth_max.setValue( + HexrdConfig().polar_res_tth_max) + self.ui.polar_res_eta_min.setValue( + HexrdConfig().polar_res_eta_min) + self.ui.polar_res_eta_max.setValue( + HexrdConfig().polar_res_eta_max) + self.ui.polar_snip1d_algorithm.setCurrentIndex( + HexrdConfig().polar_snip1d_algorithm) + self.ui.polar_apply_snip1d.setChecked( + HexrdConfig().polar_apply_snip1d) + self.ui.polar_snip1d_width.setValue( + HexrdConfig().polar_snip1d_width) + self.ui.polar_snip1d_numiter.setValue( + HexrdConfig().polar_snip1d_numiter) + self.ui.polar_apply_erosion.setChecked( + HexrdConfig().polar_apply_erosion) + + self.update_enable_states() def update_enable_states(self): apply_snip1d = self.ui.polar_apply_snip1d.isChecked() @@ -280,9 +281,9 @@ def on_eta_min_changed(self, min_value): max_value = min_value + 360.0 update_max = True if update_max: - blocked = QSignalBlocker(self.ui.polar_res_eta_max) # noqa: F841 - self.ui.polar_res_eta_max.setValue(max_value) - HexrdConfig().set_polar_res_eta_max(max_value, rerender=False) + with block_signals(self.ui.polar_res_eta_max): + self.ui.polar_res_eta_max.setValue(max_value) + HexrdConfig().set_polar_res_eta_max(max_value, rerender=False) HexrdConfig().polar_res_eta_min = min_value def on_eta_max_changed(self, max_value): @@ -296,9 +297,9 @@ def on_eta_max_changed(self, max_value): min_value = max_value - 360.0 update_min = True if update_min: - blocked = QSignalBlocker(self.ui.polar_res_eta_min) # noqa: F841 - self.ui.polar_res_eta_min.setValue(min_value) - HexrdConfig().set_polar_res_eta_min(min_value, rerender=False) + with block_signals(self.ui.polar_res_eta_min): + self.ui.polar_res_eta_min.setValue(min_value) + HexrdConfig().set_polar_res_eta_min(min_value, rerender=False) HexrdConfig().polar_res_eta_max = max_value diff --git a/hexrd/ui/indexing/fit_grains_options_dialog.py b/hexrd/ui/indexing/fit_grains_options_dialog.py index e984c3b8e..6f9d1d668 100644 --- a/hexrd/ui/indexing/fit_grains_options_dialog.py +++ b/hexrd/ui/indexing/fit_grains_options_dialog.py @@ -1,11 +1,12 @@ from PySide2.QtCore import ( - QItemSelectionModel, QModelIndex, QObject, QSignalBlocker, Qt, Signal) + QItemSelectionModel, QModelIndex, QObject, Qt, Signal) from PySide2.QtWidgets import QDialogButtonBox, QFileDialog, QHeaderView from hexrd.ui.hexrd_config import HexrdConfig from hexrd.ui.indexing.grains_table_model import GrainsTableModel from hexrd.ui.reflections_table import ReflectionsTable from hexrd.ui.ui_loader import UiLoader +from hexrd.ui.utils import block_signals from hexrd.ui.indexing.fit_grains_tolerances_model import ( FitGrainsToleranceModel) @@ -221,47 +222,47 @@ def update_config(self): indexing_config['_write_spots'] = self.ui.write_out_spots.isChecked() def update_gui_from_config(self, config): - blocked = [QSignalBlocker(x) for x in self.all_widgets()] - self.ui.npdiv.setValue(config.get('npdiv')) - self.ui.refit_pixel_scale.setValue(config.get('refit')[0]) - self.ui.refit_ome_step_scale.setValue(config.get('refit')[1]) - self.ui.threshold.setValue(config.get('threshold')) - - tth_max = config.get('tth_max') - if isinstance(tth_max, bool): - enabled = tth_max - instrument = tth_max - value = 0.0 - else: - enabled = True - instrument = False - value = tth_max - - self.ui.tth_max_enable.setChecked(enabled) - - self.ui.tth_max_instrument.setEnabled(enabled) - self.ui.tth_max_instrument.setChecked(instrument) - - self.ui.tth_max_specify.setEnabled(enabled) - self.ui.tth_max_specify.setChecked(not instrument) - - self.ui.tth_max_value.setEnabled(enabled and (not instrument)) - self.ui.tth_max_value.setValue(value) - - tolerances = config.get('tolerance') - self.tolerances_model.update_from_config(tolerances) - - indexing_config = HexrdConfig().indexing_config - self.selected_material = indexing_config.get('_selected_material') - working_dir = indexing_config.get( - 'working_dir', str(Path(HexrdConfig().working_dir).parent)) - analysis_name = indexing_config.get( - 'analysis_name', Path(HexrdConfig().working_dir).stem) - self.spots_path = str(Path(working_dir) / analysis_name) - write_spots = indexing_config.get('_write_spots', False) - self.ui.write_out_spots.setChecked(write_spots) - - self.update_num_hkls() + with block_signals(*self.all_widgets()): + self.ui.npdiv.setValue(config.get('npdiv')) + self.ui.refit_pixel_scale.setValue(config.get('refit')[0]) + self.ui.refit_ome_step_scale.setValue(config.get('refit')[1]) + self.ui.threshold.setValue(config.get('threshold')) + + tth_max = config.get('tth_max') + if isinstance(tth_max, bool): + enabled = tth_max + instrument = tth_max + value = 0.0 + else: + enabled = True + instrument = False + value = tth_max + + self.ui.tth_max_enable.setChecked(enabled) + + self.ui.tth_max_instrument.setEnabled(enabled) + self.ui.tth_max_instrument.setChecked(instrument) + + self.ui.tth_max_specify.setEnabled(enabled) + self.ui.tth_max_specify.setChecked(not instrument) + + self.ui.tth_max_value.setEnabled(enabled and (not instrument)) + self.ui.tth_max_value.setValue(value) + + tolerances = config.get('tolerance') + self.tolerances_model.update_from_config(tolerances) + + indexing_config = HexrdConfig().indexing_config + self.selected_material = indexing_config.get('_selected_material') + working_dir = indexing_config.get( + 'working_dir', str(Path(HexrdConfig().working_dir).parent)) + analysis_name = indexing_config.get( + 'analysis_name', Path(HexrdConfig().working_dir).stem) + self.spots_path = str(Path(working_dir) / analysis_name) + write_spots = indexing_config.get('_write_spots', False) + self.ui.write_out_spots.setChecked(write_spots) + + self.update_num_hkls() def run(self): self.ui.show() diff --git a/hexrd/ui/indexing/fit_grains_results_dialog.py b/hexrd/ui/indexing/fit_grains_results_dialog.py index 5432473b0..345192501 100644 --- a/hexrd/ui/indexing/fit_grains_results_dialog.py +++ b/hexrd/ui/indexing/fit_grains_results_dialog.py @@ -12,7 +12,7 @@ from matplotlib.backends.backend_qt5agg import FigureCanvas from matplotlib.figure import Figure -from PySide2.QtCore import QObject, QSignalBlocker, QTimer, Qt, Signal +from PySide2.QtCore import QObject, QTimer, Qt, Signal from PySide2.QtWidgets import QFileDialog, QMenu, QSizePolicy from hexrd.matrixutil import vecMVToSymm @@ -23,6 +23,7 @@ from hexrd.ui.indexing.grains_table_model import GrainsTableModel from hexrd.ui.navigation_toolbar import NavigationToolbar from hexrd.ui.ui_loader import UiLoader +from hexrd.ui.utils import block_signals COORDS_SLICE = slice(6, 9) @@ -445,13 +446,11 @@ def update_selectors(self): prev_ind = self.ui.plot_color_option.currentIndex() - blocker = QSignalBlocker(self.ui.plot_color_option) # noqa: F841 - self.ui.plot_color_option.clear() + with block_signals(self.ui.plot_color_option): + self.ui.plot_color_option.clear() - for item in items: - self.ui.plot_color_option.addItem(*item) - - del blocker + for item in items: + self.ui.plot_color_option.addItem(*item) if hasattr(self, '_first_selector_update'): self.ui.plot_color_option.setCurrentIndex(prev_ind) @@ -525,8 +524,8 @@ def update_ranges_mpl(self): self.ranges_mpl = self.ranges_gui def update_ranges_gui(self): - blocked = [QSignalBlocker(w) for w in self.range_widgets] # noqa: F841 - self.ranges_gui = self.ranges_mpl + with block_signals(*self.range_widgets): + self.ranges_gui = self.ranges_mpl def backup_ranges(self): self._ranges_backup = self.ranges_mpl diff --git a/hexrd/ui/indexing/ome_maps_select_dialog.py b/hexrd/ui/indexing/ome_maps_select_dialog.py index 9de91197d..1dbf5137d 100644 --- a/hexrd/ui/indexing/ome_maps_select_dialog.py +++ b/hexrd/ui/indexing/ome_maps_select_dialog.py @@ -1,11 +1,12 @@ import os -from PySide2.QtCore import Signal, QObject, QSignalBlocker +from PySide2.QtCore import Signal, QObject from PySide2.QtWidgets import QFileDialog, QMessageBox from hexrd.ui.hexrd_config import HexrdConfig from hexrd.ui.reflections_table import ReflectionsTable from hexrd.ui.ui_loader import UiLoader +from hexrd.ui.utils import block_signals class OmeMapsSelectDialog(QObject): @@ -158,24 +159,24 @@ def update_config(self): indexing_config['_selected_material'] = self.selected_material def update_gui(self): - blockers = [QSignalBlocker(x) for x in self.widgets] # noqa: F841 + with block_signals(*self.widgets): + indexing_config = HexrdConfig().indexing_config + find_orientations = indexing_config['find_orientations'] + maps_config = find_orientations['orientation_maps'] - indexing_config = HexrdConfig().indexing_config - maps_config = indexing_config['find_orientations']['orientation_maps'] + self.method_name = maps_config.get('_select_method', 'load') - self.method_name = maps_config.get('_select_method', 'load') + file_name = maps_config['file'] if maps_config['file'] else '' - file_name = maps_config['file'] if maps_config['file'] else '' + self.ui.file_name.setText(file_name) + self.threshold = maps_config['threshold'] + self.ui.bin_frames.setValue(maps_config['bin_frames']) - self.ui.file_name.setText(file_name) - self.threshold = maps_config['threshold'] - self.ui.bin_frames.setValue(maps_config['bin_frames']) + self.selected_material = indexing_config.get('_selected_material') - self.selected_material = indexing_config.get('_selected_material') + self.update_method_tab() - self.update_method_tab() - - self.update_num_hkls() + self.update_num_hkls() @property def method_name(self): diff --git a/hexrd/ui/laue_overlay_editor.py b/hexrd/ui/laue_overlay_editor.py index c80792af4..6e31a50a8 100644 --- a/hexrd/ui/laue_overlay_editor.py +++ b/hexrd/ui/laue_overlay_editor.py @@ -1,7 +1,6 @@ import copy import numpy as np -from PySide2.QtCore import QSignalBlocker from PySide2.QtWidgets import QCheckBox, QComboBox, QDoubleSpinBox from hexrd.rotations import angles_from_rmat_xyz, rotMatOfExpMap @@ -10,7 +9,7 @@ from hexrd.ui.hexrd_config import HexrdConfig from hexrd.ui.overlays.laue_overlay import LaueLabelType, LaueRangeShape from hexrd.ui.ui_loader import UiLoader -from hexrd.ui.utils import convert_angle_convention +from hexrd.ui.utils import block_signals, convert_angle_convention class LaueOverlayEditor: @@ -67,25 +66,24 @@ def update_gui(self): if self.overlay is None: return - blockers = [QSignalBlocker(w) for w in self.widgets] # noqa: F841 - - overlay = self.overlay - self.ui.min_energy.setValue(overlay.min_energy) - self.ui.max_energy.setValue(overlay.max_energy) - self.sample_rmat = overlay.sample_rmat - self.crystal_params = overlay.crystal_params - self.refinements = overlay.refinements - self.width_shape = overlay.width_shape - self.label_type = overlay.label_type - self.label_offsets = overlay.label_offsets - - self.ui.enable_widths.setChecked(overlay.has_widths) - if overlay.has_widths: - self.ui.tth_width.setValue(np.degrees(overlay.tth_width)) - self.ui.eta_width.setValue(np.degrees(overlay.eta_width)) - - self.update_enable_states() - self.update_orientation_suffixes() + with block_signals(*self.widgets): + overlay = self.overlay + self.ui.min_energy.setValue(overlay.min_energy) + self.ui.max_energy.setValue(overlay.max_energy) + self.sample_rmat = overlay.sample_rmat + self.crystal_params = overlay.crystal_params + self.refinements = overlay.refinements + self.width_shape = overlay.width_shape + self.label_type = overlay.label_type + self.label_offsets = overlay.label_offsets + + self.ui.enable_widths.setChecked(overlay.has_widths) + if overlay.has_widths: + self.ui.tth_width.setValue(np.degrees(overlay.tth_width)) + self.ui.eta_width.setValue(np.degrees(overlay.eta_width)) + + self.update_enable_states() + self.update_orientation_suffixes() def update_enable_states(self): enable_widths = self.enable_widths diff --git a/hexrd/ui/material_properties_editor.py b/hexrd/ui/material_properties_editor.py index a2bda2f10..1dad39dc2 100644 --- a/hexrd/ui/material_properties_editor.py +++ b/hexrd/ui/material_properties_editor.py @@ -2,14 +2,12 @@ import numpy as np from numpy.linalg import LinAlgError, inv -from PySide2.QtCore import QSignalBlocker - from hexrd.unitcell import _StiffnessDict from hexrd.ui.hexrd_config import HexrdConfig from hexrd.ui.matrix_editor import MatrixEditor from hexrd.ui.ui_loader import UiLoader -from hexrd.ui.utils import apply_symmetric_constraint, compose +from hexrd.ui.utils import apply_symmetric_constraint, block_signals, compose class MaterialPropertiesEditor: @@ -96,17 +94,16 @@ def update_elastic_tensor_gui(self): editor.data = data def update_misc_gui(self): - blocked = [QSignalBlocker(w) for w in self.misc_widgets] # noqa: F841 - - material = self.material + with block_signals(*self.misc_widgets): + material = self.material - density = getattr(material.unitcell, 'density', 0) - volume = getattr(material, 'vol', 0) - volume_per_atom = getattr(material, 'vol_per_atom', 0) + density = getattr(material.unitcell, 'density', 0) + volume = getattr(material, 'vol', 0) + volume_per_atom = getattr(material, 'vol_per_atom', 0) - self.ui.density.setValue(density) - self.ui.volume.setValue(volume) - self.ui.volume_per_atom.setValue(volume_per_atom) + self.ui.density.setValue(density) + self.ui.volume.setValue(volume) + self.ui.volume_per_atom.setValue(volume_per_atom) def update_enable_states(self): matrix_valid = not self.elastic_tensor_editor.matrix_invalid diff --git a/hexrd/ui/material_structure_editor.py b/hexrd/ui/material_structure_editor.py index 6ee0e6812..b99b2e1bb 100644 --- a/hexrd/ui/material_structure_editor.py +++ b/hexrd/ui/material_structure_editor.py @@ -3,9 +3,7 @@ import numpy as np -from PySide2.QtCore import ( - Qt, QItemSelectionModel, QObject, QSignalBlocker, Signal -) +from PySide2.QtCore import Qt, QItemSelectionModel, QObject, Signal from PySide2.QtWidgets import ( QLineEdit, QItemEditorFactory, QStyledItemDelegate, QTableWidgetItem ) @@ -15,6 +13,7 @@ from hexrd.ui.hexrd_config import HexrdConfig from hexrd.ui.material_site_editor import MaterialSiteEditor from hexrd.ui.ui_loader import UiLoader +from hexrd.ui.utils import block_signals DEFAULT_SITE = { @@ -229,20 +228,19 @@ def update_table(self): self.ui.table, self.ui.table.selectionModel() ] - blockers = [QSignalBlocker(x) for x in block_list] # noqa: F841 - - self.ui.table.setRowCount(len(self.sites)) - for i, site in enumerate(self.sites): - w = self.create_table_widget(site['name']) - self.ui.table.setItem(i, 0, w) - - if prev_selected is not None: - select_row = (prev_selected if prev_selected < len(self.sites) - else len(self.sites) - 1) - self.select_row(select_row) - - # Just in case the selection actually changed... - self.selection_changed() + with block_signals(*block_list): + self.ui.table.setRowCount(len(self.sites)) + for i, site in enumerate(self.sites): + w = self.create_table_widget(site['name']) + self.ui.table.setItem(i, 0, w) + + if prev_selected is not None: + select_row = (prev_selected if prev_selected < len(self.sites) + else len(self.sites) - 1) + self.select_row(select_row) + + # Just in case the selection actually changed... + self.selection_changed() def update_material(self): # Convert the sites back to the material data format diff --git a/hexrd/ui/materials_panel.py b/hexrd/ui/materials_panel.py index d2b410689..8d282e4b7 100644 --- a/hexrd/ui/materials_panel.py +++ b/hexrd/ui/materials_panel.py @@ -1,6 +1,6 @@ import math -from PySide2.QtCore import QObject, QSignalBlocker, Qt +from PySide2.QtCore import QObject, Qt from PySide2.QtGui import QFocusEvent, QKeyEvent from PySide2.QtWidgets import QComboBox @@ -14,6 +14,7 @@ from hexrd.ui.material_structure_editor import MaterialStructureEditor from hexrd.ui.overlay_manager import OverlayManager from hexrd.ui.ui_loader import UiLoader +from hexrd.ui.utils import block_signals class MaterialsPanel(QObject): @@ -164,28 +165,26 @@ def update_gui_from_config(self): self.ui.min_d_spacing, self.ui.limit_active ] - blockers = [QSignalBlocker(x) for x in block_list] - combo = self.ui.materials_combo - current_items = [combo.itemText(x) for x in range(combo.count())] - materials_keys = list(HexrdConfig().materials.keys()) - - # If the materials in the config have changed, re-build the list - if current_items != materials_keys: - self.ui.materials_combo.clear() - self.ui.materials_combo.addItems(materials_keys) + with block_signals(*block_list): + combo = self.ui.materials_combo + current_items = [combo.itemText(x) for x in range(combo.count())] + materials_keys = list(HexrdConfig().materials.keys()) - self.material_editor_widget.material = self.material - self.ui.materials_combo.setCurrentIndex( - materials_keys.index(HexrdConfig().active_material_name)) - self.ui.show_overlays.setChecked(HexrdConfig().show_overlays) + # If the materials in the config have changed, re-build the list + if current_items != materials_keys: + self.ui.materials_combo.clear() + self.ui.materials_combo.addItems(materials_keys) - self.ui.min_d_spacing.setValue(self.material.dmin.getVal('angstrom')) + self.material_editor_widget.material = self.material + self.ui.materials_combo.setCurrentIndex( + materials_keys.index(HexrdConfig().active_material_name)) + self.ui.show_overlays.setChecked(HexrdConfig().show_overlays) - self.ui.limit_active.setChecked(HexrdConfig().limit_active_rings) + self.ui.min_d_spacing.setValue( + self.material.dmin.getVal('angstrom')) - # Unblock the signal blockers before proceeding - del blockers + self.ui.limit_active.setChecked(HexrdConfig().limit_active_rings) self.update_material_limits() self.update_table() diff --git a/hexrd/ui/matrix_editor.py b/hexrd/ui/matrix_editor.py index 99098c029..e79c53f80 100644 --- a/hexrd/ui/matrix_editor.py +++ b/hexrd/ui/matrix_editor.py @@ -1,9 +1,10 @@ import numpy as np -from PySide2.QtCore import QSignalBlocker, Signal +from PySide2.QtCore import Signal from PySide2.QtWidgets import QGridLayout, QWidget from hexrd.ui.scientificspinbox import ScientificDoubleSpinBox +from hexrd.ui.utils import block_signals DEFAULT_ENABLED_STYLE_SHEET = 'background-color: white' DEFAULT_DISABLED_STYLE_SHEET = 'background-color: #F0F0F0' @@ -94,10 +95,10 @@ def gui_data(self): @gui_data.setter def gui_data(self, v): - blockers = [QSignalBlocker(w) for w in self.all_widgets] # noqa: F841 - for i in range(self.rows): - for j in range(self.cols): - self.set_gui_value(i, j, v[i][j]) + with block_signals(*self.all_widgets): + for i in range(self.rows): + for j in range(self.cols): + self.set_gui_value(i, j, v[i][j]) @property def all_widgets(self): diff --git a/hexrd/ui/overlay_manager.py b/hexrd/ui/overlay_manager.py index 0668a86f8..f22105fa9 100644 --- a/hexrd/ui/overlay_manager.py +++ b/hexrd/ui/overlay_manager.py @@ -1,4 +1,4 @@ -from PySide2.QtCore import Qt, QItemSelectionModel, QSignalBlocker +from PySide2.QtCore import Qt, QItemSelectionModel from PySide2.QtWidgets import ( QCheckBox, QComboBox, QHBoxLayout, QHeaderView, QSizePolicy, QTableWidgetItem, QWidget @@ -9,6 +9,7 @@ from hexrd.ui.overlay_editor import OverlayEditor from hexrd.ui.overlay_style_picker import OverlayStylePicker from hexrd.ui.ui_loader import UiLoader +from hexrd.ui.utils import block_signals COLUMNS = { @@ -127,42 +128,42 @@ def update_table(self): self.ui.table, self.ui.table.selectionModel() ] - blockers = [QSignalBlocker(x) for x in block_list] # noqa: F841 - prev_selected = self.selected_row + with block_signals(*block_list): + prev_selected = self.selected_row - overlays = HexrdConfig().overlays - self.clear_table() - self.ui.table.setRowCount(len(overlays)) - for i, overlay in enumerate(overlays): - w = QTableWidgetItem(overlay.name) - self.ui.table.setItem(i, COLUMNS['name'], w) + overlays = HexrdConfig().overlays + self.clear_table() + self.ui.table.setRowCount(len(overlays)) + for i, overlay in enumerate(overlays): + w = QTableWidgetItem(overlay.name) + self.ui.table.setItem(i, COLUMNS['name'], w) - w = self.create_materials_combo(overlay.material_name) - self.ui.table.setCellWidget(i, COLUMNS['material'], w) + w = self.create_materials_combo(overlay.material_name) + self.ui.table.setCellWidget(i, COLUMNS['material'], w) - w = self.create_type_combo(overlay.type) - self.ui.table.setCellWidget(i, COLUMNS['type'], w) + w = self.create_type_combo(overlay.type) + self.ui.table.setCellWidget(i, COLUMNS['type'], w) - w = self.create_visibility_checkbox(overlay.visible) - self.ui.table.setCellWidget(i, COLUMNS['visible'], w) + w = self.create_visibility_checkbox(overlay.visible) + self.ui.table.setCellWidget(i, COLUMNS['visible'], w) - if prev_selected is not None: - select_row = (prev_selected if prev_selected < len(overlays) - else len(overlays) - 1) - self.select_row(select_row) + if prev_selected is not None: + select_row = (prev_selected if prev_selected < len(overlays) + else len(overlays) - 1) + self.select_row(select_row) - self.ui.table.resizeColumnsToContents() + self.ui.table.resizeColumnsToContents() - # The last section isn't always stretching automatically, even - # though we have setStretchLastSection(True) set. - # Force it to stretch manually. - last_column = max(v for v in COLUMNS.values()) - self.ui.table.horizontalHeader().setSectionResizeMode( - last_column, QHeaderView.Stretch) + # The last section isn't always stretching automatically, even + # though we have setStretchLastSection(True) set. + # Force it to stretch manually. + last_column = max(v for v in COLUMNS.values()) + self.ui.table.horizontalHeader().setSectionResizeMode( + last_column, QHeaderView.Stretch) - # Just in case the selection actually changed... - self.selection_changed() + # Just in case the selection actually changed... + self.selection_changed() def select_row(self, i): if i is None or i >= self.ui.table.rowCount(): diff --git a/hexrd/ui/overlay_style_picker.py b/hexrd/ui/overlay_style_picker.py index 888f82ee9..bd6b20e39 100644 --- a/hexrd/ui/overlay_style_picker.py +++ b/hexrd/ui/overlay_style_picker.py @@ -2,13 +2,14 @@ from matplotlib.font_manager import weight_dict -from PySide2.QtCore import QObject, QSignalBlocker +from PySide2.QtCore import QObject from PySide2.QtGui import QColor from PySide2.QtWidgets import QColorDialog from hexrd.ui.constants import OverlayType from hexrd.ui.hexrd_config import HexrdConfig from hexrd.ui.ui_loader import UiLoader +from hexrd.ui.utils import block_signals class OverlayStylePicker(QObject): @@ -122,22 +123,20 @@ def update_gui(self): ranges = self.style['ranges'] keys = self.keys - blockers = [QSignalBlocker(x) for x in self.all_widgets] - self.ui.data_color.setText(data[keys['data_color']]) - self.ui.data_style.setCurrentText(data[keys['data_style']]) - self.ui.data_size.setValue(data[keys['data_size']]) - self.ui.range_color.setText(ranges[keys['range_color']]) - self.ui.range_style.setCurrentText(ranges[keys['range_style']]) - self.ui.range_size.setValue(ranges[keys['range_size']]) - - if self.include_labels: - labels = self.style['labels'] - self.ui.label_color.setText(labels[keys['label_color']]) - self.ui.label_size.setValue(labels[keys['label_size']]) - self.ui.label_weight.setCurrentText(labels[keys['label_weight']]) - - # Unblock - del blockers + with block_signals(*self.all_widgets): + self.ui.data_color.setText(data[keys['data_color']]) + self.ui.data_style.setCurrentText(data[keys['data_style']]) + self.ui.data_size.setValue(data[keys['data_size']]) + self.ui.range_color.setText(ranges[keys['range_color']]) + self.ui.range_style.setCurrentText(ranges[keys['range_style']]) + self.ui.range_size.setValue(ranges[keys['range_size']]) + + if self.include_labels: + labels = self.style['labels'] + self.ui.label_color.setText(labels[keys['label_color']]) + self.ui.label_size.setValue(labels[keys['label_size']]) + self.ui.label_weight.setCurrentText( + labels[keys['label_weight']]) self.update_button_colors() diff --git a/hexrd/ui/powder_overlay_editor.py b/hexrd/ui/powder_overlay_editor.py index f1b72ca7d..f6dbddf39 100644 --- a/hexrd/ui/powder_overlay_editor.py +++ b/hexrd/ui/powder_overlay_editor.py @@ -2,13 +2,13 @@ import numpy as np -from PySide2.QtCore import QSignalBlocker from PySide2.QtWidgets import QCheckBox, QDoubleSpinBox from hexrd.ui.hexrd_config import HexrdConfig from hexrd.ui.reflections_table import ReflectionsTable from hexrd.ui.select_items_widget import SelectItemsWidget from hexrd.ui.ui_loader import UiLoader +from hexrd.ui.utils import block_signals class PowderOverlayEditor: @@ -95,14 +95,13 @@ def update_gui(self): if self.overlay is None: return - blockers = [QSignalBlocker(w) for w in self.widgets] # noqa: F841 + with block_signals(*self.widgets): + self.tth_width_gui = self.tth_width_config + self.offset_gui = self.offset_config + self.refinements_with_labels = self.overlay.refinements_with_labels - self.tth_width_gui = self.tth_width_config - self.offset_gui = self.offset_config - self.refinements_with_labels = self.overlay.refinements_with_labels - - self.update_enable_states() - self.update_reflections_table() + self.update_enable_states() + self.update_reflections_table() def update_config(self): self.tth_width_config = self.tth_width_gui diff --git a/hexrd/ui/ranges_table_editor.py b/hexrd/ui/ranges_table_editor.py index 2db0ed83d..e7650fcc3 100644 --- a/hexrd/ui/ranges_table_editor.py +++ b/hexrd/ui/ranges_table_editor.py @@ -1,11 +1,12 @@ import copy import numpy as np -from PySide2.QtCore import QItemSelectionModel, QObject, QSignalBlocker, Signal +from PySide2.QtCore import QItemSelectionModel, QObject, Signal from PySide2.QtWidgets import QSizePolicy from hexrd.ui.scientificspinbox import ScientificDoubleSpinBox from hexrd.ui.ui_loader import UiLoader +from hexrd.ui.utils import block_signals class RangesTableEditor(QObject): @@ -154,25 +155,26 @@ def update_table(self): self.ui.table, self.ui.table.selectionModel() ] - blockers = [QSignalBlocker(x) for x in block_list] # noqa: F841 - prev_selected = self.selected_row + with block_signals(*block_list): - self.ui.table.setRowCount(len(self._data)) - for i, entry in enumerate(self._data): - for j, datum in enumerate(entry): - if self.data_to_gui_func is not None: - datum = self.data_to_gui_func(datum) - w = self.create_double_spin_box(datum) - self.ui.table.setCellWidget(i, j, w) + prev_selected = self.selected_row - if prev_selected is not None: - select_row = (prev_selected if prev_selected < len(self._data) - else len(self._data) - 1) - self.select_row(select_row) + self.ui.table.setRowCount(len(self._data)) + for i, entry in enumerate(self._data): + for j, datum in enumerate(entry): + if self.data_to_gui_func is not None: + datum = self.data_to_gui_func(datum) + w = self.create_double_spin_box(datum) + self.ui.table.setCellWidget(i, j, w) - # Just in case the selection actually changed... - self.update_enable_states() + if prev_selected is not None: + select_row = (prev_selected if prev_selected < len(self._data) + else len(self._data) - 1) + self.select_row(select_row) + + # Just in case the selection actually changed... + self.update_enable_states() def table_data(self, row, column): val = self.ui.table.cellWidget(row, column).value() diff --git a/hexrd/ui/reflections_table.py b/hexrd/ui/reflections_table.py index baa89e528..37074558b 100644 --- a/hexrd/ui/reflections_table.py +++ b/hexrd/ui/reflections_table.py @@ -3,14 +3,14 @@ import numpy as np -from PySide2.QtCore import Qt, QItemSelectionModel, QSignalBlocker +from PySide2.QtCore import Qt, QItemSelectionModel from PySide2.QtWidgets import QTableWidgetItem from hexrd.crystallography import hklToStr from hexrd.ui.hexrd_config import HexrdConfig from hexrd.ui.ui_loader import UiLoader -from hexrd.ui.utils import exclusions_off, tth_max_off +from hexrd.ui.utils import block_signals, exclusions_off, tth_max_off class COLUMNS: @@ -107,13 +107,13 @@ def selected_rows(self): @selected_rows.setter def selected_rows(self, rows): selection_model = self.ui.table.selectionModel() - blocker = QSignalBlocker(selection_model) # noqa: F841 - selection_model.clear() + with block_signals(selection_model): + selection_model.clear() - command = QItemSelectionModel.Select | QItemSelectionModel.Rows - for i in rows: - model_index = selection_model.model().index(i, 0) - selection_model.select(model_index, command) + command = QItemSelectionModel.Select | QItemSelectionModel.Rows + for i in rows: + model_index = selection_model.model().index(i, 0) + selection_model.select(model_index, command) def active_material_modified(self): if HexrdConfig().active_material is self.material: @@ -131,78 +131,78 @@ def update_table(self): table, table.selectionModel() ] - blockers = [QSignalBlocker(x) for x in block_list] # noqa: F841 - - plane_data = material.planeData - - # For the table, we will turn off exclusions so that all - # rows are displayed, even the excluded ones. The user - # picks the exclusions by selecting the rows. - with exclusions_off(plane_data): - with tth_max_off(plane_data): - hkls = plane_data.getHKLs(asStr=True) - d_spacings = plane_data.getPlaneSpacings() - tth = plane_data.getTTh() - sf = plane_data.structFact - powder_intensity = plane_data.powder_intensity - multiplicity = plane_data.getMultiplicity() - - # Grab the hkl ids - hkl_ids = [-1] * len(hkls) - for hkl_data in plane_data.hklDataList: - try: - idx = hkls.index(hklToStr(hkl_data['hkl'])) - except ValueError: - continue - else: - hkl_ids[idx] = hkl_data['hklID'] - - # Since structure factors use arbitrary scaling, re-scale them - # to a range that's easier on the eyes. - rescale_structure_factors(sf) - - self.update_hkl_index_maps(hkls) - - table.clearContents() - table.setRowCount(len(hkls)) - - # We have to disable sorting while adding items, or else Qt - # will automatically move some rows in the middle of setItem(). - # After sorting is enabled again, Qt sorts the table. - with sorting_disabled(table): - for i, hkl in enumerate(hkls): - table_item = IntTableItem(hkl_ids[i]) - table.setItem(i, COLUMNS.ID, table_item) - - table_item = HklTableItem(hkl) - table.setItem(i, COLUMNS.HKL, table_item) - - table_item = FloatTableItem(d_spacings[i]) - table.setItem(i, COLUMNS.D_SPACING, table_item) - table_item = FloatTableItem(math.degrees(tth[i])) - table.setItem(i, COLUMNS.TTH, table_item) - - table_item = FloatTableItem(sf[i]) - table.setItem(i, COLUMNS.SF, table_item) - - table_item = FloatTableItem(powder_intensity[i]) - table.setItem(i, COLUMNS.POWDER_INTENSITY, table_item) - - table_item = IntTableItem(multiplicity[i]) - table.setItem(i, COLUMNS.MULTIPLICITY, table_item) - - # Set the selectability for the entire row - selectable = True - if plane_data.tThMax is not None: - selectable = tth[i] <= plane_data.tThMax - - self.set_row_selectable(i, selectable) - - table.resizeColumnsToContents() - - self.update_selected_rows() - self.update_material_name() + with block_signals(*block_list): + plane_data = material.planeData + + # For the table, we will turn off exclusions so that all + # rows are displayed, even the excluded ones. The user + # picks the exclusions by selecting the rows. + with exclusions_off(plane_data): + with tth_max_off(plane_data): + hkls = plane_data.getHKLs(asStr=True) + d_spacings = plane_data.getPlaneSpacings() + tth = plane_data.getTTh() + sf = plane_data.structFact + powder_intensity = plane_data.powder_intensity + multiplicity = plane_data.getMultiplicity() + + # Grab the hkl ids + hkl_ids = [-1] * len(hkls) + for hkl_data in plane_data.hklDataList: + try: + idx = hkls.index(hklToStr(hkl_data['hkl'])) + except ValueError: + continue + else: + hkl_ids[idx] = hkl_data['hklID'] + + # Since structure factors use arbitrary scaling, re-scale them + # to a range that's easier on the eyes. + rescale_structure_factors(sf) + + self.update_hkl_index_maps(hkls) + + table.clearContents() + table.setRowCount(len(hkls)) + + # We have to disable sorting while adding items, or else Qt + # will automatically move some rows in the middle of setItem(). + # After sorting is enabled again, Qt sorts the table. + with sorting_disabled(table): + for i, hkl in enumerate(hkls): + table_item = IntTableItem(hkl_ids[i]) + table.setItem(i, COLUMNS.ID, table_item) + + table_item = HklTableItem(hkl) + table.setItem(i, COLUMNS.HKL, table_item) + + table_item = FloatTableItem(d_spacings[i]) + table.setItem(i, COLUMNS.D_SPACING, table_item) + + table_item = FloatTableItem(math.degrees(tth[i])) + table.setItem(i, COLUMNS.TTH, table_item) + + table_item = FloatTableItem(sf[i]) + table.setItem(i, COLUMNS.SF, table_item) + + table_item = FloatTableItem(powder_intensity[i]) + table.setItem(i, COLUMNS.POWDER_INTENSITY, table_item) + + table_item = IntTableItem(multiplicity[i]) + table.setItem(i, COLUMNS.MULTIPLICITY, table_item) + + # Set the selectability for the entire row + selectable = True + if plane_data.tThMax is not None: + selectable = tth[i] <= plane_data.tThMax + + self.set_row_selectable(i, selectable) + + table.resizeColumnsToContents() + + self.update_selected_rows() + self.update_material_name() def update_hkl_index_maps(self, hkls): self.hkl_to_index_map = {x: i for i, x in enumerate(hkls)}