コード例 #1
0
ファイル: mainwindow.py プロジェクト: tangzheng1104/test
    def setupUi(self, *args):
        # called in MainWindowBase.__init__()
        # put the log widget at the bottom
        self.addDockWidget(Qt.BottomDockWidgetArea, self._setupLogWidget())
        # file widget at the top
        self.toolbox = ToolBox(self)
        self._addToolboxItem(self._setupFileWidget())
        self._addToolboxItem(self._setupDataWidget())
        self._addToolboxItem(self._setupOptimWidget())
        self._addToolboxItem(self._setupModelWidget())
        self._addToolboxItem(self._setupStatsWidget())

        # set up central widget of the main window
        self.centralLayout = QVBoxLayout()
        # put buttons in central widget
        self.centralLayout.addWidget(self.toolbox)
        self.centralLayout.addWidget(self._setupStartButton())
        centralWidget = QWidget(self)
        centralWidget.setLayout(self.centralLayout)
        centralWidget.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum)
        self.setCentralWidget(centralWidget)
        self.onStartupSignal.connect(self.initUi)
        # set program icon, same for Win+Lin
        icopath = "resources/icon/mcsas.ico"
        if isMac():
            icopath = "resources/icon/mcsas.icns"
        icopath = QFileInfo(makeAbsolutePath(icopath)).absoluteFilePath()
        self.setWindowIcon(QIcon(icopath))
コード例 #2
0
 def _createEntries(self):
     entryWidget = QWidget(self)
     entryLayout = QHBoxLayout(entryWidget)
     inputWidgets = (self._createParamBox(), self._createAutoRange(),
                     self._createLower(), self._createUpper(),
                     self._createBins(), self._createXScale(),
                     self._createYWeight())
     self._labels = dict()
     # assumes same ordering of entryWidgets above and Histogram.displayData
     for col, inputWidget in zip(Histogram.displayData, inputWidgets):
         fieldWidget = QWidget(self)  # combines label + input
         fieldLayout = QVBoxLayout(fieldWidget)
         fieldLayout.setContentsMargins(QMargins())
         # create label, text is set in _selectParam()
         self._labels[col] = QLabel(self)
         self._labels[col].setAlignment(Qt.AlignHCenter)
         # stack label + input
         fieldLayout.addWidget(self._labels[col])
         fieldLayout.addWidget(inputWidget)
         fieldWidget.setLayout(fieldLayout)
         # add field to row of inputs
         entryLayout.addWidget(fieldWidget)
     entryWidget.setLayout(entryLayout)
     self.pbox.setCurrentIndex(0)
     self.lentry.selectAll()  # select the first input by default
     return entryWidget
コード例 #3
0
 def _createButtons(self):
     btnWidget = QWidget(self)
     btnLayout = QHBoxLayout(btnWidget)
     okBtn = QPushButton("add", self)
     okBtn.clicked.connect(self.accept)
     cancelBtn = QPushButton("cancel", self)
     cancelBtn.clicked.connect(self.reject)
     btnLayout.addWidget(okBtn)
     btnLayout.addWidget(cancelBtn)
     btnWidget.setLayout(btnLayout)
     return btnWidget
コード例 #4
0
ファイル: mainwindow.py プロジェクト: tangzheng1104/test
 def _setupStartButton(self):
     """Set up "Start/Stop" - button."""
     self.startStopBtn = QPushButton()
     self.startStopBtn.setCheckable(True)
     self.startStopBtn.clicked[bool].connect(self.onStartStopClick)
     btnLayout = QHBoxLayout()
     btnLayout.setContentsMargins(0, 0, 0, 0)
     self.startStopBtn.setSizePolicy(QSizePolicy.Maximum,
                                     QSizePolicy.Maximum)
     btnLayout.addWidget(self.startStopBtn)
     btnWidget = QWidget(self)
     btnWidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum)
     btnWidget.setLayout(btnLayout)
     return btnWidget
コード例 #5
0
    def makeSetting(self, param, activeBtns=False):
        """Creates an input widget for the provided Parameter and configures
        it appropriately.
        """
        if param is None:
            return None
        widget = QWidget(self)
        layout = QHBoxLayout(widget)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addStretch()

        try:
            suffix = param.suffix()
        except AttributeError:
            suffix = None

        if suffix is None:
            layout.addWidget(self._makeLabel(param.displayName()))
        else:
            layout.addWidget(
                self._makeLabel(u"{} ({})".format(param.displayName(),
                                                  suffix)))

        widget.setLayout(layout)
        if isString(param.__doc__):
            # word wrapping by rich text: https://stackoverflow.com/a/4796057
            txt = "<span>{0}</span>".format(param.__doc__)
            # add description as tooltip if available for parameter
            widget.setToolTip(txt)

        # create scalar value input widget with min/max limits
        minmaxValue, widgets = None, []
        if isinstance(param, ParameterNumerical):
            minmaxValue = param.min(), param.max()
        if isinstance(param, ParameterFloat):
            minmaxValue = param.displayValueRange()
        decimals = None
        if hasattr(param, "decimals"):
            decimals = param.decimals()
        w = self._makeEntry(param.name(),
                            param.dtype,
                            param.displayValue(),
                            decimals=decimals,
                            minmax=minmaxValue,
                            parent=widget)
        try:  # set special value text for lower bound, simple solution
            special = param.displayValues(w.minimum())
            w.setSpecialValueText(special)
        except:
            pass
        w.setFixedWidth(FIXEDWIDTH)
        widgets.insert(old_div(len(widgets), 2), w)

        # Special widget settings for active fitting parameters:
        activeBtns = activeBtns and isinstance(param, FitParameterBase)
        if activeBtns:
            # create input boxes for user specified active fitting range
            # within default upper/lower from class definition
            # minmaxValue = type(param).min(), type(param).max()
            activeRange = {
                "min": param.displayActiveRange()[0],
                "max": param.displayActiveRange()[1]
            }
            for bound in "min", "max":
                w = self._makeEntry(param.name() + bound,
                                    param.dtype,
                                    activeRange[bound],
                                    decimals=decimals,
                                    minmax=minmaxValue,
                                    parent=widget)
                w.setPrefix(bound + ": ")
                w.setFixedWidth(FIXEDWIDTH)
                widgets.append(w)
            # create *active* buttons for FitParameters only
            w = self._makeEntry(param.name() + "active",
                                bool,
                                param.isActive(),
                                widgetType=QPushButton,
                                parent=widget)
            w.setText("Active")
            w.setFixedWidth(FIXEDWIDTH * .5)
            widgets.append(w)

        # add input widgets to the layout
        for w in widgets:
            layout.addWidget(w)
            # store the parameter name
            w.parameterName = param.name()
        # configure UI accordingly (hide/show widgets)
        # no backend update, ui was just built, data is still in sync
        self.updateParam(param, emitBackendUpdated=False)
        return widget
コード例 #6
0
class ModelWidget(AlgorithmWidget):
    _calculator = None
    _statsWidget = None  # RangeList for (re-)storing histogram settings
    _models = None

    def __init__(self, parent, calculator, *args):
        super(ModelWidget, self).__init__(parent, None, *args)
        self._calculator = calculator
        self.title = TitleHandler.setup(self, "Model")
        # get all loadable ScatteringModels from model directory
        self._models = FindModels()

        layout = QVBoxLayout(self)
        layout.setObjectName("modelLayout")
        self.setLayout(layout)

        self.modelBox = QComboBox(self)
        self.modelBox.setFixedWidth(FIXEDWIDTH)
        layout.addWidget(self.modelBox)
        self.modelWidget = QWidget(self)
        paramLayout = QVBoxLayout(self.modelWidget)
        self.modelWidget.setLayout(paramLayout)
        layout.addWidget(self.modelWidget)

    def setStatsWidget(self, statsWidget):
        """Sets the statistics widget to use for updating ranges."""
        assert (isinstance(statsWidget, AppSettings))
        self._statsWidget = statsWidget

    def onDataSelected(self, dataobj):
        """Gets the data which is currently selected in the UI and rebuilds
        the model selection box based on compatible models."""
        if not isinstance(dataobj, DataObj):
            return
        try:
            self.modelBox.currentIndexChanged[int].disconnect()
        except:
            pass
        self.modelBox.clear()
        # build selection list of available models
        for modelid in self._models:
            cls, dummy = self._models[modelid]
            if cls is None or not issubclass(cls, dataobj.modelType):
                continue
            category = modelid.split('.')[0:-2]
            if category[0] == self._models.rootName:
                del category[0]
            # set up the display name of the model, may contain category
            displayName = " / ".join(category + [
                cls.name(),
            ])
            # store the unique model identifier alongside its title
            self.modelBox.addItem(displayName, modelid)
        self.modelBox.setCurrentIndex(-1)  # select none first
        self.modelBox.currentIndexChanged[int].connect(self._selectModelSlot)
        # trigger signal by switching from none -> 0
        self.modelBox.setCurrentIndex(0)

    def storeSession(self, section=None):
        if self.appSettings is None or self.model is None:
            return
        model = self.model.name()
        self.setRootGroup()
        self.appSettings.beginGroup(self.objectName())
        self.appSettings.setValue("model", model)
        super(ModelWidget, self).storeSession(model)
        self.appSettings.endGroup()
        self._statsWidget.storeSession()

    def restoreSession(self, model=None):
        """Load last known user settings from persistent app settings."""
        if self.appSettings is None:
            return
        if model is None:
            # get the last model used and select it
            self.appSettings.beginGroup(self.objectName())
            model = self.appSettings.value("model")
            self.appSettings.endGroup()
            # calls restoreSession(model) and storeSession()
            # mind the QSettings.group()
            if not isString(model):  # default model if none set
                model = "Sphere"
            self.selectModel(model)
        else:
            self.appSettings.beginGroup(self.objectName())
            super(ModelWidget, self).restoreSession(model)
            self.appSettings.endGroup()
            self._statsWidget.restoreSession()

    def _selectModelSlot(self, key=None):
        # get the model by its unique name in the items data field
        modelid = self.modelBox.itemData(key)
        if modelid not in self._models:
            return
        model, dummy = self._models[modelid]
        if model is None or not issubclass(model, ScatteringModel):
            return
        # store current settings before changing the model
        self.storeSession()
        self._calculator.model = model()  # instantiate the model class
        # remove parameter widgets from layout
        layout = self.modelWidget.layout()
        self.removeWidgets(self.modelWidget)
        # create new parameter widget based on current selection
        for p in self.model.params():
            try:
                widget = self.makeSetting(p, activeBtns=True)
                layout.addWidget(widget)
            except Exception as e:
                DisplayException(e,
                                 fmt=u"An error occurred on building a "
                                 "UI for parameter '{p}' in model '{m}'."
                                 "<p><nobr>{e}</nobr></p>"
                                 "Please see the log for a traceback.".format(
                                     p=p.name(), m=self.model.name(), e="{e}"))
                self.removeWidgets(self.modelWidget)
                self.modelBox.setCurrentIndex(0)
                return
        layout.addStretch()
        # restore user settings for this model
        self.restoreSession(self.model.name())

    def selectModel(self, model):
        """*model*: string containing the name of the model to select.
        Calls _selectModelSlot() via signal."""
        if not isString(model):
            return
        index = 0
        # search the model with the provided name
        for i in range(0, self.modelBox.count()):
            if self.modelBox.itemText(i).lower() == model.lower().strip():
                index = i
                break
        # set the index found or the first one otherwise
        self.modelBox.setCurrentIndex(index)

    @AlgorithmWidget.algorithm.getter
    def algorithm(self):
        if self._calculator is None:
            return None
        return self._calculator.model

    model = algorithm

    def setSphericalSizeRange(self, minVal, maxVal):
        key = "radius"
        # get parameter display order of magnitude:
        param = None
        for p in self.model.params():
            if key in p.name().lower():
                param = p
                break
        if param is None:
            logging.debug("No 'radius'-named parameter found, "
                          "not setting spherical size range!")
            return False  # nothing to do
        keymin, keymax = key + "min", key + "max"
        if self.get(keymin) is not None and self.get(keymax) is not None:
            self.set(keymin, param.toDisplay(minVal))
            self.set(keymax, param.toDisplay(maxVal))
            return True
        return False