def setup(self): ScriptedLoadableModuleWidget.setup(self) # Instantiate and connect widgets ... # # File area # filesCollapsibleButton = ctk.ctkCollapsibleButton() filesCollapsibleButton.text = "Input files" filesCollapsibleButton.collapsed = False self.layout.addWidget(filesCollapsibleButton) # Layout within the files collapsible button filesFormLayout = qt.QFormLayout(filesCollapsibleButton) # select one file buttonLayout = qt.QHBoxLayout() self.archetypeText = qt.QLineEdit() buttonLayout.addWidget(self.archetypeText) self.addFromArchetype = qt.QPushButton("Browse...") buttonLayout.addWidget(self.addFromArchetype) self.archetypeStartNumber = 0 filesFormLayout.addRow("Filename pattern: ", buttonLayout) # file list group fileListGroupBox = ctk.ctkCollapsibleGroupBox() fileListGroupBox.title = "File list" fileListLayout = qt.QVBoxLayout() fileListGroupBox.setLayout(fileListLayout) filesFormLayout.addRow("", fileListGroupBox) self.addByBrowsingButton = qt.QPushButton("Select files...") fileListLayout.addWidget(self.addByBrowsingButton) self.fileTable = qt.QTextBrowser() fileListLayout.addWidget(self.fileTable) fileListGroupBox.collapsed = True # original volume size self.originalVolumeSizeLabel = qt.QLabel() filesFormLayout.addRow("Size: ", self.originalVolumeSizeLabel) # reverse slice order self.reverseCheckBox = qt.QCheckBox() self.reverseCheckBox.toolTip = "Read the images in reverse order (flips loaded volume along IS axis)" filesFormLayout.addRow("Reverse: ", self.reverseCheckBox) # original spacing self.spacingWidget = slicer.qMRMLCoordinatesWidget() self.spacingWidget.setMRMLScene(slicer.mrmlScene) self.spacingWidget.decimalsOption = ctk.ctkDoubleSpinBox.DecimalsByKey | ctk.ctkDoubleSpinBox.DecimalsByShortcuts | ctk.ctkDoubleSpinBox.DecimalsByValue self.spacingWidget.minimum = 0.0 self.spacingWidget.maximum = 1000000000.0 self.spacingWidget.quantity = "length" self.spacingWidget.unitAwareProperties = slicer.qMRMLCoordinatesWidget.Precision | slicer.qMRMLCoordinatesWidget.Prefix | slicer.qMRMLCoordinatesWidget.Scaling | slicer.qMRMLCoordinatesWidget.Suffix self.spacingWidget.coordinates = "1,1,1" self.spacingWidget.toolTip = "Set the colunm, row, slice spacing; original spacing not including downsample" filesFormLayout.addRow("Spacing: ", self.spacingWidget) # # output area # outputCollapsibleButton = ctk.ctkCollapsibleButton() outputCollapsibleButton.text = "Output" outputCollapsibleButton.collapsed = False self.layout.addWidget(outputCollapsibleButton) outputFormLayout = qt.QFormLayout(outputCollapsibleButton) # # output volume selector # self.outputSelector = slicer.qMRMLNodeComboBox() self.outputSelector.nodeTypes = [ "vtkMRMLScalarVolumeNode", "vtkMRMLVectorVolumeNode" ] self.outputSelector.showChildNodeTypes = False self.outputSelector.showHidden = False self.outputSelector.showChildNodeTypes = False self.outputSelector.selectNodeUponCreation = True self.outputSelector.noneEnabled = True self.outputSelector.removeEnabled = True self.outputSelector.renameEnabled = True self.outputSelector.addEnabled = True self.outputSelector.noneDisplay = "(Create new volume)" self.outputSelector.setMRMLScene(slicer.mrmlScene) self.outputSelector.setToolTip( "Pick the output volume to populate or None to autogenerate.") outputFormLayout.addRow("Output Volume: ", self.outputSelector) # # output ROI selector # self.outputROISelector = slicer.qMRMLNodeComboBox() self.outputROISelector.nodeTypes = [ "vtkMRMLAnnotationROINode", "vtkMRMLMarkupsROINode" ] self.outputROISelector.showChildNodeTypes = False self.outputROISelector.showHidden = False self.outputROISelector.showChildNodeTypes = False self.outputROISelector.noneEnabled = True self.outputROISelector.removeEnabled = True self.outputROISelector.renameEnabled = True self.outputROISelector.addEnabled = False self.outputROISelector.noneDisplay = "(Full volume)" self.outputROISelector.setMRMLScene(slicer.mrmlScene) self.outputROISelector.setToolTip( "Set the region of the volume that will be loaded") outputFormLayout.addRow("Region of interest: ", self.outputROISelector) # # Quality selector # qualityLayout = qt.QVBoxLayout() self.qualityPreviewRadioButton = qt.QRadioButton("preview") self.qualityHalfRadioButton = qt.QRadioButton("half resolution") self.qualityFullRadioButton = qt.QRadioButton("full resolution") qualityLayout.addWidget(self.qualityPreviewRadioButton) qualityLayout.addWidget(self.qualityHalfRadioButton) qualityLayout.addWidget(self.qualityFullRadioButton) self.qualityPreviewRadioButton.setChecked(True) outputFormLayout.addRow("Quality: ", qualityLayout) self.sliceSkipSpinBox = qt.QSpinBox() self.sliceSkipSpinBox.toolTip = "Skips the selected number of slices between each pair of output volume slices (use, for example, on long thin samples with more slices than in-plane resolution)" outputFormLayout.addRow("Slice skip: ", self.sliceSkipSpinBox) # Force grayscale output self.grayscaleCheckBox = qt.QCheckBox() self.grayscaleCheckBox.toolTip = "Force reading the image in grayscale. Only makes a difference if the input has color (RGB or RGBA) voxels." self.grayscaleCheckBox.checked = True outputFormLayout.addRow("Grayscale: ", self.grayscaleCheckBox) # output volume size self.outputVolumeSizeLabel = qt.QLabel() outputFormLayout.addRow("Output size: ", self.outputVolumeSizeLabel) # output volume spacing self.outputSpacingWidget = slicer.qMRMLCoordinatesWidget() self.outputSpacingWidget.setMRMLScene(slicer.mrmlScene) self.outputSpacingWidget.readOnly = True self.outputSpacingWidget.frame = False self.outputSpacingWidget.decimalsOption = ctk.ctkDoubleSpinBox.DecimalsByKey | ctk.ctkDoubleSpinBox.DecimalsByShortcuts | ctk.ctkDoubleSpinBox.DecimalsByValue self.outputSpacingWidget.minimum = 0.0 self.outputSpacingWidget.maximum = 1000000000.0 self.outputSpacingWidget.quantity = "length" self.outputSpacingWidget.unitAwareProperties = slicer.qMRMLCoordinatesWidget.Precision | slicer.qMRMLCoordinatesWidget.Prefix | slicer.qMRMLCoordinatesWidget.Scaling | slicer.qMRMLCoordinatesWidget.Suffix self.outputSpacingWidget.coordinates = "1,1,1" self.outputSpacingWidget.toolTip = "Slice spacing of the volume that will be loaded" outputFormLayout.addRow("Output spacing: ", self.outputSpacingWidget) self.loadButton = qt.QPushButton("Load files") self.loadButton.toolTip = "Load files as a 3D volume" self.loadButton.enabled = False outputFormLayout.addRow(self.loadButton) # connections self.reverseCheckBox.connect('toggled(bool)', self.updateLogicFromWidget) self.sliceSkipSpinBox.connect("valueChanged(int)", self.updateLogicFromWidget) self.spacingWidget.connect("coordinatesChanged(double*)", self.updateLogicFromWidget) self.qualityPreviewRadioButton.connect( "toggled(bool)", lambda toggled, widget=self.qualityPreviewRadioButton: self. onQualityToggled(toggled, widget)) self.qualityHalfRadioButton.connect( "toggled(bool)", lambda toggled, widget=self.qualityHalfRadioButton: self. onQualityToggled(toggled, widget)) self.qualityFullRadioButton.connect( "toggled(bool)", lambda toggled, widget=self.qualityFullRadioButton: self. onQualityToggled(toggled, widget)) self.grayscaleCheckBox.connect('toggled(bool)', self.updateLogicFromWidget) self.outputROISelector.connect("currentNodeChanged(vtkMRMLNode*)", self.setOutputROINode) self.addByBrowsingButton.connect('clicked()', self.addByBrowsing) self.addFromArchetype.connect('clicked()', self.selectArchetype) self.archetypeText.connect('textChanged(const QString &)', self.populateFromArchetype) self.loadButton.connect('clicked()', self.onLoadButton) # Add vertical spacer self.layout.addStretch(1) self.loadButton.enabled = False
def setup(self): ScriptedLoadableModuleWidget.setup(self) # Instantiate and connect widgets ... # # File area # filesCollapsibleButton = ctk.ctkCollapsibleButton() filesCollapsibleButton.text = "Files" filesCollapsibleButton.collapsed = False self.layout.addWidget(filesCollapsibleButton) # Layout within the files collapsible button filesFormLayout = qt.QFormLayout(filesCollapsibleButton) self.fileModel = qt.QStandardItemModel() self.fileTable = qt.QTableView() self.fileTable.horizontalHeader().stretchLastSection = True self.fileTable.horizontalHeader().visible = False self.fileTable.setModel(self.fileModel) filesFormLayout.addRow(self.fileTable) buttonLayout = qt.QHBoxLayout() self.addByBrowsingButton = qt.QPushButton("Browse for files") self.clearButton = qt.QPushButton("Clear") buttonLayout.addWidget(self.addByBrowsingButton) buttonLayout.addWidget(self.clearButton) filesFormLayout.addRow(buttonLayout) self.propertiesLabel = qt.QLabel() filesFormLayout.addRow(self.propertiesLabel) # # output area # outputCollapsibleButton = ctk.ctkCollapsibleButton() outputCollapsibleButton.text = "Output" outputCollapsibleButton.collapsed = False self.layout.addWidget(outputCollapsibleButton) outputFormLayout = qt.QFormLayout(outputCollapsibleButton) # # output volume selector # self.outputSelector = slicer.qMRMLNodeComboBox() self.outputSelector.nodeTypes = ["vtkMRMLScalarVolumeNode",] self.outputSelector.showChildNodeTypes = False self.outputSelector.showHidden = False self.outputSelector.showChildNodeTypes = False self.outputSelector.selectNodeUponCreation = True self.outputSelector.noneEnabled = True self.outputSelector.removeEnabled = True self.outputSelector.renameEnabled = True self.outputSelector.addEnabled = True self.outputSelector.setMRMLScene( slicer.mrmlScene ) self.outputSelector.setToolTip( "Pick the output volume to populate or None to autogenerate." ) outputFormLayout.addRow("Output Volume: ", self.outputSelector) self.spacing = slicer.qMRMLCoordinatesWidget() self.spacing.decimalsOption = ctk.ctkDoubleSpinBox.DecimalsByKey | ctk.ctkDoubleSpinBox.DecimalsByShortcuts | ctk.ctkDoubleSpinBox.DecimalsByValue self.spacing.minimum = 0.0 self.spacing.maximum = 1000000000.0 self.spacing.quantity = "length" self.spacing.unitAwareProperties = slicer.qMRMLCoordinatesWidget.Precision | slicer.qMRMLCoordinatesWidget.Prefix | slicer.qMRMLCoordinatesWidget.Scaling | slicer.qMRMLCoordinatesWidget.Suffix self.spacing.decimals = 8 self.spacing.coordinates = "1,1,1" self.spacing.toolTip = "Set the colunm, row, slice spacing in mm; original spacing not including downsample" outputFormLayout.addRow("Spacing: ", self.spacing) self.downsample = qt.QCheckBox() self.downsample.toolTip = "Reduces data size by half in each dimension by skipping every other pixel and slice (uses about 1/8 memory)" outputFormLayout.addRow("Downsample: ", self.downsample) self.reverse = qt.QCheckBox() self.reverse.toolTip = "Read the images in reverse order" outputFormLayout.addRow("Reverse: ", self.reverse) self.sliceSkip = ctk.ctkDoubleSpinBox() self.sliceSkip.decimals = 0 self.sliceSkip.minimum = 0 self.sliceSkip.toolTip = "Skips the selected number of slices (use, for example, on long thin samples with more slices than in-plane resolution)" outputFormLayout.addRow("Slice skip: ", self.sliceSkip) self.loadButton = qt.QPushButton("Load files") outputFormLayout.addRow(self.loadButton) # # Add by name area # addByNameCollapsibleButton = ctk.ctkCollapsibleButton() addByNameCollapsibleButton.text = "Add files by name" addByNameCollapsibleButton.collapsed = True addByNameFormLayout = qt.QFormLayout(addByNameCollapsibleButton) # Don't enable Add by name for now - let's see if it's actually needed # self.layout.addWidget(addByNameCollapsibleButton) forExample = """ directoryPath = '/Volumes/SSD2T/data/SlicerMorph/Sample_for_steve/1326_Rec' pathFormat = '%s/1326__rec%04d.png' start, end = (50, 621) """ self.archetypePathEdit = ctk.ctkPathLineEdit() self.archetypePathEdit.filters = ctk.ctkPathLineEdit().Files addByNameFormLayout.addRow("Archetype file", self.archetypePathEdit) self.archetypeFormat = qt.QLineEdit() addByNameFormLayout.addRow("Name format", self.archetypeFormat) self.indexRange = ctk.ctkRangeWidget() self.indexRange.decimals = 0 self.indexRange.maximum = 0 addByNameFormLayout.addRow("Index range", self.indexRange) self.generateNamesButton = qt.QPushButton("Apply") self.generateNamesButton.toolTip = "Run the algorithm." self.generateNamesButton.enabled = False addByNameFormLayout.addRow(self.generateNamesButton) # connections self.addByBrowsingButton.connect('clicked()', self.addByBrowsing) self.clearButton.connect('clicked()', self.onClear) self.archetypePathEdit.connect('currentPathChanged(QString)', self.validateInput) self.archetypePathEdit.connect('currentPathChanged(QString)', self.updateGUIFromArchetype) self.archetypeFormat.connect('textChanged(QString)', self.validateInput) self.generateNamesButton.connect('clicked()', self.onGenerateNames) # self.outputSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.validateInput) # TODO - this is missing self.loadButton.connect('clicked()', self.onLoadButton) # refill last selection self.archetypePathEdit.currentPath = slicer.util.settingsValue("ImageStacks/lastArchetypePath", "") # Add vertical spacer self.layout.addStretch(1) # Refresh Apply button state self.validateInput()