def _updateLabelShortcuts(self): numShortcuts = len(self._labelShortcuts) numRows = len(self._labelControlUi.labelListModel) mgr = ShortcutManager() ActionInfo = ShortcutManager.ActionInfo # Add any shortcuts we don't have yet. for i in range(numShortcuts, numRows): toolTipObject = LabelListModel.EntryToolTipAdapter( self._labelControlUi.labelListModel, i) action_info = ActionInfo( "Labeling", "Select Label {}".format(i + 1), "Select Label {}".format(i + 1), partial(self._labelControlUi.labelListView.selectRow, i), self._labelControlUi.labelListView, toolTipObject, ) mgr.register(str(i + 1), action_info) self._labelShortcuts.append(action_info) # Make sure that all shortcuts have an appropriate description for i in range(numRows): action_info = self._labelShortcuts[i] description = "Select " + self._labelControlUi.labelListModel[ i].name new_action_info = mgr.update_description(action_info, description) self._labelShortcuts[i] = new_action_info
def _initAppletDrawerUic(self, drawerPath=None): """ Load the ui file for the applet drawer, which we own. """ if drawerPath is None: localDir = os.path.split(__file__)[0] drawerPath = os.path.join(localDir, "dlClassificationDrawer.ui") self.drawer = uic.loadUi(drawerPath) self._setModelGuiVisible(False) self.drawer.comboBox.clear() self.drawer.liveUpdateButton.clicked.connect( self._livePredictionClicked) self.drawer.loadModel.clicked.connect(self._loadModelButtonClicked) if self.topLevelOperator.ModelPath.ready(): self.classifier = self.topLevelOperator.ModelPath.value self.drawer.comboBox.clear() self.drawer.comboBox.addItem(self.topLevelOperator.ModelPath.value) # Model for our list of classification labels (=classes) model = LabelListModel() self.drawer.labelListView.setModel(model) self.drawer.labelListModel = model # Add fixed labels for two classes. Currently our neural networks discriminate between two classes only. self._addNewLabel("Background", self._colorForLabel(1), None, makePermanent=True) self._addNewLabel("Foreground", self._colorForLabel(2), None, makePermanent=True)
def createWidget(self, parent): red = QColor(255, 0, 0) green = QColor(0, 255, 0) blue = QColor(0, 0, 255) model = LabelListModel([ Label("Label 1", red), Label("Label 2", green), Label("Label 3", blue) ]) a = LabelListView(parent) a.setModel(model) return a
def _updateLabelShortcuts(self): numShortcuts = len(self._labelShortcuts) numRows = len(self._labelControlUi.labelListModel) # Add any shortcuts we don't have yet. for i in range(numShortcuts, numRows): shortcut = QShortcut( QKeySequence(str(i + 1)), self, member=partial(self._labelControlUi.labelListView.selectRow, i)) self._labelShortcuts.append(shortcut) toolTipObject = LabelListModel.EntryToolTipAdapter( self._labelControlUi.labelListModel, i) ShortcutManager().register("Labeling", "", shortcut, toolTipObject) # Make sure that all shortcuts have an appropriate description for i in range(numRows): shortcut = self._labelShortcuts[i] description = "Select " + self._labelControlUi.labelListModel[ i].name ShortcutManager().setDescription(shortcut, description)
def _initLabelUic(self, drawerUiPath): _labelControlUi = uic.loadUi(drawerUiPath) # We own the applet bar ui self._labelControlUi = _labelControlUi # Initialize the label list model model = LabelListModel() _labelControlUi.labelListView.setModel(model) _labelControlUi.labelListModel = model _labelControlUi.labelListModel.rowsRemoved.connect( self._onLabelRemoved) _labelControlUi.labelListModel.elementSelected.connect( self._onLabelSelected) def handleClearRequested(row, name): selection = QMessageBox.warning( self, "Clear labels?", "All '{}' brush strokes will be erased. Are you sure?".format( name), QMessageBox.Ok | QMessageBox.Cancel, ) if selection != QMessageBox.Ok: return # This only works if the top-level operator has a 'clearLabel' function. self.topLevelOperatorView.clearLabel(row + 1) _labelControlUi.labelListView.clearRequested.connect( handleClearRequested) def handleLabelMergeRequested(from_row, from_name, into_row, into_name): from_label = from_row + 1 into_label = into_row + 1 selection = QMessageBox.warning( self, "Merge labels?", "All '{}' brush strokes will be converted to '{}'. Are you sure?" .format(from_name, into_name), QMessageBox.Ok | QMessageBox.Cancel, ) if selection != QMessageBox.Ok: return # This only works if the top-level operator has a 'mergeLabels' function. self.topLevelOperatorView.mergeLabels(from_label, into_label) names = list(self._labelingSlots.labelNames.value) names.pop(from_label - 1) self._labelingSlots.labelNames.setValue(names) _labelControlUi.labelListView.mergeRequested.connect( handleLabelMergeRequested) # Connect Applet GUI to our event handlers if hasattr(_labelControlUi, "AddLabelButton"): _labelControlUi.AddLabelButton.setIcon(QIcon(ilastikIcons.AddSel)) _labelControlUi.AddLabelButton.clicked.connect( bind(self._addNewLabel)) _labelControlUi.labelListModel.dataChanged.connect( self.onLabelListDataChanged) # Initialize the arrow tool button with an icon and handler iconPath = os.path.split(__file__)[0] + "/icons/arrow.png" arrowIcon = QIcon(iconPath) _labelControlUi.arrowToolButton.setIcon(arrowIcon) _labelControlUi.arrowToolButton.setCheckable(True) _labelControlUi.arrowToolButton.clicked.connect( lambda checked: self._handleToolButtonClicked( checked, Tool.Navigation)) # Initialize the paint tool button with an icon and handler paintBrushIconPath = os.path.split( __file__)[0] + "/icons/paintbrush.png" paintBrushIcon = QIcon(paintBrushIconPath) _labelControlUi.paintToolButton.setIcon(paintBrushIcon) _labelControlUi.paintToolButton.setCheckable(True) _labelControlUi.paintToolButton.clicked.connect( lambda checked: self._handleToolButtonClicked(checked, Tool.Paint)) # Initialize the erase tool button with an icon and handler eraserIconPath = os.path.split(__file__)[0] + "/icons/eraser.png" eraserIcon = QIcon(eraserIconPath) _labelControlUi.eraserToolButton.setIcon(eraserIcon) _labelControlUi.eraserToolButton.setCheckable(True) _labelControlUi.eraserToolButton.clicked.connect( lambda checked: self._handleToolButtonClicked(checked, Tool.Erase)) # Initialize the thresholding tool if hasattr(_labelControlUi, "thresToolButton"): thresholdIconPath = os.path.split( __file__)[0] + "/icons/threshold.png" thresholdIcon = QIcon(thresholdIconPath) _labelControlUi.thresToolButton.setIcon(thresholdIcon) _labelControlUi.thresToolButton.setCheckable(True) _labelControlUi.thresToolButton.clicked.connect( lambda checked: self._handleToolButtonClicked( checked, Tool.Threshold)) # This maps tool types to the buttons that enable them if hasattr(_labelControlUi, "thresToolButton"): self.toolButtons = { Tool.Navigation: _labelControlUi.arrowToolButton, Tool.Paint: _labelControlUi.paintToolButton, Tool.Erase: _labelControlUi.eraserToolButton, Tool.Threshold: _labelControlUi.thresToolButton, } else: self.toolButtons = { Tool.Navigation: _labelControlUi.arrowToolButton, Tool.Paint: _labelControlUi.paintToolButton, Tool.Erase: _labelControlUi.eraserToolButton, } self.brushSizes = [1, 3, 5, 7, 11, 23, 31, 61] for size in self.brushSizes: _labelControlUi.brushSizeComboBox.addItem(str(size)) _labelControlUi.brushSizeComboBox.currentIndexChanged.connect( self._onBrushSizeChange) self.paintBrushSizeIndex = preferences.get("labeling", "paint brush size", default=0) self.eraserSizeIndex = preferences.get("labeling", "eraser brush size", default=4)
def initLabelUic(self, drawerUiPath): _labelControlUi = uic.loadUi(drawerUiPath) # We own the applet bar ui self._labelControlUi = _labelControlUi # Initialize the label list model model = LabelListModel() _labelControlUi.labelListView.setModel(model) _labelControlUi.labelListModel = model _labelControlUi.labelListModel.rowsRemoved.connect(self.onLabelRemoved) _labelControlUi.labelListModel.labelSelected.connect( self.onLabelSelected) @traceLogged(traceLogger) def onDataChanged(topLeft, bottomRight): """Handle changes to the label list selections.""" firstRow = topLeft.row() lastRow = bottomRight.row() firstCol = topLeft.column() lastCol = bottomRight.column() if lastCol == firstCol == 0: assert (firstRow == lastRow ) #only one data item changes at a time #in this case, the actual data (for example color) has changed color = _labelControlUi.labelListModel[firstRow].color self._colorTable16[firstRow + 1] = color.rgba() self.editor.brushingModel.setBrushColor(color) # Update the label layer colortable to match the list entry labellayer = self.getLabelLayer() labellayer.colorTable = self._colorTable16 else: #this column is used for the 'delete' buttons, we don't care #about data changed here pass # Connect Applet GUI to our event handlers _labelControlUi.AddLabelButton.clicked.connect(bind(self.addNewLabel)) _labelControlUi.labelListModel.dataChanged.connect(onDataChanged) # Initialize the arrow tool button with an icon and handler iconPath = os.path.split(__file__)[0] + "/icons/arrow.jpg" arrowIcon = QIcon(iconPath) _labelControlUi.arrowToolButton.setIcon(arrowIcon) _labelControlUi.arrowToolButton.setCheckable(True) _labelControlUi.arrowToolButton.clicked.connect( lambda checked: self.handleToolButtonClicked( checked, Tool.Navigation)) # Initialize the paint tool button with an icon and handler paintBrushIconPath = os.path.split( __file__)[0] + "/icons/paintbrush.png" paintBrushIcon = QIcon(paintBrushIconPath) _labelControlUi.paintToolButton.setIcon(paintBrushIcon) _labelControlUi.paintToolButton.setCheckable(True) _labelControlUi.paintToolButton.clicked.connect( lambda checked: self.handleToolButtonClicked(checked, Tool.Paint)) # Initialize the erase tool button with an icon and handler eraserIconPath = os.path.split(__file__)[0] + "/icons/eraser.png" eraserIcon = QIcon(eraserIconPath) _labelControlUi.eraserToolButton.setIcon(eraserIcon) _labelControlUi.eraserToolButton.setCheckable(True) _labelControlUi.eraserToolButton.clicked.connect( lambda checked: self.handleToolButtonClicked(checked, Tool.Erase)) # This maps tool types to the buttons that enable them self.toolButtons = { Tool.Navigation: _labelControlUi.arrowToolButton, Tool.Paint: _labelControlUi.paintToolButton, Tool.Erase: _labelControlUi.eraserToolButton } self.brushSizes = [(1, ""), (3, "Tiny"), (5, "Small"), (7, "Medium"), (11, "Large"), (23, "Huge"), (31, "Megahuge"), (61, "Gigahuge")] for size, name in self.brushSizes: _labelControlUi.brushSizeComboBox.addItem(str(size) + " " + name) _labelControlUi.brushSizeComboBox.currentIndexChanged.connect( self.onBrushSizeChange) self.paintBrushSizeIndex = PreferencesManager().get('labeling', 'paint brush size', default=0) self.eraserSizeIndex = PreferencesManager().get('labeling', 'eraser brush size', default=4)
if __name__ == "__main__": # =========================================================================== # Example: of how the dotting interface works # we generate a random signal a certain position every 200 milliseconds # in order to simulate a signal of update from the graph. # =========================================================================== from ilastik.widgets.labelListModel import LabelListModel, Label from ilastik.widgets.labelListView import LabelListView from lazyflow.graph import Graph app = QApplication([]) labelListModel = LabelListModel() LV = LabelListView() LV.setModel(labelListModel) LV._table.setShowGrid(True) g = Graph() cron = QTimer() cron.start(500 * 3) op = OpArrayPiper2(graph=g) # Generate random noise shape = (1, 500, 500, 1, 1) array = np.random.randint(0, 255, 500 * 500).reshape(shape).astype(np.uint8) op.Input.setValue(array)
for _, v in list(self._currentDotsHash.items()): v.setVisible(boolval) if __name__ == "__main__": #=========================================================================== # Example: of how the dotting interface works # we generate a random signal a certain position every 200 milliseconds # in order to simulate a signal of update from the graph. #=========================================================================== from ilastik.widgets.labelListModel import LabelListModel, Label from ilastik.widgets.labelListView import LabelListView from lazyflow.graph import Graph app = QApplication([]) labelListModel = LabelListModel() LV = LabelListView() LV.setModel(labelListModel) LV._table.setShowGrid(True) g = Graph() cron = QTimer() cron.start(500 * 3) op = OpArrayPiper2(graph=g) #Generate random noise shape = (1, 500, 500, 1, 1) array = np.random.randint(0, 255, 500 * 500).reshape(shape).astype(np.uint8) op.Input.setValue(array)
def __init__(self, parentApplet, topLevelOperatorView, drawerUiPath=None ): self.topLevelOperatorView = topLevelOperatorView #members self._doneSegmentationLayer = None self._showSegmentationIn3D = False self._showUncertaintyLayer = False #end: members labelingSlots = LabelingGui.LabelingSlots() labelingSlots.labelInput = topLevelOperatorView.WriteSeeds labelingSlots.labelOutput = topLevelOperatorView.opLabelArray.Output labelingSlots.labelEraserValue = topLevelOperatorView.opLabelArray.EraserLabelValue labelingSlots.labelNames = topLevelOperatorView.LabelNames labelingSlots.labelDelete = topLevelOperatorView.opLabelArray.DeleteLabel labelingSlots.maxLabelValue = topLevelOperatorView.opLabelArray.MaxLabelValue labelingSlots.labelsAllowed = topLevelOperatorView.LabelsAllowed # We provide our own UI file (which adds an extra control for interactive mode) directory = os.path.split(__file__)[0] if drawerUiPath is None: drawerUiPath = os.path.join(directory, 'carvingDrawer.ui') self.dialogdirCOM = os.path.join(directory, 'carvingObjectManagement.ui') self.dialogdirSAD = os.path.join(directory, 'saveAsDialog.ui') rawInputSlot = topLevelOperatorView.RawData super(CarvingGui, self).__init__(parentApplet, labelingSlots, topLevelOperatorView, drawerUiPath, rawInputSlot) self.labelingDrawerUi.currentObjectLabel.setText("<not saved yet>") # Init special base class members self.minLabelNumber = 2 self.maxLabelNumber = 2 mgr = ShortcutManager() ActionInfo = ShortcutManager.ActionInfo #set up keyboard shortcuts mgr.register( "3", ActionInfo( "Carving", "Run interactive segmentation", "Run interactive segmentation", self.labelingDrawerUi.segment.click, self.labelingDrawerUi.segment, self.labelingDrawerUi.segment ) ) try: self.render = True self._shownObjects3D = {} self._renderMgr = RenderingManager( self.editor.view3d ) except: self.render = False # Segmentation is toggled on by default in _after_init, below. # (We can't enable it until the layers are all present.) self._showSegmentationIn3D = False self._segmentation_3d_label = None self.labelingDrawerUi.segment.clicked.connect(self.onSegmentButton) self.labelingDrawerUi.segment.setEnabled(True) self.topLevelOperatorView.Segmentation.notifyDirty( bind( self._update_rendering ) ) self.topLevelOperatorView.HasSegmentation.notifyValueChanged( bind( self._updateGui ) ) ## uncertainty self.labelingDrawerUi.pushButtonUncertaintyFG.setEnabled(False) self.labelingDrawerUi.pushButtonUncertaintyBG.setEnabled(False) def onUncertaintyFGButton(): logger.debug( "uncertFG button clicked" ) pos = self.topLevelOperatorView.getMaxUncertaintyPos(label=2) self.editor.posModel.slicingPos = (pos[0], pos[1], pos[2]) self.labelingDrawerUi.pushButtonUncertaintyFG.clicked.connect(onUncertaintyFGButton) def onUncertaintyBGButton(): logger.debug( "uncertBG button clicked" ) pos = self.topLevelOperatorView.getMaxUncertaintyPos(label=1) self.editor.posModel.slicingPos = (pos[0], pos[1], pos[2]) self.labelingDrawerUi.pushButtonUncertaintyBG.clicked.connect(onUncertaintyBGButton) def onUncertaintyCombo(value): if value == 0: value = "none" self.labelingDrawerUi.pushButtonUncertaintyFG.setEnabled(False) self.labelingDrawerUi.pushButtonUncertaintyBG.setEnabled(False) self._showUncertaintyLayer = False else: if value == 1: value = "localMargin" elif value == 2: value = "exchangeCount" elif value == 3: value = "gabow" else: raise RuntimeError("unhandled case '%r'" % value) self.labelingDrawerUi.pushButtonUncertaintyFG.setEnabled(True) self.labelingDrawerUi.pushButtonUncertaintyBG.setEnabled(True) self._showUncertaintyLayer = True logger.debug( "uncertainty changed to %r" % value ) self.topLevelOperatorView.UncertaintyType.setValue(value) self.updateAllLayers() #make sure that an added/deleted uncertainty layer is recognized self.labelingDrawerUi.uncertaintyCombo.currentIndexChanged.connect(onUncertaintyCombo) ## background priority def onBackgroundPrioritySpin(value): logger.debug( "background priority changed to %f" % value ) self.topLevelOperatorView.BackgroundPriority.setValue(value) self.labelingDrawerUi.backgroundPrioritySpin.valueChanged.connect(onBackgroundPrioritySpin) def onBackgroundPriorityDirty(slot, roi): oldValue = self.labelingDrawerUi.backgroundPrioritySpin.value() newValue = self.topLevelOperatorView.BackgroundPriority.value if newValue != oldValue: self.labelingDrawerUi.backgroundPrioritySpin.setValue(newValue) self.topLevelOperatorView.BackgroundPriority.notifyDirty(onBackgroundPriorityDirty) ## bias def onNoBiasBelowDirty(slot, roi): oldValue = self.labelingDrawerUi.noBiasBelowSpin.value() newValue = self.topLevelOperatorView.NoBiasBelow.value if newValue != oldValue: self.labelingDrawerUi.noBiasBelowSpin.setValue(newValue) self.topLevelOperatorView.NoBiasBelow.notifyDirty(onNoBiasBelowDirty) def onNoBiasBelowSpin(value): logger.debug( "background priority changed to %f" % value ) self.topLevelOperatorView.NoBiasBelow.setValue(value) self.labelingDrawerUi.noBiasBelowSpin.valueChanged.connect(onNoBiasBelowSpin) ## save self.labelingDrawerUi.save.clicked.connect(self.onSaveButton) ## clear self.labelingDrawerUi.clear.clicked.connect(self._onClearAction) ## object names self.labelingDrawerUi.namesButton.clicked.connect(self.onShowObjectNames) if hasattr( self.labelingDrawerUi, 'exportAllMeshesButton' ): self.labelingDrawerUi.exportAllMeshesButton.clicked.connect(self._exportAllObjectMeshes) def labelBackground(): self.selectLabel(0) def labelObject(): self.selectLabel(1) self._labelControlUi.labelListModel.allowRemove(False) bgToolTipObject = LabelListModel.EntryToolTipAdapter(self._labelControlUi.labelListModel, 0) mgr.register( "1", ActionInfo( "Carving", "Select background label", "Select background label", labelBackground, self.viewerControlWidget(), bgToolTipObject ) ) fgToolTipObject = LabelListModel.EntryToolTipAdapter(self._labelControlUi.labelListModel, 1) mgr.register( "2", ActionInfo( "Carving", "Select object label", "Select object label", labelObject, self.viewerControlWidget(), fgToolTipObject ) ) def layerIndexForName(name): return self.layerstack.findMatchingIndex(lambda x: x.name == name) def addLayerToggleShortcut(layername, shortcut): def toggle(): row = layerIndexForName(layername) self.layerstack.selectRow(row) layer = self.layerstack[row] layer.visible = not layer.visible self.viewerControlWidget().layerWidget.setFocus() mgr.register(shortcut, ActionInfo( "Carving", "Toggle layer %s" % layername, "Toggle layer %s" % layername, toggle, self.viewerControlWidget(), None ) ) #TODO addLayerToggleShortcut("Completed segments (unicolor)", "d") addLayerToggleShortcut("Segmentation", "s") addLayerToggleShortcut("Input Data", "r") ''' def updateLayerTimings(): s = "Layer timings:\n" for l in self.layerstack: s += "%s: %f sec.\n" % (l.name, l.averageTimePerTile) self.labelingDrawerUi.layerTimings.setText(s) t = QTimer(self) t.setInterval(1*1000) # 10 seconds t.start() t.timeout.connect(updateLayerTimings) ''' def makeColortable(): self._doneSegmentationColortable = [QColor(0,0,0,0).rgba()] for i in range(254): r,g,b = numpy.random.randint(0,255), numpy.random.randint(0,255), numpy.random.randint(0,255) # ensure colors have sufficient distance to pure red and pure green while (255 - r)+g+b<128 or r+(255-g)+b<128: r,g,b = numpy.random.randint(0,255), numpy.random.randint(0,255), numpy.random.randint(0,255) self._doneSegmentationColortable.append(QColor(r,g,b).rgba()) self._doneSegmentationColortable.append(QColor(0,255,0).rgba()) makeColortable() def onRandomizeColors(): if self._doneSegmentationLayer is not None: logger.debug( "randomizing colors ..." ) makeColortable() self._doneSegmentationLayer.colorTable = self._doneSegmentationColortable if self.render and self._renderMgr.ready: self._update_rendering() #self.labelingDrawerUi.randomizeColors.clicked.connect(onRandomizeColors) self._updateGui()
def _initLabelUic(self, drawerUiPath): _labelControlUi = uic.loadUi(drawerUiPath) # We own the applet bar ui self._labelControlUi = _labelControlUi # Initialize the label list model model = LabelListModel() _labelControlUi.labelListView.setModel(model) _labelControlUi.labelListModel=model _labelControlUi.labelListModel.rowsRemoved.connect(self._onLabelRemoved) _labelControlUi.labelListModel.elementSelected.connect(self._onLabelSelected) # Connect Applet GUI to our event handlers if hasattr(_labelControlUi, "AddLabelButton"): _labelControlUi.AddLabelButton.setIcon( QIcon(ilastikIcons.AddSel) ) _labelControlUi.AddLabelButton.clicked.connect( bind(self._addNewLabel) ) _labelControlUi.labelListModel.dataChanged.connect(self.onLabelListDataChanged) # Initialize the arrow tool button with an icon and handler iconPath = os.path.split(__file__)[0] + "/icons/arrow.png" arrowIcon = QIcon(iconPath) _labelControlUi.arrowToolButton.setIcon(arrowIcon) _labelControlUi.arrowToolButton.setCheckable(True) _labelControlUi.arrowToolButton.clicked.connect( lambda checked: self._handleToolButtonClicked(checked, Tool.Navigation) ) # Initialize the paint tool button with an icon and handler paintBrushIconPath = os.path.split(__file__)[0] + "/icons/paintbrush.png" paintBrushIcon = QIcon(paintBrushIconPath) _labelControlUi.paintToolButton.setIcon(paintBrushIcon) _labelControlUi.paintToolButton.setCheckable(True) _labelControlUi.paintToolButton.clicked.connect( lambda checked: self._handleToolButtonClicked(checked, Tool.Paint) ) # Initialize the erase tool button with an icon and handler eraserIconPath = os.path.split(__file__)[0] + "/icons/eraser.png" eraserIcon = QIcon(eraserIconPath) _labelControlUi.eraserToolButton.setIcon(eraserIcon) _labelControlUi.eraserToolButton.setCheckable(True) _labelControlUi.eraserToolButton.clicked.connect( lambda checked: self._handleToolButtonClicked(checked, Tool.Erase) ) # Initialize the thresholding tool if hasattr(_labelControlUi, "thresToolButton"): thresholdIconPath = os.path.split(__file__)[0] \ + "/icons/threshold.png" thresholdIcon = QIcon(thresholdIconPath) _labelControlUi.thresToolButton.setIcon(thresholdIcon) _labelControlUi.thresToolButton.setCheckable(True) _labelControlUi.thresToolButton.clicked.connect( lambda checked: self._handleToolButtonClicked(checked, Tool.Threshold) ) # This maps tool types to the buttons that enable them if hasattr(_labelControlUi, "thresToolButton"): self.toolButtons = { Tool.Navigation : _labelControlUi.arrowToolButton, Tool.Paint : _labelControlUi.paintToolButton, Tool.Erase : _labelControlUi.eraserToolButton, Tool.Threshold : _labelControlUi.thresToolButton} else: self.toolButtons = { Tool.Navigation : _labelControlUi.arrowToolButton, Tool.Paint : _labelControlUi.paintToolButton, Tool.Erase : _labelControlUi.eraserToolButton} self.brushSizes = [ 1, 3, 5, 7, 11, 23, 31, 61 ] for size in self.brushSizes: _labelControlUi.brushSizeComboBox.addItem( str(size) ) _labelControlUi.brushSizeComboBox.currentIndexChanged.connect(self._onBrushSizeChange) self.paintBrushSizeIndex = PreferencesManager().get( 'labeling', 'paint brush size', default=0 ) self.eraserSizeIndex = PreferencesManager().get( 'labeling', 'eraser brush size', default=4 )