class MappingGroupBox(QGroupBox): def __init__(self, tab, root_config_path): super(MappingGroupBox, self).__init__("Mapping") self.tab = tab self.main_window = tab.main_window self.root_config_path = root_config_path self.layout = QFormLayout() config = self.tab.main_window.config self.formats = self.get_mapping_formats(config) self.input_label = Label("From:", self.tab, f"{root_config_path}.input_format") self.input_combo = MappingCombo(self.tab, f"{root_config_path}.input_format", self.formats) self.layout.addRow(self.input_label, self.input_combo) self.output_label = Label("To:", self.tab, f"{root_config_path}.output_format") self.output_combo = MappingCombo(self.tab, f"{root_config_path}.output_format", self.formats) self.layout.addRow(self.output_label, self.output_combo) self.setLayout(self.layout) @classmethod def get_mapping_formats(cls, config): return [None] + list( FileMapping(config, "", raise_errors=False).mapping_graph.nodes)
def tab_microenv(self): layout = QFormLayout() sex = QHBoxLayout() sex.addWidget(QRadioButton("Male")) sex.addWidget(QRadioButton("Female")) layout.addRow(QLabel("Sex"), sex) layout.addRow("Date of Birth", QLineEdit()) # self.setTabText(1,"Microenvironment") self.tab2.setLayout(layout)
def __init__(self): super(PatientWeightDialog, self).__init__() # Class variables self.patient_weight_message = "Patient weight is needed for SUV2ROI " self.patient_weight_message += "conversion.\nPlease enter patient " self.patient_weight_message += "weight in kg." # Get stylesheet if platform.system() == 'Darwin': self.stylesheet_path = "res/stylesheet.qss" else: self.stylesheet_path = "res/stylesheet-win-linux.qss" self.stylesheet = open(resource_path(self.stylesheet_path)).read() self.setWindowIcon( QtGui.QIcon("res/images/btn-icons/onkodicom_icon.png")) buttonBox = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, self) self.patient_weight_message_label = QLabel(self.patient_weight_message) self.patient_weight_prompt = QLabel("Patient Weight:") self.patient_weight_entry = QLineEdit() self.text_font = QtGui.QFont() self.text_font.setPointSize(11) # Set button object names buttonBox.button(QDialogButtonBox.Ok).setProperty( "QPushButtonClass", "success-button") buttonBox.button(QDialogButtonBox.Cancel).setProperty( "QPushButtonClass", "fail-button") # Set stylesheets buttonBox.setStyleSheet(self.stylesheet) self.patient_weight_message_label.setFont(self.text_font) self.patient_weight_message_label.setStyleSheet(self.stylesheet) self.patient_weight_prompt.setMinimumHeight(36) self.patient_weight_prompt.setMargin(4) self.patient_weight_prompt.setFont(self.text_font) self.patient_weight_prompt.setAlignment(QtCore.Qt.AlignVCenter | QtCore.Qt.AlignHCenter) self.patient_weight_prompt.setStyleSheet(self.stylesheet) self.patient_weight_entry.setStyleSheet(self.stylesheet) # Input dialog layout entry_layout = QFormLayout(self) entry_layout.addRow(self.patient_weight_message_label) entry_layout.addRow(self.patient_weight_prompt, self.patient_weight_entry) entry_layout.addWidget(buttonBox) buttonBox.accepted.connect(self.accepting) buttonBox.rejected.connect(self.rejecting) self.setWindowTitle("Enter Patient Weight")
def create_gui(self): self.setWindowTitle('Trigger Editor') icon_path = self.path / 'trigger.png' icon = QIcon(str(icon_path.resolve())) self.setWindowIcon(icon) form_layout = QFormLayout() form_layout.addRow('Trigger Name:', self.name) form_layout.addRow('Search Text:', self.search_text) form_layout.addRow('Alert Text:', self.alert_text) form_layout.addRow('Use Audio:', self.use_audio) form_layout.addRow(self.button_box) self.setLayout(form_layout) self.open()
def __init__(self, standard_name, fma_id, organ, url): super(Dialog_Organ, self).__init__() # Passing the current values if it is an existing option or empty if its a new one self.standard_name = standard_name self.setWindowIcon( QtGui.QIcon( resource_path("res/images/btn-icons/onkodicom_icon.png"))) self.fma_id = fma_id self.organ = organ self.url = url # Creating the UI components button_box = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, self) self.standard_name_header = QLineEdit() self.standard_name_header.setText(self.standard_name) self.fma_id_header = QLineEdit() self.fma_id_header.setText(self.fma_id) self.organ_header = QLineEdit() self.organ_header.setText(self.organ) self.url_header = QLineEdit() self.url_header.setText(self.url) layout = QFormLayout(self) layout.addRow(QLabel("Standard Name:"), self.standard_name_header) layout.addRow(QLabel("FMA ID:"), self.fma_id_header) layout.addRow(QLabel("Organ:"), self.organ_header) layout.addRow(QLabel("Url:"), self.url_header) layout.addWidget(button_box) button_box.accepted.connect(self.accepting) button_box.rejected.connect(self.reject) self.setWindowTitle("Standard Organ Names")
def __init__(self) -> None: super().__init__() # member self.combobox_parameter1 = IM3536ParameterCombobox() self.combobox_parameter2 = IM3536ParameterCombobox() self.combobox_parameter3 = IM3536ParameterCombobox() self.combobox_parameter4 = IM3536ParameterCombobox() self.spinbox_measurements_num = QSpinBox() self.checkbox_parmanent = QCheckBox("Parmanent Measurement") self.checkbox_acquire_monitor_data = QCheckBox( "Acquire Voltage/Current Monitor Values") self.group_parameter = QGroupBox("Parameter") self.group_only_lcr = QGroupBox("Only LCR Meter Mode") self.group_option = QGroupBox("Option") # setup self.combobox_parameter1.setCurrentText( "Rs (Equivalent series resistance)") self.combobox_parameter1.set_none_disabled(True) self.spinbox_measurements_num.setRange(1, 1000000000) self.checkbox_acquire_monitor_data.setChecked(True) self.checkbox_parmanent.setChecked(True) self.spinbox_measurements_num.setEnabled(False) self.group_only_lcr.setEnabled(False) # stup layout f_layout_parameter = QFormLayout() f_layout_parameter.addRow("1", self.combobox_parameter1) f_layout_parameter.addRow("2", self.combobox_parameter2) f_layout_parameter.addRow("3", self.combobox_parameter3) f_layout_parameter.addRow("4", self.combobox_parameter4) self.group_parameter.setLayout(f_layout_parameter) f_layout_only_lcr = QFormLayout() f_layout_only_lcr.addRow(self.checkbox_parmanent) f_layout_only_lcr.addRow("Number of Measurements", self.spinbox_measurements_num) self.group_only_lcr.setLayout(f_layout_only_lcr) f_layout_option = QFormLayout() f_layout_option.addRow(self.checkbox_acquire_monitor_data) self.group_option.setLayout(f_layout_option) v_layout = AVBoxLayout(self) v_layout.addWidget(self.group_parameter) v_layout.addWidget(self.group_only_lcr) v_layout.addWidget(self.group_option)
def __init__(self, parent=None): super(Winform, self).__init__(parent) self.setWindowTitle("窗体布局管理例子") self.resize(400, 100) fromlayout = QFormLayout() labl1 = QLabel("标签1") lineEdit1 = QLineEdit() labl2 = QLabel("标签2") lineEdit2 = QLineEdit() labl3 = QLabel("标签3") lineEdit3 = QLineEdit() fromlayout.addRow(labl1, lineEdit1) fromlayout.addRow(labl2, lineEdit2) fromlayout.addRow(labl3, lineEdit3) self.setLayout(fromlayout)
def __init__(self, win_name, scan, upper_level, lower_level): super(Dialog_Windowing, self).__init__() # Passing the current values if it is an existing option or empty if its a new one self.win_name = win_name self.setWindowIcon( QtGui.QIcon( resource_path("res/images/btn-icons/onkodicom_icon.png"))) self.scan = scan self.upper_level = upper_level self.lower_level = lower_level # Create the ui components for the inputs button_box = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, self) self.name = QLineEdit() self.name.setText(self.win_name) self.scan_text = QLineEdit() self.scan_text.setText(self.scan) self.upper_level_text = QLineEdit() self.upper_level_text.setText(self.upper_level) self.lower_level_text = QLineEdit() self.lower_level_text.setText(self.lower_level) layout = QFormLayout(self) layout.addRow(QLabel("Window Name:"), self.name) layout.addRow(QLabel("Scan:"), self.scan_text) layout.addRow(QLabel("Upper Value:"), self.upper_level_text) layout.addRow(QLabel("Lower Value:"), self.lower_level_text) layout.addWidget(button_box) button_box.accepted.connect(self.accepting) button_box.rejected.connect(self.reject) self.setWindowTitle("Image Windowing")
def __init__(self, dose, notes): super(Dialog_Dose, self).__init__() # Class variables self.dose = dose self.notes = notes self.setWindowIcon( QtGui.QIcon("res/images/btn-icons/onkodicom_icon.png")) buttonBox = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, self) self.iso_dose = QLineEdit() self.iso_dose.setText(self.dose) self.iso_unit = QComboBox() self.iso_unit.addItems(["cGy", "%"]) self.iso_notes = QLineEdit() self.iso_notes.setText(self.notes) # Input dialog layout layout = QFormLayout(self) layout.addRow(QLabel("Isodose Level:"), self.iso_dose) layout.addRow(QLabel("Unit:"), self.iso_unit) layout.addRow(QLabel("Notes:"), self.iso_notes) layout.addWidget(buttonBox) buttonBox.accepted.connect(self.accepting) buttonBox.rejected.connect(self.reject) self.setWindowTitle("Isodose Levels")
class MyWidget(QWidget): def __init__(self): super().__init__() self._init_UI() def set_text(self): input_d = QInputDialog(self) res_text, res_ok = input_d.getText(self, "title", "text:") if res_ok: self.text.setText(res_text) def set_title(self): self.setWindowTitle(self.form_name.text()) def _init_UI(self): self.setGeometry(300, 300, 250, 150) self.setWindowTitle('Example 7') self.label_name = QLabel("form name", self) self.text = QTextEdit("kek", self) # self.kek_btn = QLabel("kek", self) self.kek_btn = QPushButton("kek", self) self.form_name = QLineEdit(self.windowTitle(), self) self.layout = QFormLayout(self) self.layout.addRow(self.label_name, self.form_name) self.layout.addRow(self.kek_btn, self.text) self.form_name.textChanged.connect(self.set_title) self.kek_btn.clicked.connect(self.set_text) # self.layout.addWidget(self.kek_btn, 0, 0) # self.layout.addWidget(self.text, 0, 1) self.setLayout(self.layout) self.show()
def __init__(self, standard_name, volume_name): super(Dialog_Volume, self).__init__() # Passing the current values if it is an existing option or empty if its a new one self.standard_name = standard_name self.volume_name = volume_name # Creating the UI components self.setWindowIcon( QtGui.QIcon( resource_path("res/images/btn-icons/onkodicom_icon.png"))) button_box = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, self) self.standard_name_text = QLineEdit() self.standard_name_text.setText(self.standard_name) self.volume = QLineEdit() self.volume.setText(self.volume_name) layout = QFormLayout(self) layout.addRow(QLabel("Standard Name:"), self.standard_name_text) layout.addRow(QLabel("Volume Name:"), self.volume) layout.addWidget(button_box) button_box.accepted.connect(self.accepting) button_box.rejected.connect(self.reject) self.setWindowTitle("Standard Volume Names")
def create_gui(self): self.setWindowTitle('Group Editor') icon_path = self.path / 'group.png' icon = QIcon(str(icon_path.resolve())) self.setWindowIcon(icon) form_layout = QFormLayout() self.setLayout(form_layout) form_layout.addRow('Group Name:', self.name) form_layout.addRow('Comments: ', self.comments) form_layout.addRow(self.button_box) self.setLayout(form_layout) self.open()
def __init__(self) -> None: super().__init__() # member self.pathname_line = PathLine() self.checkbox_save_to_file = QCheckBox("Save to File") self.t_button_open_filedialog = create_tool_button( is_text_beside_icon=True) self.t_button_step_mode = create_tool_button(fixed_width=250) self.t_button_cycle_mode = create_tool_button(fixed_width=250) self.t_button_only_lcr_mode = create_tool_button(fixed_width=250) self.t_button_lcr_state = create_tool_button(fixed_width=250) self.spinbox_interval = QSpinBox() self.group_save = QGroupBox("Save") self.group_mode = QGroupBox("Mode") self.group_lcr_state = QGroupBox("LCR Meter") self.group_measure_interval = QGroupBox("Measurement Interval") # setup self.spinbox_interval.setRange(1, 100000) self.checkbox_save_to_file.setEnabled(False) # setup layout f_layout_save = QFormLayout() f_layout_save.addRow("File Path", self.pathname_line) f_layout_save.addWidget(self.t_button_open_filedialog) f_layout_save.addRow(self.checkbox_save_to_file) self.group_save.setLayout(f_layout_save) v_layout_mode = AVBoxLayout() v_layout_mode.addWidget(self.t_button_step_mode) v_layout_mode.addWidget(self.t_button_cycle_mode) v_layout_mode.addWidget(self.t_button_only_lcr_mode) v_layout_mode.setAlignment(Qt.AlignHCenter) self.group_mode.setLayout(v_layout_mode) v_layout_lcr_state = AVBoxLayout() v_layout_lcr_state.addWidget(self.t_button_lcr_state) v_layout_lcr_state.setAlignment(Qt.AlignHCenter) self.group_lcr_state.setLayout(v_layout_lcr_state) f_layout_repeat = QFormLayout() f_layout_repeat.addRow("Interval", add_unit(self.spinbox_interval, "msec")) self.group_measure_interval.setLayout(f_layout_repeat) v_layout = AVBoxLayout(self) v_layout.addWidget(self.group_save) v_layout.addWidget(self.group_mode) v_layout.addWidget(self.group_lcr_state) v_layout.addWidget(self.group_measure_interval)
def __init__(self) -> None: super().__init__() self.spinbox_distance = QSpinBox() self.spinbox_cycle_num = QSpinBox() self.int_slider = IntSlider() self.spinbox_stop_interval = QSpinBox() # setup self.spinbox_distance.setRange(1, 100000) self.spinbox_cycle_num.setRange(1, 100000) self.int_slider.range = 1, 50000 self.spinbox_stop_interval.setRange(0, 10000) # setup layout f_layout = QFormLayout(self) f_layout.addRow("Displacement", add_unit(self.spinbox_distance, "μm")) f_layout.addRow("Number of Cycle", add_unit(self.spinbox_cycle_num, "times")) f_layout.addRow("Speed", add_unit(self.int_slider, "μm/sec")) f_layout.addRow("Stop Interval", add_unit(self.spinbox_stop_interval, "msec"))
def init_ui(self): self.setFixedSize(200, 100) self.move2center() btn_color: QPushButton = QPushButton('颜色!') btn_color.clicked.connect(self.show_color_dialog) grid = QFormLayout() grid.addRow('换个', btn_color) grid.addRow('开始', self.time_editor_start) grid.addRow('结束', self.time_editor_end) self.setLayout(grid) self.setWindowTitle('Settings')
def __init__(self): super(MainWindow, self).__init__() centralWidget = QWidget() self.setCentralWidget(centralWidget) layout = QFormLayout(centralWidget) textLayout = QHBoxLayout() self.text = QLineEdit('Hello, PySide6') self.text.setClearButtonEnabled(True) textLayout.addWidget(self.text) self.sayButton = QPushButton('Say') textLayout.addWidget(self.sayButton) self.text.returnPressed.connect(self.sayButton.animateClick) self.sayButton.clicked.connect(self.say) layout.addRow('Text:', textLayout) self.voiceCombo = QComboBox() layout.addRow('Voice:', self.voiceCombo) self.volumeSlider = QSlider(Qt.Horizontal) self.volumeSlider.setMinimum(0) self.volumeSlider.setMaximum(100) self.volumeSlider.setValue(100) layout.addRow('Volume:', self.volumeSlider) self.engine = None engineNames = QTextToSpeech.availableEngines() if len(engineNames) > 0: engineName = engineNames[0] self.engine = QTextToSpeech(engineName) self.engine.stateChanged.connect(self.stateChanged) self.setWindowTitle( 'QTextToSpeech Example ({})'.format(engineName)) self.voices = [] for voice in self.engine.availableVoices(): self.voices.append(voice) self.voiceCombo.addItem(voice.name()) else: self.setWindowTitle('QTextToSpeech Example (no engines available)') self.sayButton.setEnabled(False)
class AdapterSettingsDialog(QDialog): def __init__(self, parent, data): assert type(data) == BinaryView self.bv = data QDialog.__init__(self, parent) debug_state = binjaplug.get_state(self.bv) self.setWindowTitle("Debug Adapter Settings") self.setMinimumSize(UIContext.getScaledWindowSize(400, 130)) self.setAttribute(Qt.WA_DeleteOnClose) layout = QVBoxLayout() layout.setSpacing(0) titleLabel = QLabel("Adapter Settings") titleLayout = QHBoxLayout() titleLayout.setContentsMargins(0, 0, 0, 0) titleLayout.addWidget(titleLabel) self.adapterEntry = QPushButton(self) self.adapterMenu = QMenu(self) for adapter in DebugAdapter.ADAPTER_TYPE: if not DebugAdapter.ADAPTER_TYPE.can_use(adapter): continue def select_adapter(adapter): return lambda: self.selectAdapter(adapter) self.adapterMenu.addAction(adapter.name, select_adapter(adapter)) if adapter == debug_state.adapter_type: self.adapterEntry.setText(adapter.name) self.adapterEntry.setMenu(self.adapterMenu) self.argumentsEntry = QLineEdit(self) self.addressEntry = QLineEdit(self) self.portEntry = QLineEdit(self) self.requestTerminalEmulator = QCheckBox(self) self.formLayout = QFormLayout() self.formLayout.addRow("Adapter Type", self.adapterEntry) self.formLayout.addRow("Command Line Arguments", self.argumentsEntry) self.formLayout.addRow("Address", self.addressEntry) self.formLayout.addRow("Port", self.portEntry) self.formLayout.addRow("Request Terminal Emulator", self.requestTerminalEmulator) buttonLayout = QHBoxLayout() buttonLayout.setContentsMargins(0, 0, 0, 0) self.cancelButton = QPushButton("Cancel") self.cancelButton.clicked.connect(lambda: self.reject()) self.acceptButton = QPushButton("Accept") self.acceptButton.clicked.connect(lambda: self.accept()) self.acceptButton.setDefault(True) buttonLayout.addStretch(1) buttonLayout.addWidget(self.cancelButton) buttonLayout.addWidget(self.acceptButton) layout.addLayout(titleLayout) layout.addSpacing(10) layout.addLayout(self.formLayout) layout.addStretch(1) layout.addSpacing(10) layout.addLayout(buttonLayout) self.setLayout(layout) self.addressEntry.setText(debug_state.remote_host) self.portEntry.setText(str(debug_state.remote_port)) self.addressEntry.textEdited.connect(lambda: self.apply()) self.portEntry.textEdited.connect(lambda: self.apply()) self.argumentsEntry.setText(' '.join( shlex.quote(arg) for arg in debug_state.command_line_args)) self.argumentsEntry.textEdited.connect(lambda: self.updateArguments()) self.requestTerminalEmulator.setChecked( debug_state.request_terminal_emulator) self.requestTerminalEmulator.stateChanged.connect(lambda: self.apply()) self.accepted.connect(lambda: self.apply()) def selectAdapter(self, adapter): self.bv.store_metadata('debugger.adapter_type', adapter.value) debug_state = binjaplug.get_state(self.bv) debug_state.adapter_type = adapter self.adapterEntry.setText(adapter.name) if DebugAdapter.ADAPTER_TYPE.use_exec(adapter): self.argumentsEntry.setEnabled(True) self.addressEntry.setEnabled(False) self.portEntry.setEnabled(False) elif DebugAdapter.ADAPTER_TYPE.use_connect(adapter): self.argumentsEntry.setEnabled(False) self.addressEntry.setEnabled(True) self.portEntry.setEnabled(True) def apply(self): debug_state = binjaplug.get_state(self.bv) arguments = shlex.split(self.argumentsEntry.text()) debug_state.command_line_args = arguments self.bv.store_metadata('debugger.command_line_args', arguments) address = self.addressEntry.text() port = int(self.portEntry.text()) debug_state.remote_host = address debug_state.remote_port = port self.bv.store_metadata('debugger.remote_host', address) self.bv.store_metadata('debugger.remote_port', port) request_terminal_emulator = self.requestTerminalEmulator.isChecked() debug_state.request_terminal_emulator = request_terminal_emulator self.bv.store_metadata('debugger.request_terminal_emulator', request_terminal_emulator) def updateArguments(self): try: arguments = shlex.split(self.argumentsEntry.text()) self.acceptButton.setEnabled(True) except: self.acceptButton.setEnabled(False)
class MainWidget(QWidget): def __init__(self, parent=None): super(MainWidget, self).__init__(parent) self.chart = QChart() self.series = QBarSeries() self.main_layout = QGridLayout() self.button_layout = QGridLayout() self.font_layout = QFormLayout() self.font_size = QDoubleSpinBox() self.legend_posx = QDoubleSpinBox() self.legend_posy = QDoubleSpinBox() self.legend_width = QDoubleSpinBox() self.legend_height = QDoubleSpinBox() self.detach_legend_button = QPushButton("Toggle attached") self.detach_legend_button.clicked.connect(self.toggle_attached) self.button_layout.addWidget(self.detach_legend_button, 0, 0) self.add_set_button = QPushButton("add barset") self.add_set_button.clicked.connect(self.add_barset) self.button_layout.addWidget(self.add_set_button, 2, 0) self.remove_barset_button = QPushButton("remove barset") self.remove_barset_button.clicked.connect(self.remove_barset) self.button_layout.addWidget(self.remove_barset_button, 3, 0) self.align_button = QPushButton("Align (Bottom)") self.align_button.clicked.connect(self.set_legend_alignment) self.button_layout.addWidget(self.align_button, 4, 0) self.bold_button = QPushButton("Toggle bold") self.bold_button.clicked.connect(self.toggle_bold) self.button_layout.addWidget(self.bold_button, 8, 0) self.italic_button = QPushButton("Toggle italic") self.italic_button.clicked.connect(self.toggle_italic) self.button_layout.addWidget(self.italic_button, 9, 0) self.legend_posx.valueChanged.connect(self.update_legend_layout) self.legend_posy.valueChanged.connect(self.update_legend_layout) self.legend_width.valueChanged.connect(self.update_legend_layout) self.legend_height.valueChanged.connect(self.update_legend_layout) legend_layout = QFormLayout() legend_layout.addRow("HPos", self.legend_posx) legend_layout.addRow("VPos", self.legend_posy) legend_layout.addRow("Width", self.legend_width) legend_layout.addRow("Height", self.legend_height) self.legend_settings = QGroupBox("Detached legend") self.legend_settings.setLayout(legend_layout) self.button_layout.addWidget(self.legend_settings) self.legend_settings.setVisible(False) # Create chart view with the chart self.chart_view = QChartView(self.chart, self) # Create spinbox to modify font size self.font_size.setValue(self.chart.legend().font().pointSizeF()) self.font_size.valueChanged.connect(self.font_size_changed) self.font_layout.addRow("Legend font size", self.font_size) # Create layout for grid and detached legend self.main_layout.addLayout(self.button_layout, 0, 0) self.main_layout.addLayout(self.font_layout, 1, 0) self.main_layout.addWidget(self.chart_view, 0, 1, 3, 1) self.setLayout(self.main_layout) self.create_series() def create_series(self): self.add_barset() self.add_barset() self.add_barset() self.add_barset() self.chart.addSeries(self.series) self.chart.setTitle("Legend detach example") self.chart.createDefaultAxes() self.chart.legend().setVisible(True) self.chart.legend().setAlignment(Qt.AlignBottom) self.chart_view.setRenderHint(QPainter.Antialiasing) def show_legend_spinbox(self): self.legend_settings.setVisible(True) chart_viewrect = self.chart_view.rect() self.legend_posx.setMinimum(0) self.legend_posx.setMaximum(chart_viewrect.width()) self.legend_posx.setValue(150) self.legend_posy.setMinimum(0) self.legend_posy.setMaximum(chart_viewrect.height()) self.legend_posy.setValue(150) self.legend_width.setMinimum(0) self.legend_width.setMaximum(chart_viewrect.width()) self.legend_width.setValue(150) self.legend_height.setMinimum(0) self.legend_height.setMaximum(chart_viewrect.height()) self.legend_height.setValue(75) def hideLegendSpinbox(self): self.legend_settings.setVisible(False) def toggle_attached(self): legend = self.chart.legend() if legend.isAttachedToChart(): legend.detachFromChart() legend.setBackgroundVisible(True) legend.setBrush(QBrush(QColor(128, 128, 128, 128))) legend.setPen(QPen(QColor(192, 192, 192, 192))) self.show_legend_spinbox() self.update_legend_layout() else: legend.attachToChart() legend.setBackgroundVisible(False) self.hideLegendSpinbox() self.update() def add_barset(self): series_count = self.series.count() bar_set = QBarSet(f"set {series_count}") delta = series_count * 0.1 bar_set.append([1 + delta, 2 + delta, 3 + delta, 4 + delta]) self.series.append(bar_set) def remove_barset(self): sets = self.series.barSets() len_sets = len(sets) if len_sets > 0: self.series.remove(sets[len_sets - 1]) def set_legend_alignment(self): button = self.sender() legend = self.chart.legend() alignment = legend.alignment() if alignment == Qt.AlignTop: legend.setAlignment(Qt.AlignLeft) if button: button.setText("Align (Left)") elif alignment == Qt.AlignLeft: legend.setAlignment(Qt.AlignBottom) if button: button.setText("Align (Bottom)") elif alignment == Qt.AlignBottom: legend.setAlignment(Qt.AlignRight) if button: button.setText("Align (Right)") else: if button: button.setText("Align (Top)") legend.setAlignment(Qt.AlignTop) def toggle_bold(self): legend = self.chart.legend() font = legend.font() font.setBold(not font.bold()) legend.setFont(font) def toggle_italic(self): legend = self.chart.legend() font = legend.font() font.setItalic(not font.italic()) legend.setFont(font) def font_size_changed(self): legend = self.chart.legend() font = legend.font() font_size = self.font_size.value() if font_size < 1: font_size = 1 font.setPointSizeF(font_size) legend.setFont(font) def update_legend_layout(self): legend = self.chart.legend() rect = QRectF(self.legend_posx.value(), self.legend_posy.value(), self.legend_width.value(), self.legend_height.value()) legend.setGeometry(rect) legend.update()
def __init__(self, parent=None): super(MainWidget, self).__init__(parent) self.chart = QChart() self.series = QBarSeries() self.main_layout = QGridLayout() self.button_layout = QGridLayout() self.font_layout = QFormLayout() self.font_size = QDoubleSpinBox() self.legend_posx = QDoubleSpinBox() self.legend_posy = QDoubleSpinBox() self.legend_width = QDoubleSpinBox() self.legend_height = QDoubleSpinBox() self.detach_legend_button = QPushButton("Toggle attached") self.detach_legend_button.clicked.connect(self.toggle_attached) self.button_layout.addWidget(self.detach_legend_button, 0, 0) self.add_set_button = QPushButton("add barset") self.add_set_button.clicked.connect(self.add_barset) self.button_layout.addWidget(self.add_set_button, 2, 0) self.remove_barset_button = QPushButton("remove barset") self.remove_barset_button.clicked.connect(self.remove_barset) self.button_layout.addWidget(self.remove_barset_button, 3, 0) self.align_button = QPushButton("Align (Bottom)") self.align_button.clicked.connect(self.set_legend_alignment) self.button_layout.addWidget(self.align_button, 4, 0) self.bold_button = QPushButton("Toggle bold") self.bold_button.clicked.connect(self.toggle_bold) self.button_layout.addWidget(self.bold_button, 8, 0) self.italic_button = QPushButton("Toggle italic") self.italic_button.clicked.connect(self.toggle_italic) self.button_layout.addWidget(self.italic_button, 9, 0) self.legend_posx.valueChanged.connect(self.update_legend_layout) self.legend_posy.valueChanged.connect(self.update_legend_layout) self.legend_width.valueChanged.connect(self.update_legend_layout) self.legend_height.valueChanged.connect(self.update_legend_layout) legend_layout = QFormLayout() legend_layout.addRow("HPos", self.legend_posx) legend_layout.addRow("VPos", self.legend_posy) legend_layout.addRow("Width", self.legend_width) legend_layout.addRow("Height", self.legend_height) self.legend_settings = QGroupBox("Detached legend") self.legend_settings.setLayout(legend_layout) self.button_layout.addWidget(self.legend_settings) self.legend_settings.setVisible(False) # Create chart view with the chart self.chart_view = QChartView(self.chart, self) # Create spinbox to modify font size self.font_size.setValue(self.chart.legend().font().pointSizeF()) self.font_size.valueChanged.connect(self.font_size_changed) self.font_layout.addRow("Legend font size", self.font_size) # Create layout for grid and detached legend self.main_layout.addLayout(self.button_layout, 0, 0) self.main_layout.addLayout(self.font_layout, 1, 0) self.main_layout.addWidget(self.chart_view, 0, 1, 3, 1) self.setLayout(self.main_layout) self.create_series()
class UIManipulateROIWindow: def setup_ui(self, manipulate_roi_window_instance, rois, dataset_rtss, roi_color, signal_roi_manipulated): self.patient_dict_container = PatientDictContainer() self.rois = rois self.dataset_rtss = dataset_rtss self.signal_roi_manipulated = signal_roi_manipulated self.roi_color = roi_color self.roi_names = [] # Names of selected ROIs self.all_roi_names = [] # Names of all existing ROIs for roi_id, roi_dict in self.rois.items(): self.all_roi_names.append(roi_dict['name']) # Operation names self.single_roi_operation_names = [ "Expand", "Contract", "Inner Rind (annulus)", "Outer Rind (annulus)" ] self.multiple_roi_operation_names = [ "Union", "Intersection", "Difference" ] self.operation_names = self.multiple_roi_operation_names + \ self.single_roi_operation_names self.new_ROI_contours = None self.manipulate_roi_window_instance = manipulate_roi_window_instance self.dicom_view = DicomAxialView(metadata_formatted=True, is_four_view=True) self.dicom_preview = DicomAxialView(metadata_formatted=True, is_four_view=True) self.dicom_view.slider.valueChanged.connect( self.dicom_view_slider_value_changed) self.dicom_preview.slider.valueChanged.connect( self.dicom_preview_slider_value_changed) self.init_layout() QtCore.QMetaObject.connectSlotsByName(manipulate_roi_window_instance) def retranslate_ui(self, manipulate_roi_window_instance): _translate = QtCore.QCoreApplication.translate manipulate_roi_window_instance.setWindowTitle( _translate("ManipulateRoiWindowInstance", "OnkoDICOM - Draw Region Of Interest")) self.first_roi_name_label.setText( _translate("FirstROINameLabel", "ROI 1: ")) self.first_roi_name_dropdown_list.setPlaceholderText("ROI 1") self.first_roi_name_dropdown_list.addItems(self.all_roi_names) self.operation_name_label.setText( _translate("OperationNameLabel", "Operation")) self.operation_name_dropdown_list.setPlaceholderText("Operation") self.operation_name_dropdown_list.addItems(self.operation_names) self.second_roi_name_label.setText( _translate("SecondROINameLabel", "ROI 2: ")) self.second_roi_name_dropdown_list.setPlaceholderText("ROI 2") self.second_roi_name_dropdown_list.addItems(self.all_roi_names) self.manipulate_roi_window_instance_draw_button.setText( _translate("ManipulateRoiWindowInstanceDrawButton", "Draw")) self.manipulate_roi_window_instance_save_button.setText( _translate("ManipulateRoiWindowInstanceSaveButton", "Save")) self.manipulate_roi_window_instance_cancel_button.setText( _translate("ManipulateRoiWindowInstanceCancelButton", "Cancel")) self.margin_label.setText(_translate("MarginLabel", "Margin (mm): ")) self.new_roi_name_label.setText( _translate("NewROINameLabel", "New ROI Name")) self.ROI_view_box_label.setText("ROI") self.preview_box_label.setText("Preview") def init_layout(self): """ Initialize the layout for the DICOM View tab. Add the view widget and the slider in the layout. Add the whole container 'tab2_view' as a tab in the main page. """ # Initialise a ManipulateROIWindow if platform.system() == 'Darwin': self.stylesheet_path = "res/stylesheet.qss" else: self.stylesheet_path = "res/stylesheet-win-linux.qss" stylesheet = open(resource_path(self.stylesheet_path)).read() window_icon = QIcon() window_icon.addPixmap(QPixmap(resource_path("res/images/icon.ico")), QIcon.Normal, QIcon.Off) self.manipulate_roi_window_instance.setObjectName( "ManipulateRoiWindowInstance") self.manipulate_roi_window_instance.setWindowIcon(window_icon) # Creating a form box to hold all buttons and input fields self.manipulate_roi_window_input_container_box = QFormLayout() self.manipulate_roi_window_input_container_box.setObjectName( "ManipulateRoiWindowInputContainerBox") self.manipulate_roi_window_input_container_box.setLabelAlignment( Qt.AlignLeft) # Create a label for denoting the first ROI name self.first_roi_name_label = QLabel() self.first_roi_name_label.setObjectName("FirstROINameLabel") self.first_roi_name_dropdown_list = QComboBox() # Create an dropdown list for ROI name self.first_roi_name_dropdown_list.setObjectName( "FirstROINameDropdownList") self.first_roi_name_dropdown_list.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.Minimum) self.first_roi_name_dropdown_list.resize( self.first_roi_name_dropdown_list.sizeHint().width(), self.first_roi_name_dropdown_list.sizeHint().height()) self.first_roi_name_dropdown_list.activated.connect( self.update_selected_rois) self.manipulate_roi_window_input_container_box.addRow( self.first_roi_name_label, self.first_roi_name_dropdown_list) # Create a label for denoting the operation self.operation_name_label = QLabel() self.operation_name_label.setObjectName("OperationNameLabel") self.operation_name_dropdown_list = QComboBox() # Create an dropdown list for operation name self.operation_name_dropdown_list.setObjectName( "OperationNameDropdownList") self.operation_name_dropdown_list.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.Minimum) self.operation_name_dropdown_list.resize( self.operation_name_dropdown_list.sizeHint().width(), self.operation_name_dropdown_list.sizeHint().height()) self.operation_name_dropdown_list.activated.connect( self.operation_changed) self.manipulate_roi_window_input_container_box.addRow( self.operation_name_label, self.operation_name_dropdown_list) # Create a label for denoting the second ROI name self.second_roi_name_label = QLabel() self.second_roi_name_label.setObjectName("SecondROINameLabel") self.second_roi_name_label.setVisible(False) self.second_roi_name_dropdown_list = QComboBox() # Create an dropdown list for ROI name self.second_roi_name_dropdown_list.setObjectName( "SecondROINameDropdownList") self.second_roi_name_dropdown_list.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.Minimum) self.second_roi_name_dropdown_list.resize( self.second_roi_name_dropdown_list.sizeHint().width(), self.second_roi_name_dropdown_list.sizeHint().height()) self.second_roi_name_dropdown_list.setVisible(False) self.second_roi_name_dropdown_list.activated.connect( self.update_selected_rois) self.manipulate_roi_window_input_container_box.addRow( self.second_roi_name_label, self.second_roi_name_dropdown_list) # Create a label for denoting the margin self.margin_label = QLabel() self.margin_label.setObjectName("MarginLabel") self.margin_label.setVisible(False) # Create input for the new ROI name self.margin_line_edit = QLineEdit() self.margin_line_edit.setObjectName("MarginInput") self.margin_line_edit.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum) self.margin_line_edit.resize(self.margin_line_edit.sizeHint().width(), self.margin_line_edit.sizeHint().height()) self.margin_line_edit.setVisible(False) self.margin_line_edit.setValidator( QRegularExpressionValidator( QRegularExpression("^[0-9]*[.]?[0-9]*$"))) self.manipulate_roi_window_input_container_box.addRow( self.margin_label, self.margin_line_edit) # Create a label for denoting the new ROI name self.new_roi_name_label = QLabel() self.new_roi_name_label.setObjectName("NewROINameLabel") # Create input for the new ROI name self.new_roi_name_line_edit = QLineEdit() self.new_roi_name_line_edit.setObjectName("NewROINameInput") self.new_roi_name_line_edit.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum) self.new_roi_name_line_edit.resize( self.new_roi_name_line_edit.sizeHint().width(), self.new_roi_name_line_edit.sizeHint().height()) self.manipulate_roi_window_input_container_box.addRow( self.new_roi_name_label, self.new_roi_name_line_edit) # Create a spacer between inputs and buttons spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) spacer.setFocusPolicy(Qt.NoFocus) self.manipulate_roi_window_input_container_box.addRow(spacer) # Create a warning message when missing inputs self.warning_message = QWidget() self.warning_message.setContentsMargins(8, 5, 8, 5) warning_message_layout = QHBoxLayout() warning_message_layout.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignLeft) warning_message_icon = QLabel() warning_message_icon.setPixmap( QtGui.QPixmap( resource_path("res/images/btn-icons/alert_icon.png"))) warning_message_layout.addWidget(warning_message_icon) self.warning_message_text = QLabel() self.warning_message_text.setStyleSheet("color: red") warning_message_layout.addWidget(self.warning_message_text) self.warning_message.setLayout(warning_message_layout) self.warning_message.setVisible(False) self.manipulate_roi_window_input_container_box.addRow( self.warning_message) # Create a draw button self.manipulate_roi_window_instance_draw_button = QPushButton() self.manipulate_roi_window_instance_draw_button.setObjectName( "ManipulateRoiWindowInstanceDrawButton") self.manipulate_roi_window_instance_draw_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum)) self.manipulate_roi_window_instance_draw_button.resize( self.manipulate_roi_window_instance_draw_button.sizeHint().width(), self.manipulate_roi_window_instance_draw_button.sizeHint().height( )) self.manipulate_roi_window_instance_draw_button.setCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.manipulate_roi_window_instance_draw_button.clicked.connect( self.onDrawButtonClicked) self.manipulate_roi_window_input_container_box.addRow( self.manipulate_roi_window_instance_draw_button) # Create a horizontal box for saving and cancel the drawing self.manipulate_roi_window_cancel_save_box = QHBoxLayout() self.manipulate_roi_window_cancel_save_box.setObjectName( "ManipulateRoiWindowCancelSaveBox") # Create an exit button to cancel the drawing # Add a button to go back/exit from the application self.manipulate_roi_window_instance_cancel_button = QPushButton() self.manipulate_roi_window_instance_cancel_button.setObjectName( "ManipulateRoiWindowInstanceCancelButton") self.manipulate_roi_window_instance_cancel_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum)) self.manipulate_roi_window_instance_cancel_button.resize( self.manipulate_roi_window_instance_cancel_button.sizeHint().width( ), self.manipulate_roi_window_instance_cancel_button.sizeHint(). height()) self.manipulate_roi_window_instance_cancel_button.setCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.manipulate_roi_window_instance_cancel_button.clicked.connect( self.onCancelButtonClicked) self.manipulate_roi_window_instance_cancel_button.setProperty( "QPushButtonClass", "fail-button") icon_cancel = QtGui.QIcon() icon_cancel.addPixmap( QtGui.QPixmap( resource_path('res/images/btn-icons/cancel_icon.png'))) self.manipulate_roi_window_instance_cancel_button.setIcon(icon_cancel) self.manipulate_roi_window_cancel_save_box.addWidget( self.manipulate_roi_window_instance_cancel_button) # Create a save button to save all the changes self.manipulate_roi_window_instance_save_button = QPushButton() self.manipulate_roi_window_instance_save_button.setObjectName( "ManipulateRoiWindowInstanceSaveButton") self.manipulate_roi_window_instance_save_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum)) self.manipulate_roi_window_instance_save_button.resize( self.manipulate_roi_window_instance_save_button.sizeHint().width(), self.manipulate_roi_window_instance_save_button.sizeHint().height( )) self.manipulate_roi_window_instance_save_button.setProperty( "QPushButtonClass", "success-button") icon_save = QtGui.QIcon() icon_save.addPixmap( QtGui.QPixmap(resource_path('res/images/btn-icons/save_icon.png'))) self.manipulate_roi_window_instance_save_button.setIcon(icon_save) self.manipulate_roi_window_instance_save_button.clicked.connect( self.onSaveClicked) self.manipulate_roi_window_cancel_save_box.addWidget( self.manipulate_roi_window_instance_save_button) self.manipulate_roi_window_input_container_box.addRow( self.manipulate_roi_window_cancel_save_box) # Creating a horizontal box to hold the ROI view and the preview self.manipulate_roi_window_instance_view_box = QHBoxLayout() self.manipulate_roi_window_instance_view_box.setObjectName( "ManipulateRoiWindowInstanceViewBoxes") # Font for the ROI view and preview's labels font = QFont() font.setBold(True) font.setPixelSize(20) # Creating the ROI view self.ROI_view_box_layout = QVBoxLayout() self.ROI_view_box_label = QLabel() self.ROI_view_box_label.setFont(font) self.ROI_view_box_label.setAlignment(Qt.AlignHCenter) self.ROI_view_box_layout.addWidget(self.ROI_view_box_label) self.ROI_view_box_layout.addWidget(self.dicom_view) self.ROI_view_box_widget = QWidget() self.ROI_view_box_widget.setLayout(self.ROI_view_box_layout) # Creating the preview self.preview_box_layout = QVBoxLayout() self.preview_box_label = QLabel() self.preview_box_label.setFont(font) self.preview_box_label.setAlignment(Qt.AlignHCenter) self.preview_box_layout.addWidget(self.preview_box_label) self.preview_box_layout.addWidget(self.dicom_preview) self.preview_box_widget = QWidget() self.preview_box_widget.setLayout(self.preview_box_layout) # Add View and Slider into horizontal box self.manipulate_roi_window_instance_view_box.addWidget( self.ROI_view_box_widget) self.manipulate_roi_window_instance_view_box.addWidget( self.preview_box_widget) # Create a widget to hold the image slice box self.manipulate_roi_window_instance_view_widget = QWidget() self.manipulate_roi_window_instance_view_widget.setObjectName( "ManipulateRoiWindowInstanceActionWidget") self.manipulate_roi_window_instance_view_widget.setLayout( self.manipulate_roi_window_instance_view_box) # Create a horizontal box for containing the input fields and the # viewports self.manipulate_roi_window_main_box = QHBoxLayout() self.manipulate_roi_window_main_box.setObjectName( "ManipulateRoiWindowMainBox") self.manipulate_roi_window_main_box.addLayout( self.manipulate_roi_window_input_container_box, 1) self.manipulate_roi_window_main_box.addWidget( self.manipulate_roi_window_instance_view_widget, 11) # Create a new central widget to hold the horizontal box layout self.manipulate_roi_window_instance_central_widget = QWidget() self.manipulate_roi_window_instance_central_widget.setObjectName( "ManipulateRoiWindowInstanceCentralWidget") self.manipulate_roi_window_instance_central_widget.setLayout( self.manipulate_roi_window_main_box) self.retranslate_ui(self.manipulate_roi_window_instance) self.manipulate_roi_window_instance.setStyleSheet(stylesheet) self.manipulate_roi_window_instance.setCentralWidget( self.manipulate_roi_window_instance_central_widget) QtCore.QMetaObject.connectSlotsByName( self.manipulate_roi_window_instance) def dicom_view_slider_value_changed(self): """ Display selected ROIs in dropbox when moving to another image slice """ self.display_selected_roi() if self.dicom_preview.slider.value() != self.dicom_view.slider.value(): self.dicom_preview.slider.setValue(self.dicom_view.slider.value()) def dicom_preview_slider_value_changed(self): """ Display generated ROI when moving to another image slice """ self.draw_roi() if self.dicom_preview.slider.value() != self.dicom_view.slider.value(): self.dicom_view.slider.setValue(self.dicom_preview.slider.value()) def onCancelButtonClicked(self): """ This function is used for canceling the drawing """ self.close() def onDrawButtonClicked(self): """ Function triggered when the Draw button is pressed from the menu. """ # Hide warning message self.warning_message.setVisible(False) # Check inputs selected_operation = self.operation_name_dropdown_list.currentText() roi_1 = self.first_roi_name_dropdown_list.currentText() roi_2 = self.second_roi_name_dropdown_list.currentText() new_roi_name = self.new_roi_name_line_edit.text() # Check the selected inputs and execute the operations if roi_1 != "" and new_roi_name != "" and \ self.margin_line_edit.text() != "" and \ selected_operation in self.single_roi_operation_names: # Single ROI operations dict_rois_contours = ROI.get_roi_contour_pixel( self.patient_dict_container.get("raw_contour"), [roi_1], self.patient_dict_container.get("pixluts")) roi_geometry = ROI.roi_to_geometry(dict_rois_contours[roi_1]) margin = float(self.margin_line_edit.text()) if selected_operation == self.single_roi_operation_names[0]: new_geometry = ROI.scale_roi(roi_geometry, margin) elif selected_operation == self.single_roi_operation_names[1]: new_geometry = ROI.scale_roi(roi_geometry, -margin) elif selected_operation == self.single_roi_operation_names[2]: new_geometry = ROI.rind_roi(roi_geometry, -margin) else: new_geometry = ROI.rind_roi(roi_geometry, margin) self.new_ROI_contours = ROI.geometry_to_roi(new_geometry) self.draw_roi() return True elif roi_1 != "" and roi_2 != "" and new_roi_name != "" and \ selected_operation in self.multiple_roi_operation_names: # Multiple ROI operations dict_rois_contours = ROI.get_roi_contour_pixel( self.patient_dict_container.get("raw_contour"), [roi_1, roi_2], self.patient_dict_container.get("pixluts")) roi_1_geometry = ROI.roi_to_geometry(dict_rois_contours[roi_1]) roi_2_geometry = ROI.roi_to_geometry(dict_rois_contours[roi_2]) # Execute the selected operation new_geometry = ROI.manipulate_rois(roi_1_geometry, roi_2_geometry, selected_operation.upper()) self.new_ROI_contours = ROI.geometry_to_roi(new_geometry) self.draw_roi() return True self.warning_message_text.setText("Not all values are specified.") self.warning_message.setVisible(True) return False def onSaveClicked(self): """ Save the new ROI """ # Get the name of the new ROI new_roi_name = self.new_roi_name_line_edit.text() # If the new ROI hasn't been drawn, draw the new ROI. Then if the new # ROI is drawn successfully, proceed to save the new ROI. if self.new_ROI_contours is None: if not self.onDrawButtonClicked(): return # Get a dict to convert SOPInstanceUID to slice id slice_ids_dict = get_dict_slice_to_uid(PatientDictContainer()) # Transform new_ROI_contours to a list of roi information rois_to_save = {} for uid, contour_sequence in self.new_ROI_contours.items(): slider_id = slice_ids_dict[uid] location = self.patient_dict_container.filepaths[slider_id] ds = pydicom.dcmread(location) slice_info = {'coords': contour_sequence, 'ds': ds} rois_to_save[slider_id] = slice_info roi_list = ROI.convert_hull_list_to_contours_data( rois_to_save, self.patient_dict_container) connectSaveROIProgress(self, roi_list, self.dataset_rtss, new_roi_name, self.roi_saved) def draw_roi(self): """ Draw the new ROI """ # Get the new ROI's name new_roi_name = self.new_roi_name_line_edit.text() # Check if the new ROI contour is None if self.new_ROI_contours is None: return # Get the info required to draw the new ROI slider_id = self.dicom_preview.slider.value() curr_slice = self.patient_dict_container.get("dict_uid")[slider_id] # Calculate the new ROI's polygon dict_ROI_contours = {} dict_ROI_contours[new_roi_name] = self.new_ROI_contours polygons = ROI.calc_roi_polygon(new_roi_name, curr_slice, dict_ROI_contours) # Set the new ROI color color = QtGui.QColor() color.setRgb(90, 250, 175, 200) pen_color = QtGui.QColor(color.red(), color.green(), color.blue()) pen = QtGui.QPen(pen_color) pen.setStyle(QtCore.Qt.PenStyle(1)) pen.setWidthF(2.0) # Draw the new ROI self.dicom_preview.update_view() for i in range(len(polygons)): self.dicom_preview.scene.addPolygon(polygons[i], pen, QtGui.QBrush(color)) def update_selected_rois(self): """ Get the names of selected ROIs """ # Hide warning message self.warning_message.setVisible(False) self.roi_names = [] if self.first_roi_name_dropdown_list.currentText() != "": self.roi_names.append( self.first_roi_name_dropdown_list.currentText()) if self.second_roi_name_dropdown_list.currentText() != "" and \ self.second_roi_name_dropdown_list.isVisible(): self.roi_names.append( self.second_roi_name_dropdown_list.currentText()) self.dict_rois_contours_axial = ROI.get_roi_contour_pixel( self.patient_dict_container.get("raw_contour"), self.roi_names, self.patient_dict_container.get("pixluts")) self.display_selected_roi() def display_selected_roi(self): """ Display selected ROIs """ # Get the info required to display the selected ROIs slider_id = self.dicom_view.slider.value() curr_slice = self.patient_dict_container.get("dict_uid")[slider_id] self.rois = self.patient_dict_container.get("rois") # Display the selected ROIs self.dicom_view.update_view() for roi_id, roi_dict in self.rois.items(): roi_name = roi_dict['name'] if roi_name in self.roi_names: polygons = ROI.calc_roi_polygon(roi_name, curr_slice, self.dict_rois_contours_axial) self.dicom_view.draw_roi_polygons(roi_id, polygons, self.roi_color) def operation_changed(self): """ Change the form when users select different operations """ # Hide warning message self.warning_message.setVisible(False) selected_operation = self.operation_name_dropdown_list.currentText() if selected_operation in self.single_roi_operation_names: self.second_roi_name_label.setVisible(False) self.second_roi_name_dropdown_list.setVisible(False) self.margin_label.setVisible(True) self.margin_line_edit.setVisible(True) self.update_selected_rois() else: self.second_roi_name_label.setVisible(True) self.second_roi_name_dropdown_list.setVisible(True) self.margin_label.setVisible(False) self.margin_line_edit.setVisible(False) self.update_selected_rois() def roi_saved(self, new_rtss): """ Create a new ROI in Structure Tab and notify user """ new_roi_name = self.new_roi_name_line_edit.text() self.signal_roi_manipulated.emit((new_rtss, {"draw": new_roi_name})) QMessageBox.about(self.manipulate_roi_window_instance, "Saved", "New contour successfully created!") self.close()
import sys from PySide6.QtWidgets import QApplication, QPushButton, QWidget, QLineEdit, QFormLayout app = QApplication(sys.argv) window = QWidget() button1 = QPushButton("One") lineEdit1 = QLineEdit() button2 = QPushButton("Two") lineEdit2 = QLineEdit() button3 = QPushButton("Three") lineEdit3 = QLineEdit() layout = QFormLayout(window) layout.addRow(button1, lineEdit1) layout.addRow(button2, lineEdit2) layout.addRow(button3, lineEdit3) window.show() app.exec()
self._lcr_t_btn_connect.setDefaultAction( self._action_disconnect_lcr if self._lcrmeter_status. is_connecting else self._action_connect_lcr) self._stage_t_btn_connect.setDefaultAction( self._action_disconnect_stage_controller if self. _stage_controller_status.is_connecting else self. _action_connect_stage_controller) self._lcr_combobox_port.currentTextChanged.connect( self._lcrmeter_port_changed) self._stage_combobox_port.currentTextChanged.connect( self._stage_controller_port_changed) # setup layout f_layout_lcr = QFormLayout() f_layout_lcr.addRow("Port", self._lcr_combobox_port) f_layout_lcr.addRow("Baudrate", self._lcr_combobox_baudrate) f_layout_lcr.addWidget(self._lcr_t_btn_connect) group_lcr = QGroupBox("LCRMeter") group_lcr.setLayout(f_layout_lcr) f_layout_stage = QFormLayout() f_layout_stage.addRow("Port ", self._stage_combobox_port) f_layout_stage.addWidget(self._stage_t_btn_connect) group_stage = QGroupBox("Linear Stage") group_stage.setLayout(f_layout_stage) v_layout = AVBoxLayout(self) v_layout.addWidget(group_lcr) v_layout.addWidget(group_stage)
class UIDrawROIWindow: def setup_ui(self, draw_roi_window_instance, rois, dataset_rtss, signal_roi_drawn): """ this function is responsible for setting up the UI for DrawROIWindow param draw_roi_window_instance: the current drawing window instance. :param rois: the rois to be drawn :param dataset_rtss: the rtss to be written to :param signal_roi_drawn: the signal to be triggered when roi is drawn """ self.patient_dict_container = PatientDictContainer() self.rois = rois self.dataset_rtss = dataset_rtss self.signal_roi_drawn = signal_roi_drawn self.drawn_roi_list = {} self.standard_organ_names = [] self.standard_volume_names = [] self.standard_names = [] # Combination of organ and volume self.ROI_name = None # Selected ROI name self.target_pixel_coords = [] # This will contain the new pixel # coordinates specified by the min and max self.drawingROI = None self.slice_changed = False self.drawing_tool_radius = INITIAL_DRAWING_TOOL_RADIUS self.keep_empty_pixel = False # pixel density self.target_pixel_coords_single_array = [] # 1D array self.draw_roi_window_instance = draw_roi_window_instance self.colour = None self.ds = None self.zoom = 1.0 self.upper_limit = None self.lower_limit = None # is_four_view is set to True to stop the SUV2ROI button from appearing self.dicom_view = DicomAxialView(is_four_view=True) self.current_slice = self.dicom_view.slider.value() self.dicom_view.slider.valueChanged.connect(self.slider_value_changed) self.init_layout() QtCore.QMetaObject.connectSlotsByName(draw_roi_window_instance) def retranslate_ui(self, draw_roi_window_instance): """ this function retranslate the ui for draw roi window :param draw_roi_window_instance: the current drawing window instance. """ _translate = QtCore.QCoreApplication.translate draw_roi_window_instance.setWindowTitle( _translate("DrawRoiWindowInstance", "OnkoDICOM - Draw Region Of Interest")) self.roi_name_label.setText( _translate("ROINameLabel", "Region of Interest: ")) self.roi_name_line_edit.setText(_translate("ROINameLineEdit", "")) self.image_slice_number_label.setText( _translate("ImageSliceNumberLabel", "Slice Number: ")) self.image_slice_number_line_edit.setText( _translate("ImageSliceNumberLineEdit", str(self.dicom_view.current_slice_number))) self.image_slice_number_transect_button.setText( _translate("ImageSliceNumberTransectButton", "Transect")) self.image_slice_number_box_draw_button.setText( _translate("ImageSliceNumberBoxDrawButton", "Set Bounds")) self.image_slice_number_draw_button.setText( _translate("ImageSliceNumberDrawButton", "Draw")) self.image_slice_number_move_forward_button.setText( _translate("ImageSliceNumberMoveForwardButton", "")) self.image_slice_number_move_backward_button.setText( _translate("ImageSliceNumberMoveBackwardButton", "")) self.draw_roi_window_instance_save_button.setText( _translate("DrawRoiWindowInstanceSaveButton", "Save")) self.draw_roi_window_instance_cancel_button.setText( _translate("DrawRoiWindowInstanceCancelButton", "Cancel")) self.internal_hole_max_label.setText( _translate("InternalHoleLabel", "Maximum internal hole size (pixels): ")) self.internal_hole_max_line_edit.setText( _translate("InternalHoleInput", "9")) self.isthmus_width_max_label.setText( _translate("IsthmusWidthLabel", "Maximum isthmus width size (pixels): ")) self.isthmus_width_max_line_edit.setText( _translate("IsthmusWidthInput", "5")) self.min_pixel_density_label.setText( _translate("MinPixelDensityLabel", "Minimum density (pixels): ")) self.min_pixel_density_line_edit.setText( _translate("MinPixelDensityInput", "")) self.max_pixel_density_label.setText( _translate("MaxPixelDensityLabel", "Maximum density (pixels): ")) self.max_pixel_density_line_edit.setText( _translate("MaxPixelDensityInput", "")) self.toggle_keep_empty_pixel_label.setText( _translate("ToggleKeepEmptyPixelLabel", "Keep empty pixel: ")) self.draw_roi_window_viewport_zoom_label.setText( _translate("DrawRoiWindowViewportZoomLabel", "Zoom: ")) self.draw_roi_window_cursor_radius_change_label.setText( _translate("DrawRoiWindowCursorRadiusChangeLabel", "Cursor Radius: ")) self.draw_roi_window_instance_action_reset_button.setText( _translate("DrawRoiWindowInstanceActionClearButton", "Reset")) def init_layout(self): """ Initialize the layout for the DICOM View tab. Add the view widget and the slider in the layout. Add the whole container 'tab2_view' as a tab in the main page. """ # Initialise a DrawROIWindow if platform.system() == 'Darwin': self.stylesheet_path = "res/stylesheet.qss" else: self.stylesheet_path = "res/stylesheet-win-linux.qss" stylesheet = open(resource_path(self.stylesheet_path)).read() window_icon = QIcon() window_icon.addPixmap(QPixmap(resource_path("res/images/icon.ico")), QIcon.Normal, QIcon.Off) self.draw_roi_window_instance.setObjectName("DrawRoiWindowInstance") self.draw_roi_window_instance.setWindowIcon(window_icon) # Creating a form box to hold all buttons and input fields self.draw_roi_window_input_container_box = QFormLayout() self.draw_roi_window_input_container_box. \ setObjectName("DrawRoiWindowInputContainerBox") self.draw_roi_window_input_container_box. \ setLabelAlignment(Qt.AlignLeft) # Create a label for denoting the ROI name self.roi_name_label = QLabel() self.roi_name_label.setObjectName("ROINameLabel") self.roi_name_line_edit = QLineEdit() # Create an input box for ROI name self.roi_name_line_edit.setObjectName("ROINameLineEdit") self.roi_name_line_edit.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.roi_name_line_edit.resize( self.roi_name_line_edit.sizeHint().width(), self.roi_name_line_edit.sizeHint().height()) self.roi_name_line_edit.setEnabled(False) self.draw_roi_window_input_container_box. \ addRow(self.roi_name_label, self.roi_name_line_edit) # Create horizontal box to store image slice number and backward, # forward buttons self.image_slice_number_box = QHBoxLayout() self.image_slice_number_box.setObjectName("ImageSliceNumberBox") # Create a label for denoting the Image Slice Number self.image_slice_number_label = QLabel() self.image_slice_number_label.setObjectName("ImageSliceNumberLabel") self.image_slice_number_box.addWidget(self.image_slice_number_label) # Create a line edit for containing the image slice number self.image_slice_number_line_edit = QLineEdit() self.image_slice_number_line_edit. \ setObjectName("ImageSliceNumberLineEdit") self.image_slice_number_line_edit. \ setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.image_slice_number_line_edit.resize( self.image_slice_number_line_edit.sizeHint().width(), self.image_slice_number_line_edit.sizeHint().height()) self.image_slice_number_line_edit.setCursorPosition(0) self.image_slice_number_line_edit.setEnabled(False) self.image_slice_number_box. \ addWidget(self.image_slice_number_line_edit) # Create a button to move backward to the previous image self.image_slice_number_move_backward_button = QPushButton() self.image_slice_number_move_backward_button. \ setObjectName("ImageSliceNumberMoveBackwardButton") self.image_slice_number_move_backward_button.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.image_slice_number_move_backward_button.resize(QSize(24, 24)) self.image_slice_number_move_backward_button.clicked. \ connect(self.onBackwardClicked) icon_move_backward = QtGui.QIcon() icon_move_backward.addPixmap( QtGui.QPixmap( resource_path('res/images/btn-icons/backward_slide_icon.png'))) self.image_slice_number_move_backward_button.setIcon( icon_move_backward) self.image_slice_number_box. \ addWidget(self.image_slice_number_move_backward_button) # Create a button to move forward to the next image self.image_slice_number_move_forward_button = QPushButton() self.image_slice_number_move_forward_button. \ setObjectName("ImageSliceNumberMoveForwardButton") self.image_slice_number_move_forward_button.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.image_slice_number_move_forward_button.resize(QSize(24, 24)) self.image_slice_number_move_forward_button.clicked. \ connect(self.onForwardClicked) icon_move_forward = QtGui.QIcon() icon_move_forward.addPixmap( QtGui.QPixmap( resource_path('res/images/btn-icons/forward_slide_icon.png'))) self.image_slice_number_move_forward_button.setIcon(icon_move_forward) self.image_slice_number_box. \ addWidget(self.image_slice_number_move_forward_button) self.draw_roi_window_input_container_box. \ addRow(self.image_slice_number_box) # Create a horizontal box for containing the zoom function self.draw_roi_window_viewport_zoom_box = QHBoxLayout() self.draw_roi_window_viewport_zoom_box.setObjectName( "DrawRoiWindowViewportZoomBox") # Create a label for zooming self.draw_roi_window_viewport_zoom_label = QLabel() self.draw_roi_window_viewport_zoom_label. \ setObjectName("DrawRoiWindowViewportZoomLabel") # Create an input box for zoom factor self.draw_roi_window_viewport_zoom_input = QLineEdit() self.draw_roi_window_viewport_zoom_input. \ setObjectName("DrawRoiWindowViewportZoomInput") self.draw_roi_window_viewport_zoom_input. \ setText("{:.2f}".format(self.zoom * 100) + "%") self.draw_roi_window_viewport_zoom_input.setCursorPosition(0) self.draw_roi_window_viewport_zoom_input.setEnabled(False) self.draw_roi_window_viewport_zoom_input. \ setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.draw_roi_window_viewport_zoom_input.resize( self.draw_roi_window_viewport_zoom_input.sizeHint().width(), self.draw_roi_window_viewport_zoom_input.sizeHint().height()) # Create 2 buttons for zooming in and out # Zoom In Button self.draw_roi_window_viewport_zoom_in_button = QPushButton() self.draw_roi_window_viewport_zoom_in_button. \ setObjectName("DrawRoiWindowViewportZoomInButton") self.draw_roi_window_viewport_zoom_in_button.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.draw_roi_window_viewport_zoom_in_button.resize(QSize(24, 24)) self.draw_roi_window_viewport_zoom_in_button. \ setProperty("QPushButtonClass", "zoom-button") icon_zoom_in = QtGui.QIcon() icon_zoom_in.addPixmap( QtGui.QPixmap( resource_path('res/images/btn-icons/zoom_in_icon.png'))) self.draw_roi_window_viewport_zoom_in_button.setIcon(icon_zoom_in) self.draw_roi_window_viewport_zoom_in_button.clicked. \ connect(self.onZoomInClicked) # Zoom Out Button self.draw_roi_window_viewport_zoom_out_button = QPushButton() self.draw_roi_window_viewport_zoom_out_button. \ setObjectName("DrawRoiWindowViewportZoomOutButton") self.draw_roi_window_viewport_zoom_out_button.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.draw_roi_window_viewport_zoom_out_button.resize(QSize(24, 24)) self.draw_roi_window_viewport_zoom_out_button. \ setProperty("QPushButtonClass", "zoom-button") icon_zoom_out = QtGui.QIcon() icon_zoom_out.addPixmap( QtGui.QPixmap( resource_path('res/images/btn-icons/zoom_out_icon.png'))) self.draw_roi_window_viewport_zoom_out_button.setIcon(icon_zoom_out) self.draw_roi_window_viewport_zoom_out_button.clicked. \ connect(self.onZoomOutClicked) self.draw_roi_window_viewport_zoom_box. \ addWidget(self.draw_roi_window_viewport_zoom_label) self.draw_roi_window_viewport_zoom_box. \ addWidget(self.draw_roi_window_viewport_zoom_input) self.draw_roi_window_viewport_zoom_box. \ addWidget(self.draw_roi_window_viewport_zoom_out_button) self.draw_roi_window_viewport_zoom_box. \ addWidget(self.draw_roi_window_viewport_zoom_in_button) self.draw_roi_window_input_container_box. \ addRow(self.draw_roi_window_viewport_zoom_box) self.init_cursor_radius_change_box() # Create field to toggle two options: Keep empty pixel or fill empty # pixel when using draw cursor self.toggle_keep_empty_pixel_box = QHBoxLayout() self.toggle_keep_empty_pixel_label = QLabel() self.toggle_keep_empty_pixel_label. \ setObjectName("ToggleKeepEmptyPixelLabel") # Create input for min pixel size self.toggle_keep_empty_pixel_combo_box = QComboBox() self.toggle_keep_empty_pixel_combo_box.addItems(["Off", "On"]) self.toggle_keep_empty_pixel_combo_box.setCurrentIndex(0) self.toggle_keep_empty_pixel_combo_box.setEnabled(False) self.toggle_keep_empty_pixel_combo_box. \ setObjectName("ToggleKeepEmptyPixelComboBox") self.toggle_keep_empty_pixel_combo_box. \ setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.toggle_keep_empty_pixel_combo_box.resize( self.toggle_keep_empty_pixel_combo_box.sizeHint().width(), self.toggle_keep_empty_pixel_combo_box.sizeHint().height()) self.toggle_keep_empty_pixel_combo_box.currentIndexChanged.connect( self.toggle_keep_empty_pixel_box_index_changed) self.toggle_keep_empty_pixel_box. \ addWidget(self.toggle_keep_empty_pixel_label) self.toggle_keep_empty_pixel_box. \ addWidget(self.toggle_keep_empty_pixel_combo_box) self.draw_roi_window_input_container_box. \ addRow(self.toggle_keep_empty_pixel_box) # Create a horizontal box for transect and draw button self.draw_roi_window_transect_draw_box = QHBoxLayout() self.draw_roi_window_transect_draw_box. \ setObjectName("DrawRoiWindowTransectDrawBox") # Create a transect button self.image_slice_number_transect_button = QPushButton() self.image_slice_number_transect_button. \ setObjectName("ImageSliceNumberTransectButton") self.image_slice_number_transect_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum)) self.image_slice_number_transect_button.resize( self.image_slice_number_transect_button.sizeHint().width(), self.image_slice_number_transect_button.sizeHint().height()) self.image_slice_number_transect_button.clicked. \ connect(self.transect_handler) icon_transect = QtGui.QIcon() icon_transect.addPixmap( QtGui.QPixmap( resource_path('res/images/btn-icons/transect_icon.png'))) self.image_slice_number_transect_button.setIcon(icon_transect) self.draw_roi_window_transect_draw_box. \ addWidget(self.image_slice_number_transect_button) # Create a bounding box button self.image_slice_number_box_draw_button = QPushButton() self.image_slice_number_box_draw_button. \ setObjectName("ImageSliceNumberBoxDrawButton") self.image_slice_number_box_draw_button.setSizePolicy( QSizePolicy.MinimumExpanding, QSizePolicy.Minimum) self.image_slice_number_box_draw_button.resize( self.image_slice_number_box_draw_button.sizeHint().width(), self.image_slice_number_box_draw_button.sizeHint().height()) self.image_slice_number_box_draw_button.clicked. \ connect(self.onBoxDrawClicked) icon_box_draw = QtGui.QIcon() icon_box_draw.addPixmap( QtGui.QPixmap( resource_path('res/images/btn-icons/draw_bound_icon.png'))) self.image_slice_number_box_draw_button.setIcon(icon_box_draw) self.draw_roi_window_transect_draw_box. \ addWidget(self.image_slice_number_box_draw_button) # Create a draw button self.image_slice_number_draw_button = QPushButton() self.image_slice_number_draw_button. \ setObjectName("ImageSliceNumberDrawButton") self.image_slice_number_draw_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum)) self.image_slice_number_draw_button.resize( self.image_slice_number_draw_button.sizeHint().width(), self.image_slice_number_draw_button.sizeHint().height()) self.image_slice_number_draw_button.clicked.connect(self.onDrawClicked) icon_draw = QtGui.QIcon() icon_draw.addPixmap( QtGui.QPixmap(resource_path('res/images/btn-icons/draw_icon.png'))) self.image_slice_number_draw_button.setIcon(icon_draw) self.draw_roi_window_transect_draw_box. \ addWidget(self.image_slice_number_draw_button) self.draw_roi_window_input_container_box. \ addRow(self.draw_roi_window_transect_draw_box) # Create a contour preview button self.row_preview_layout = QtWidgets.QHBoxLayout() self.button_contour_preview = QtWidgets.QPushButton("Preview contour") self.button_contour_preview.clicked.connect(self.onPreviewClicked) self.row_preview_layout.addWidget(self.button_contour_preview) self.draw_roi_window_input_container_box. \ addRow(self.row_preview_layout) icon_preview = QtGui.QIcon() icon_preview.addPixmap( QtGui.QPixmap( resource_path('res/images/btn-icons/preview_icon.png'))) self.button_contour_preview.setIcon(icon_preview) # Create input line edit for alpha value self.label_alpha_value = QtWidgets.QLabel("Alpha value:") self.input_alpha_value = QtWidgets.QLineEdit("0.2") self.input_alpha_value. \ setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum) self.input_alpha_value.resize( self.input_alpha_value.sizeHint().width(), self.input_alpha_value.sizeHint().height()) self.input_alpha_value.setValidator( QRegularExpressionValidator( QRegularExpression("^[0-9]*[.]?[0-9]*$"))) self.draw_roi_window_input_container_box. \ addRow(self.label_alpha_value, self.input_alpha_value) # Create a label for denoting the max internal hole size self.internal_hole_max_label = QLabel() self.internal_hole_max_label.setObjectName("InternalHoleLabel") # Create input for max internal hole size self.internal_hole_max_line_edit = QLineEdit() self.internal_hole_max_line_edit.setObjectName("InternalHoleInput") self.internal_hole_max_line_edit. \ setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum) self.internal_hole_max_line_edit.resize( self.internal_hole_max_line_edit.sizeHint().width(), self.internal_hole_max_line_edit.sizeHint().height()) self.internal_hole_max_line_edit.setValidator( QRegularExpressionValidator( QRegularExpression("^[0-9]*[.]?[0-9]*$"))) self.draw_roi_window_input_container_box.addRow( self.internal_hole_max_label, self.internal_hole_max_line_edit) # Create a label for denoting the isthmus width size self.isthmus_width_max_label = QLabel() self.isthmus_width_max_label.setObjectName("IsthmusWidthLabel") # Create input for max isthmus width size self.isthmus_width_max_line_edit = QLineEdit() self.isthmus_width_max_line_edit.setObjectName("IsthmusWidthInput") self.isthmus_width_max_line_edit.setSizePolicy( QSizePolicy.MinimumExpanding, QSizePolicy.Minimum) self.isthmus_width_max_line_edit.resize( self.isthmus_width_max_line_edit.sizeHint().width(), self.isthmus_width_max_line_edit.sizeHint().height()) self.isthmus_width_max_line_edit.setValidator( QRegularExpressionValidator( QRegularExpression("^[0-9]*[.]?[0-9]*$"))) self.draw_roi_window_input_container_box.addRow( self.isthmus_width_max_label, self.isthmus_width_max_line_edit) # Create a label for denoting the minimum pixel density self.min_pixel_density_label = QLabel() self.min_pixel_density_label.setObjectName("MinPixelDensityLabel") # Create input for min pixel size self.min_pixel_density_line_edit = QLineEdit() self.min_pixel_density_line_edit.setObjectName("MinPixelDensityInput") self.min_pixel_density_line_edit.setSizePolicy( QSizePolicy.MinimumExpanding, QSizePolicy.Minimum) self.min_pixel_density_line_edit.resize( self.min_pixel_density_line_edit.sizeHint().width(), self.min_pixel_density_line_edit.sizeHint().height()) self.min_pixel_density_line_edit.setValidator( QRegularExpressionValidator( QRegularExpression("^[0-9]*[.]?[0-9]*$"))) self.draw_roi_window_input_container_box.addRow( self.min_pixel_density_label, self.min_pixel_density_line_edit) # Create a label for denoting the minimum pixel density self.max_pixel_density_label = QLabel() self.max_pixel_density_label.setObjectName("MaxPixelDensityLabel") # Create input for min pixel size self.max_pixel_density_line_edit = QLineEdit() self.max_pixel_density_line_edit.setObjectName("MaxPixelDensityInput") self.max_pixel_density_line_edit. \ setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum) self.max_pixel_density_line_edit.resize( self.max_pixel_density_line_edit.sizeHint().width(), self.max_pixel_density_line_edit.sizeHint().height()) self.max_pixel_density_line_edit.setValidator( QRegularExpressionValidator( QRegularExpression("^[0-9]*[.]?[0-9]*$"))) self.draw_roi_window_input_container_box.addRow( self.max_pixel_density_label, self.max_pixel_density_line_edit) # Create a button to clear the draw self.draw_roi_window_instance_action_reset_button = QPushButton() self.draw_roi_window_instance_action_reset_button. \ setObjectName("DrawRoiWindowInstanceActionClearButton") self.draw_roi_window_instance_action_reset_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum)) reset_button = self.draw_roi_window_instance_action_reset_button self.draw_roi_window_instance_action_reset_button.resize( reset_button.sizeHint().width(), reset_button.sizeHint().height()) self.draw_roi_window_instance_action_reset_button.clicked. \ connect(self.onResetClicked) self.draw_roi_window_instance_action_reset_button. \ setProperty("QPushButtonClass", "fail-button") icon_clear_roi_draw = QtGui.QIcon() icon_clear_roi_draw.addPixmap( QtGui.QPixmap( resource_path('res/images/btn-icons/reset_roi_draw_icon.png'))) self.draw_roi_window_instance_action_reset_button. \ setIcon(icon_clear_roi_draw) self.draw_roi_window_input_container_box. \ addRow(self.draw_roi_window_instance_action_reset_button) # Create a horizontal box for saving and cancel the drawing self.draw_roi_window_cancel_save_box = QHBoxLayout() self.draw_roi_window_cancel_save_box. \ setObjectName("DrawRoiWindowCancelSaveBox") # Create an exit button to cancel the drawing # Add a button to go back/exit from the application self.draw_roi_window_instance_cancel_button = QPushButton() self.draw_roi_window_instance_cancel_button. \ setObjectName("DrawRoiWindowInstanceCancelButton") self.draw_roi_window_instance_cancel_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum)) self.draw_roi_window_instance_cancel_button.resize( self.draw_roi_window_instance_cancel_button.sizeHint().width(), self.draw_roi_window_instance_cancel_button.sizeHint().height()) self.draw_roi_window_instance_cancel_button. \ setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.draw_roi_window_instance_cancel_button.clicked. \ connect(self.onCancelButtonClicked) self.draw_roi_window_instance_cancel_button. \ setProperty("QPushButtonClass", "fail-button") icon_cancel = QtGui.QIcon() icon_cancel.addPixmap( QtGui.QPixmap( resource_path('res/images/btn-icons/cancel_icon.png'))) self.draw_roi_window_instance_cancel_button.setIcon(icon_cancel) self.draw_roi_window_cancel_save_box. \ addWidget(self.draw_roi_window_instance_cancel_button) # Create a save button to save all the changes self.draw_roi_window_instance_save_button = QPushButton() self.draw_roi_window_instance_save_button. \ setObjectName("DrawRoiWindowInstanceSaveButton") self.draw_roi_window_instance_save_button.setSizePolicy( QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum)) self.draw_roi_window_instance_save_button.resize( self.draw_roi_window_instance_save_button.sizeHint().width(), self.draw_roi_window_instance_save_button.sizeHint().height()) self.draw_roi_window_instance_save_button. \ setProperty("QPushButtonClass", "success-button") icon_save = QtGui.QIcon() icon_save.addPixmap( QtGui.QPixmap(resource_path('res/images/btn-icons/save_icon.png'))) self.draw_roi_window_instance_save_button.setIcon(icon_save) self.draw_roi_window_instance_save_button.clicked. \ connect(self.onSaveClicked) self.draw_roi_window_cancel_save_box. \ addWidget(self.draw_roi_window_instance_save_button) self.draw_roi_window_input_container_box. \ addRow(self.draw_roi_window_cancel_save_box) # Creating a horizontal box to hold the ROI view and slider self.draw_roi_window_instance_view_box = QHBoxLayout() self.draw_roi_window_instance_view_box. \ setObjectName("DrawRoiWindowInstanceViewBox") # Add View and Slider into horizontal box self.draw_roi_window_instance_view_box.addWidget(self.dicom_view) # Create a widget to hold the image slice box self.draw_roi_window_instance_view_widget = QWidget() self.draw_roi_window_instance_view_widget.setObjectName( "DrawRoiWindowInstanceActionWidget") self.draw_roi_window_instance_view_widget.setLayout( self.draw_roi_window_instance_view_box) # Create a horizontal box for containing the input fields and the # viewport self.draw_roi_window_main_box = QHBoxLayout() self.draw_roi_window_main_box.setObjectName("DrawRoiWindowMainBox") self.draw_roi_window_main_box. \ addLayout(self.draw_roi_window_input_container_box, 1) self.draw_roi_window_main_box. \ addWidget(self.draw_roi_window_instance_view_widget, 11) # Create a new central widget to hold the vertical box layout self.draw_roi_window_instance_central_widget = QWidget() self.draw_roi_window_instance_central_widget. \ setObjectName("DrawRoiWindowInstanceCentralWidget") self.draw_roi_window_instance_central_widget.setLayout( self.draw_roi_window_main_box) self.retranslate_ui(self.draw_roi_window_instance) self.draw_roi_window_instance.setStyleSheet(stylesheet) self.draw_roi_window_instance. \ setCentralWidget(self.draw_roi_window_instance_central_widget) QtCore.QMetaObject.connectSlotsByName(self.draw_roi_window_instance) def slider_value_changed(self): """ actions to be taken when slider value changes """ image_slice_number = self.current_slice # save progress self.save_drawing_progress(image_slice_number) self.set_current_slice(self.dicom_view.slider.value()) def set_current_slice(self, slice_number): """ set the current slice :param slice_number: the slice number to be set """ self.image_slice_number_line_edit.setText(str(slice_number + 1)) self.current_slice = slice_number self.dicom_view.update_view() # check if this slice has any drawings before if self.drawn_roi_list.get(self.current_slice) is not None: self.drawingROI = self.drawn_roi_list[ self.current_slice]['drawingROI'] self.ds = self.drawn_roi_list[self.current_slice]['ds'] self.dicom_view.view.setScene(self.drawingROI) self.enable_cursor_radius_change_box() self.drawingROI.clear_cursor(self.drawing_tool_radius) else: self.disable_cursor_radius_change_box() self.ds = None def onZoomInClicked(self): """ This function is used for zooming in button """ self.dicom_view.zoom *= 1.05 self.dicom_view.update_view(zoom_change=True) if self.drawingROI \ and self.drawingROI.current_slice == self.current_slice: self.dicom_view.view.setScene(self.drawingROI) self.draw_roi_window_viewport_zoom_input.setText( "{:.2f}".format(self.dicom_view.zoom * 100) + "%") self.draw_roi_window_viewport_zoom_input.setCursorPosition(0) def onZoomOutClicked(self): """ This function is used for zooming out button """ self.dicom_view.zoom /= 1.05 self.dicom_view.update_view(zoom_change=True) if self.drawingROI \ and self.drawingROI.current_slice == self.current_slice: self.dicom_view.view.setScene(self.drawingROI) self.draw_roi_window_viewport_zoom_input. \ setText("{:.2f}".format(self.dicom_view.zoom * 100) + "%") self.draw_roi_window_viewport_zoom_input.setCursorPosition(0) def toggle_keep_empty_pixel_box_index_changed(self): self.keep_empty_pixel = self.toggle_keep_empty_pixel_combo_box. \ currentText() == "On" self.drawingROI.keep_empty_pixel = self.keep_empty_pixel def onCancelButtonClicked(self): """ This function is used for canceling the drawing """ self.closeWindow() def onBackwardClicked(self): """ This function is used when backward button is clicked """ image_slice_number = self.current_slice # save progress if self.save_drawing_progress(image_slice_number): # Backward will only execute if current image slice is above 0. if int(image_slice_number) > 0: # decrements slice by 1 and update slider to move to correct # position self.dicom_view.slider.setValue(image_slice_number - 1) def onForwardClicked(self): """ This function is used when forward button is clicked """ image_slice_number = self.current_slice # save progress if self.save_drawing_progress(image_slice_number): pixmaps = self.patient_dict_container.get("pixmaps_axial") total_slices = len(pixmaps) # Forward will only execute if current image slice is below the # total number of slices. if int(image_slice_number) < total_slices: # increments slice by 1 and update slider to move to correct # position self.dicom_view.slider.setValue(image_slice_number + 1) def onResetClicked(self): """ This function is used when reset button is clicked """ self.dicom_view.image_display() self.dicom_view.update_view() self.isthmus_width_max_line_edit.setText("5") self.internal_hole_max_line_edit.setText("9") self.min_pixel_density_line_edit.setText("") self.max_pixel_density_line_edit.setText("") if hasattr(self, 'bounds_box_draw'): delattr(self, 'bounds_box_draw') if hasattr(self, 'drawingROI'): delattr(self, 'drawingROI') self.ds = None def transect_handler(self): """ Function triggered when the Transect button is pressed from the menu. """ pixmaps = self.patient_dict_container.get("pixmaps_axial") id = self.current_slice dt = self.patient_dict_container.dataset[id] rowS = dt.PixelSpacing[0] colS = dt.PixelSpacing[1] dt.convert_pixel_data() MainPageCallClass().run_transect( self.draw_roi_window_instance, self.dicom_view.view, pixmaps[id], dt._pixel_array.transpose(), rowS, colS, is_roi_draw=True, ) def save_drawing_progress(self, image_slice_number): """ this function saves the drawing progress on current slice :param image_slice_number: the slice number to be saved """ if self.slice_changed: if hasattr(self, 'drawingROI') and self.drawingROI \ and self.ds is not None \ and len(self.drawingROI.target_pixel_coords) != 0: alpha = float(self.input_alpha_value.text()) pixel_hull_list = calculate_concave_hull_of_points( self.drawingROI.target_pixel_coords, alpha) coord_list = [] for pixel_hull in pixel_hull_list: coord_list.append(pixel_hull) self.drawn_roi_list[image_slice_number] = { 'coords': coord_list, 'ds': self.ds, 'drawingROI': self.drawingROI } self.slice_changed = False return True else: return True return True def on_transect_close(self): """ Function triggered when transect is closed """ if self.upper_limit and self.lower_limit: self.min_pixel_density_line_edit.setText(str(self.lower_limit)) self.max_pixel_density_line_edit.setText(str(self.upper_limit)) self.dicom_view.update_view() def onDrawClicked(self): """ Function triggered when the Draw button is pressed from the menu. """ pixmaps = self.patient_dict_container.get("pixmaps_axial") if self.min_pixel_density_line_edit.text() == "" \ or self.max_pixel_density_line_edit.text() == "": QMessageBox.about(self.draw_roi_window_instance, "Not Enough Data", "Not all values are specified or correct.") else: # Getting most updated selected slice id = self.current_slice dt = self.patient_dict_container.dataset[id] dt.convert_pixel_data() # Path to the selected .dcm file location = self.patient_dict_container.filepaths[id] self.ds = pydicom.dcmread(location) min_pixel = self.min_pixel_density_line_edit.text() max_pixel = self.max_pixel_density_line_edit.text() # If they are number inputs if min_pixel.isdecimal() and max_pixel.isdecimal(): min_pixel = int(min_pixel) max_pixel = int(max_pixel) if min_pixel >= max_pixel: QMessageBox.about( self.draw_roi_window_instance, "Incorrect Input", "Please ensure maximum density is " "atleast higher than minimum density.") self.drawingROI = Drawing( pixmaps[id], dt._pixel_array.transpose(), min_pixel, max_pixel, self.patient_dict_container.dataset[id], self.draw_roi_window_instance, self.slice_changed, self.current_slice, self.drawing_tool_radius, self.keep_empty_pixel, set()) self.slice_changed = True self.dicom_view.view.setScene(self.drawingROI) self.enable_cursor_radius_change_box() else: QMessageBox.about(self.draw_roi_window_instance, "Not Enough Data", "Not all values are specified or correct.") def onBoxDrawClicked(self): """ Function triggered when bounding box button is pressed """ id = self.current_slice dt = self.patient_dict_container.dataset[id] dt.convert_pixel_data() pixmaps = self.patient_dict_container.get("pixmaps_axial") self.bounds_box_draw = DrawBoundingBox(pixmaps[id], dt) self.dicom_view.view.setScene(self.bounds_box_draw) self.disable_cursor_radius_change_box() def onSaveClicked(self): """ Function triggered when Save button is clicked """ # Make sure the user has clicked Draw first if self.save_drawing_progress(image_slice_number=self.current_slice): self.saveROIList() def saveROIList(self): """ Function triggered when saving ROI list """ roi_list = ROI.convert_hull_list_to_contours_data( self.drawn_roi_list, self.patient_dict_container) if len(roi_list) == 0: QMessageBox.about(self.draw_roi_window_instance, "No ROI Detected", "Please ensure you have drawn your ROI first.") return # The list of points will need to be converted into a # single-dimensional array, as RTSTRUCT contour data is stored in # such a way. i.e. [x, y, z, x, y, z, x, y, z, ..., ...] Create a # popup window that modifies the RTSTRUCT and tells the user that # processing is happening. connectSaveROIProgress(self, roi_list, self.dataset_rtss, self.ROI_name, self.roi_saved) def roi_saved(self, new_rtss): """ Function to call save ROI and display progress """ self.signal_roi_drawn.emit((new_rtss, {"draw": self.ROI_name})) QMessageBox.about(self.draw_roi_window_instance, "Saved", "New contour successfully created!") self.closeWindow() def onPreviewClicked(self): """ function triggered when Preview button is clicked """ if hasattr(self, 'drawingROI') and self.drawingROI and len( self.drawingROI.target_pixel_coords) > 0: alpha = float(self.input_alpha_value.text()) polygon_list = calculate_concave_hull_of_points( self.drawingROI.target_pixel_coords, alpha) self.drawingROI.draw_contour_preview(polygon_list) else: QMessageBox.about(self.draw_roi_window_instance, "Not Enough Data", "Please ensure you have drawn your ROI first.") def set_selected_roi_name(self, roi_name): """ function to set selected roi name :param roi_name: roi name selected """ roi_exists = False patient_dict_container = PatientDictContainer() existing_rois = patient_dict_container.get("rois") number_of_rois = len(existing_rois) # Check to see if the ROI already exists for key, value in existing_rois.items(): if roi_name in value['name']: roi_exists = True if roi_exists: QMessageBox.about(self.draw_roi_window_instance, "ROI already exists in RTSS", "Would you like to continue?") self.ROI_name = roi_name self.roi_name_line_edit.setText(self.ROI_name) def onRadiusReduceClicked(self): """ function triggered when user reduce cursor radius """ self.drawing_tool_radius = max(self.drawing_tool_radius - 1, 4) self.draw_roi_window_cursor_radius_change_input.setText( str(self.drawing_tool_radius)) self.draw_roi_window_cursor_radius_change_input.setCursorPosition(0) self.draw_cursor_when_radius_changed() def onRadiusIncreaseClicked(self): """ function triggered when user increase cursor radius """ self.drawing_tool_radius = min(self.drawing_tool_radius + 1, 25) self.draw_roi_window_cursor_radius_change_input.setText( str(self.drawing_tool_radius)) self.draw_cursor_when_radius_changed() def draw_cursor_when_radius_changed(self): """ function to update drawing cursor when radius changed """ if self.drawingROI.cursor: self.drawingROI.draw_cursor( self.drawingROI.current_cursor_x + self.drawing_tool_radius, self.drawingROI.current_cursor_y + self.drawing_tool_radius, self.drawing_tool_radius) else: self.drawingROI.draw_cursor( (self.drawingROI.min_x + self.drawingROI.max_x) / 2, (self.drawingROI.min_y + self.drawingROI.max_y) / 2, self.drawing_tool_radius, True) def init_cursor_radius_change_box(self): """ function to init cursor radius change box """ # Create a horizontal box for containing the cursor radius changing # function self.draw_roi_window_cursor_radius_change_box = QHBoxLayout() self.draw_roi_window_cursor_radius_change_box.setObjectName( "DrawRoiWindowCursorRadiusChangeBox") # Create a label for cursor radius change self.draw_roi_window_cursor_radius_change_label = QLabel() self.draw_roi_window_cursor_radius_change_label.setObjectName( "DrawRoiWindowCursorRadiusChangeLabel") # Create an input box for cursor radius self.draw_roi_window_cursor_radius_change_input = QLineEdit() self.draw_roi_window_cursor_radius_change_input.setObjectName( "DrawRoiWindowCursorRadiusChangeInput") self.draw_roi_window_cursor_radius_change_input.setText(str(19)) self.draw_roi_window_cursor_radius_change_input.setCursorPosition(0) self.draw_roi_window_cursor_radius_change_input.setEnabled(False) self.draw_roi_window_cursor_radius_change_input.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.Minimum) self.draw_roi_window_cursor_radius_change_input.resize( self.draw_roi_window_cursor_radius_change_input.sizeHint().width(), self.draw_roi_window_cursor_radius_change_input.sizeHint().height( )) # Create 2 buttons for increasing and reducing cursor radius # Increase Button self.draw_roi_window_cursor_radius_change_increase_button = \ QPushButton() self.draw_roi_window_cursor_radius_change_increase_button. \ setObjectName("DrawRoiWindowCursorRadiusIncreaseButton") self.draw_roi_window_cursor_radius_change_increase_button. \ setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.draw_roi_window_cursor_radius_change_increase_button.resize( QSize(24, 24)) self.draw_roi_window_cursor_radius_change_increase_button.setProperty( "QPushButtonClass", "zoom-button") icon_zoom_in = QtGui.QIcon() icon_zoom_in.addPixmap( QtGui.QPixmap( resource_path('res/images/btn-icons/zoom_in_icon.png'))) self.draw_roi_window_cursor_radius_change_increase_button.setIcon( icon_zoom_in) self.draw_roi_window_cursor_radius_change_increase_button.clicked. \ connect(self.onRadiusIncreaseClicked) # Reduce Button self.draw_roi_window_cursor_radius_change_reduce_button = QPushButton() self.draw_roi_window_cursor_radius_change_reduce_button.setObjectName( "DrawRoiWindowCursorRadiusReduceButton") self.draw_roi_window_cursor_radius_change_reduce_button.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.draw_roi_window_cursor_radius_change_reduce_button.resize( QSize(24, 24)) self.draw_roi_window_cursor_radius_change_reduce_button.setProperty( "QPushButtonClass", "zoom-button") icon_zoom_out = QtGui.QIcon() icon_zoom_out.addPixmap( QtGui.QPixmap( resource_path('res/images/btn-icons/zoom_out_icon.png'))) self.draw_roi_window_cursor_radius_change_reduce_button.setIcon( icon_zoom_out) self.draw_roi_window_cursor_radius_change_reduce_button.clicked. \ connect(self.onRadiusReduceClicked) self.draw_roi_window_cursor_radius_change_box.addWidget( self.draw_roi_window_cursor_radius_change_label) self.draw_roi_window_cursor_radius_change_box.addWidget( self.draw_roi_window_cursor_radius_change_input) self.draw_roi_window_cursor_radius_change_box.addWidget( self.draw_roi_window_cursor_radius_change_reduce_button) self.draw_roi_window_cursor_radius_change_box.addWidget( self.draw_roi_window_cursor_radius_change_increase_button) self.draw_roi_window_input_container_box.addRow( self.draw_roi_window_cursor_radius_change_box) self.draw_roi_window_cursor_radius_change_increase_button.setEnabled( False) self.draw_roi_window_cursor_radius_change_reduce_button.setEnabled( False) def disable_cursor_radius_change_box(self): """ function to disable cursor radius change box """ self.draw_roi_window_cursor_radius_change_reduce_button.setEnabled( False) self.draw_roi_window_cursor_radius_change_increase_button.setEnabled( False) self.toggle_keep_empty_pixel_combo_box.setEnabled(False) def enable_cursor_radius_change_box(self): """ function to enable cursor radius change box """ self.draw_roi_window_cursor_radius_change_reduce_button.setEnabled( True) self.draw_roi_window_cursor_radius_change_increase_button.setEnabled( True) self.toggle_keep_empty_pixel_combo_box.setEnabled(True) def closeWindow(self): """ function to close draw roi window """ self.drawn_roi_list = {} if hasattr(self, 'bounds_box_draw'): delattr(self, 'bounds_box_draw') if hasattr(self, 'drawingROI'): delattr(self, 'drawingROI') self.ds = None self.close()
def tab_config(self): layout = QFormLayout() layout.addRow("Name", QLineEdit()) layout.addRow("Address", QLineEdit()) # self.setTabText(0,"Config Basics") self.tab1.setLayout(layout)