示例#1
0
    def addExperiment(self):
        textLabel = QLabel('Experiment:')
        textLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        textLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        experimentLabel = QLabel('Unknown')
        experimentLabel.setSizePolicy(QSizePolicy.Expanding,
                                      QSizePolicy.Preferred)
        self.toolBarMain.addWidget(textLabel)
        self.toolBarMain.addWidget(experimentLabel)

        # if INSTRUMENT is defined add the logo/name of the instrument
        experiment = os.getenv('EXPERIMENT')
        if experiment:
            experimentLabel.setText(experiment)
示例#2
0
 def _squeeze(self, text=None):
     if text is None:
         text = self._fulltext or self.text()
     fm = self.fontMetrics()
     labelwidth = self.size().width()
     squeezed = False
     new_lines = []
     for line in text.split('\n'):
         if fm.width(line) > labelwidth:
             squeezed = True
             new_lines.append(fm.elidedText(line, Qt.ElideRight,
                                            labelwidth))
         else:
             new_lines.append(line)
     if squeezed:
         QLabel.setText(self, '\n'.join(map(text_type, new_lines)))
         self.setToolTip(self._fulltext)
     else:
         QLabel.setText(self, self._fulltext)
         self.setToolTip('')
示例#3
0
    def __init__(self, parent, client, options):
        CustomButtonPanel.__init__(self, parent, client, options)
        # our content is a simple widget ...
        self._tableWidget = TableWidget(self)

        self._tableWidget.setColumnCount(1)
        self._tableWidget.setHorizontalHeaderLabels(['Sample name'])
        self._tableWidget.horizontalHeaderItem(0).setTextAlignment(
            Qt.AlignLeft | Qt.AlignVCenter)
        self._tableWidget.setSortingEnabled(False)
        self._tableWidget.setCornerLabel('Position')

        self.vBoxLayout.insertWidget(0, self._tableWidget)

        client.connected.connect(self.on_client_connected)
        client.setup.connect(self.on_client_connected)

        image = options.get('image', None)
        # insert the optional image at top...
        if image:
            l = QLabel(self)
            l.setText(image)
            # insert above scrollArea
            self.vBoxLayout.insertWidget(0, l, alignment=Qt.AlignHCenter)
            p = QPixmap()
            if p.load(findResource(image)):
                l.setPixmap(p)
            else:
                msg = 'Loading of Image %r failed:' % image
                msg += '\n\nCheck GUI config file for %r' % __file__
                self.showError(msg)

        self._numSamples = int(options.get('positions', 11))
        self._tableWidget.setRowCount(self._numSamples)
        # fill in widgets into grid
        for pos in range(self._numSamples):
            self._tableWidget.setCellWidget(pos, 0, QLineEdit(''))

        self._tableWidget.horizontalHeader().setStretchLastSection(100)
        # now fill in data
        self._update_sample_info()
示例#4
0
    def addInstrument(self):
        textLabel = QLabel('Instrument:')
        textLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        textLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        instrumentLabel = QLabel('Unknown')
        instrumentLabel.setSizePolicy(QSizePolicy.Expanding,
                                      QSizePolicy.Preferred)
        self.toolBarMain.addWidget(textLabel)
        self.toolBarMain.addWidget(instrumentLabel)

        instrument = os.getenv('INSTRUMENT')
        if instrument:
            instrument = instrument.split('.')[-1]
            logo = decolor_logo(QPixmap('resources/%s-logo.svg' % instrument),
                                Qt.white)
            if logo.isNull():
                instrumentLabel.setText(instrument.upper())
                return
            instrumentLabel.setPixmap(
                logo.scaledToHeight(self.toolBarMain.height(),
                                    Qt.SmoothTransformation))
示例#5
0
文件: utils.py 项目: umithardal/nicos
 def viewTextFile(self, fname):
     with open(fname) as f:
         contents = f.read()
     qd = QDialog(self, 'PreviewDlg', True)
     qd.setCaption('File preview')
     qd.resize(QSize(500, 500))
     lay = QVBoxLayout(qd, 11, 6, 'playout')
     lb = QLabel(qd, 'label')
     lb.setText('Viewing %s:' % fname)
     lay.addWidget(lb)
     tx = QTextEdit(qd, 'preview')
     tx.setReadOnly(1)
     tx.setText(contents)
     font = QFont(tx.font())
     font.setFamily('monospace')
     tx.setFont(font)
     lay.addWidget(tx)
     btn = QPushButton(qd, 'ok')
     btn.setAutoDefault(1)
     btn.setDefault(1)
     btn.setText('Close')
     btn.clicked.connect(qd.accept)
     lay.addWidget(btn, 0, QWidget.AlignRight)
     qd.show()
示例#6
0
class MainWindow(DefaultMainWindow):
    ui = '%s/main.ui' % uipath

    def __init__(self, log, gui_conf, viewonly=False, tunnel=''):
        DefaultMainWindow.__init__(self, log, gui_conf, viewonly, tunnel)
        self.add_logo()
        self.set_icons()
        self.style_file = gui_conf.stylefile

        # Cheeseburger menu
        dropdown = QMenu('')
        dropdown.addAction(self.actionConnect)
        dropdown.addAction(self.actionViewOnly)
        dropdown.addAction(self.actionPreferences)
        dropdown.addAction(self.actionExpert)
        dropdown.addSeparator()
        dropdown.addAction(self.actionExit)
        self.actionUser.setMenu(dropdown)
        self.actionUser.setIconVisibleInMenu(True)
        self.dropdown = dropdown
        self.actionExpert.setEnabled(self.client.isconnected)
        self.actionEmergencyStop.setEnabled(self.client.isconnected)
        self._init_instrument_name()
        self._init_experiment_name()

    def _init_toolbar(self):
        self.statusLabel = QLabel('',
                                  self,
                                  pixmap=QPixmap(':/disconnected'),
                                  margin=5,
                                  minimumSize=QSize(30, 10))
        self.statusLabel.setStyleSheet('color: white')

        self.toolbar = self.toolBarRight
        self.toolbar.addWidget(self.statusLabel)
        self.setStatus('disconnected')

    def _init_experiment_name(self):
        self.experiment_text = QLabel()
        self.experiment_text.setSizePolicy(QSizePolicy.Expanding,
                                           QSizePolicy.Preferred)
        self.experiment_text.setStyleSheet(
            'font-size: 17pt; font-weight: bold')
        self.toolBarMain.addWidget(self.experiment_text)

        self.experiment_label = QLabel()
        self.experiment_label.setSizePolicy(QSizePolicy.Expanding,
                                            QSizePolicy.Preferred)
        self.experiment_label.setStyleSheet('font-size: 17pt')
        self.toolBarMain.addWidget(self.experiment_label)

    def _init_instrument_name(self):
        self.instrument_text = QLabel()
        self.instrument_text.setSizePolicy(QSizePolicy.Expanding,
                                           QSizePolicy.Preferred)
        self.instrument_text.setStyleSheet(
            'font-size: 17pt; font-weight: bold')
        self.toolBarMain.addWidget(self.instrument_text)

        self.instrument_label = QLabel()
        self.instrument_label.setSizePolicy(QSizePolicy.Expanding,
                                            QSizePolicy.Preferred)
        self.instrument_label.setStyleSheet('font-size: 17pt')
        self.toolBarMain.addWidget(self.instrument_label)

    def set_icons(self):
        self.actionUser.setIcon(get_icon('settings_applications-24px.svg'))
        self.actionEmergencyStop.setIcon(
            get_icon('emergency_stop_cross-24px.svg'))
        self.actionConnect.setIcon(get_icon('power-24px.svg'))
        self.actionExit.setIcon(get_icon('exit_to_app-24px.svg'))
        self.actionViewOnly.setIcon(get_icon('lock-24px.svg'))
        self.actionPreferences.setIcon(get_icon('tune-24px.svg'))
        self.actionExpert.setIcon(get_icon('fingerprint-24px.svg'))

    def add_logo(self):
        logo_label = QLabel()
        pxr = decolor_logo(
            QPixmap(path.join(root_path, 'resources', 'logo-icon.png')),
            Qt.white)
        logo_label.setPixmap(
            pxr.scaledToHeight(self.toolBarMain.height(),
                               Qt.SmoothTransformation))
        logo_label.setMargin(5)
        self.toolBarMain.insertWidget(self.toolBarMain.actions()[0],
                                      logo_label)

        nicos_label = QLabel()
        pxr = decolor_logo(
            QPixmap(path.join(root_path, 'resources', 'nicos-logo-high.svg')),
            Qt.white)
        nicos_label.setPixmap(
            pxr.scaledToHeight(self.toolBarMain.height(),
                               Qt.SmoothTransformation))
        self.toolBarMain.insertWidget(self.toolBarMain.actions()[1],
                                      nicos_label)

    def update_instrument_text(self):
        instrument = self.client.eval('session.instrument', None)
        self.instrument_text.setText('Instrument:')
        if instrument:
            logo = decolor_logo(
                QPixmap(
                    path.join(root_path, 'resources',
                              f'{instrument}-logo.svg')), Qt.white)
            if logo.isNull():
                self.instrument_label.setText(instrument.upper())
                return
            self.instrument_label.setPixmap(
                logo.scaledToHeight(self.toolBarMain.height(),
                                    Qt.SmoothTransformation))
        else:
            self.instrument_label.setText('UNKNOWN')

    def update_experiment_text(self):
        max_text_length = 50
        experiment = self.client.eval('session.experiment.title', None)
        if experiment is not None:
            self.experiment_text.setText("     Experiment:")
            self.experiment_label.setText(experiment[0:max_text_length])

    def remove_experiment_and_instrument(self):
        self.experiment_label.clear()
        self.experiment_text.clear()
        self.instrument_label.clear()
        self.instrument_text.clear()

    def reloadQSS(self):
        self.setQSS(self.stylefile)

    def selectQSS(self):
        style_file = QFileDialog.getOpenFileName(
            self, filter="Qt Stylesheet Files (*.qss)")[0]
        if style_file:
            self.style_file = style_file
            self.setQSS(self.style_file)

    @staticmethod
    def setQSS(style_file):
        with open(style_file, 'r', encoding='utf-8') as fd:
            try:
                QApplication.instance().setStyleSheet(fd.read())
            except Exception as e:
                print(e)

    def setStatus(self, status, exception=False):
        if status == self.current_status:
            return
        if self.client.last_action_at and \
           self.current_status == 'running' and \
           status in ('idle', 'paused') and \
           current_time() - self.client.last_action_at > 20:
            # show a visual indication of what happened
            if status == 'paused':
                msg = 'Script is now paused.'
            elif exception:
                msg = 'Script has exited with an error.'
            else:
                msg = 'Script has finished.'
            self.trayIcon.showMessage(self.instrument, msg)
            self.client.last_action_at = 0
        self.current_status = status
        is_connected = status != 'disconnected'
        if is_connected:
            self.actionConnect.setText('Disconnect')
            self.statusLabel.setText('\u2713 Connected')
            self.update_instrument_text()
            self.update_experiment_text()
        else:
            self.actionConnect.setText('Connect to server...')
            self.statusLabel.setText('Disconnected')
            self.setTitlebar(False)
        # new status icon
        pixmap = QPixmap(':/' + status + ('exc' if exception else ''))
        new_icon = QIcon()
        new_icon.addPixmap(pixmap, QIcon.Disabled)
        self.trayIcon.setIcon(new_icon)
        self.trayIcon.setToolTip('%s status: %s' % (self.instrument, status))
        if self.showtrayicon:
            self.trayIcon.show()
        if self.promptWindow and status != 'paused':
            self.promptWindow.close()
        # propagate to panels
        for panel in self.panels:
            panel.updateStatus(status, exception)
        for window in self.windows.values():
            for panel in window.panels:
                panel.updateStatus(status, exception)

    def on_client_connected(self):
        DefaultMainWindow.on_client_connected(self)
        self.actionConnect.setIcon(get_icon("power_off-24px.svg"))
        self.actionExpert.setEnabled(True)
        self.actionEmergencyStop.setEnabled(not self.client.viewonly)

    def on_client_disconnected(self):
        DefaultMainWindow.on_client_disconnected(self)
        self.remove_experiment_and_instrument()
        self.actionConnect.setIcon(get_icon("power-24px.svg"))
        self.actionExpert.setEnabled(False)
        self.actionExpert.setChecked(False)
        self.actionEmergencyStop.setEnabled(False)

    def on_actionViewOnly_toggled(self, on):
        DefaultMainWindow.on_actionViewOnly_toggled(self, on)
        if self.client.isconnected:
            self.actionEmergencyStop.setEnabled(not self.client.viewonly)
        else:
            self.actionEmergencyStop.setEnabled(False)

    @pyqtSlot(bool)
    def on_actionConnect_triggered(self, _):
        # connection or disconnection request?
        connection_req = self.current_status == "disconnected"
        super().on_actionConnect_triggered(connection_req)

    @pyqtSlot()
    def on_actionUser_triggered(self):
        w = self.toolBarRight.widgetForAction(self.actionUser)
        self.dropdown.popup(w.mapToGlobal(QPoint(0, w.height())))

    @pyqtSlot()
    def on_actionEmergencyStop_triggered(self):
        self.client.tell_action('emergency')
示例#7
0
文件: display.py 项目: ess-dmsc/nicos
class PictureDisplay(NicosWidget, QWidget):
    """A display widget to show a picture."""

    designer_description = 'Widget to display a picture file'

    filepath = PropDef('filepath', str, '', 'Path to the picture that should '
                       'be displayed')
    name = PropDef('name', str, '', 'Name (caption) to be displayed above '
                   'the picture')
    refresh = PropDef('refresh', int, 0, 'Interval to check for updates '
                      'in seconds')
    height = PropDef('height', int, 0)
    width = PropDef('width', int, 0)

    def __init__(self, parent=None, designMode=False, **kwds):
        QWidget.__init__(self, parent, **kwds)
        NicosWidget.__init__(self)
        self._last_mtime = None
        self.namelabel = QLabel(self)
        self.namelabel.setAlignment(Qt.AlignHCenter)
        self.piclabel = QLabel(self)
        self.piclabel.setScaledContents(True)
        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self.piclabel, 1)
        self.setLayout(layout)

    def registerKeys(self):
        pass

    def setPicture(self):
        size = QSize(self.props['width'] * self._scale,
                     self.props['height'] * self._scale)
        if isfile(self._filePath):
            pixmap = QPixmap(self._filePath)
        else:
            pixmap = QPixmap(size)
            pixmap.fill()
        if size.isEmpty():
            self.piclabel.setPixmap(pixmap)
        else:
            self.piclabel.setPixmap(pixmap.scaled(size))
            self.piclabel.resize(self.piclabel.sizeHint())

    def updatePicture(self):
        if not isfile(self._filePath):
            return

        # on first iteration self._last_mtime is None -> always setPicture()
        mtime = getmtime(self._filePath)
        if self._last_mtime != mtime:
            self._last_mtime = mtime
            self.setPicture()

    def propertyUpdated(self, pname, value):
        NicosWidget.propertyUpdated(self, pname, value)
        if pname == 'filepath':
            self._filePath = findResource(value)
            self.setPicture()
        elif pname == 'name':
            layout = QVBoxLayout()
            if value:
                layout.addWidget(self.namelabel)
                layout.addSpacing(5)
            layout.addWidget(self.piclabel, 1)
            sip.delete(self.layout())
            self.setLayout(layout)
            self.namelabel.setText(value)
        elif pname in ('width', 'height'):
            self.setPicture()
        elif pname == 'refresh':
            if value:
                self._refreshTimer = QTimer()
                self._refreshTimer.setInterval(value * 1000)
                self._refreshTimer.timeout.connect(self.updatePicture)
                self._refreshTimer.start()
示例#8
0
文件: display.py 项目: ess-dmsc/nicos
class ValueDisplay(NicosWidget, QWidget):
    """Value display widget with two labels."""

    designer_description = 'A widget with name/value labels'
    designer_icon = ':/table'

    widgetInfo = pyqtSignal(str)

    dev = PropDef('dev', str, '', 'NICOS device name, if set, display '
                  'value of this device')
    key = PropDef('key', str, '', 'Cache key to display (without "nicos/"'
                  ' prefix), set either "dev" or this')
    statuskey = PropDef('statuskey', str, '', 'Cache key to extract status '
                        'information  for coloring value, if "dev" is '
                        'given this is set automatically')
    name = PropDef('name', str, '', 'Name of the value to display above/'
                   'left of the value; if "dev" is given this '
                   'defaults to the device name')
    unit = PropDef('unit', str, '', 'Unit of the value to display next to '
                   'the name; if "dev" is given this defaults to '
                   'the unit set in NICOS')
    format = PropDef('format', str, '', 'Python format string to use for the '
                     'value; if "dev" is given this defaults to the '
                     '"fmtstr" set in NICOS')
    maxlen = PropDef('maxlen', int, -1, 'Maximum length of the value string to '
                     'allow; defaults to no limit')
    width = PropDef('width', int, 8, 'Width of the widget in units of the '
                    'width of one character')
    istext = PropDef('istext', bool, False, 'If given, a "text" font will be '
                     'used for the value instead of the monospaced '
                     'font used for numeric values')
    showName = PropDef('showName', bool, True, 'If false, do not display the '
                       'label for the value name')
    showStatus = PropDef('showStatus', bool, True, 'If false, do not display '
                         'the device status as a color of the value text')
    showExpiration = PropDef('showExpiration', bool, True, 'If true, display '
                             'expired cache values as "n/a"')
    horizontal = PropDef('horizontal', bool, False, 'If true, display name '
                         'label left of the value instead of above it')

    def __init__(self, parent, designMode=False, colorScheme=None, **kwds):
        # keys being watched
        self._mainkeyid = None
        self._statuskeyid = None

        # other current values
        self._isfixed = ''
        # XXX could be taken from devinfo
        self._lastvalue = designMode and '1.4' or None
        self._laststatus = (OK, '')
        self._lastchange = 0
        self._mouseover = False
        self._mousetimer = None
        self._expired = True

        self._colorscheme = colorScheme or defaultColorScheme

        QWidget.__init__(self, parent, **kwds)
        NicosWidget.__init__(self)
        self._statuscolors = self._colorscheme['fore'][UNKNOWN], \
            self._colorscheme['back'][UNKNOWN]
        self._labelcolor = None

    def propertyUpdated(self, pname, value):
        if pname == 'dev':
            if value:
                self.key = value + '.value'
                self.statuskey = value + '.status'
        elif pname == 'width':
            if value < 0:
                self.reinitLayout()
            else:
                onechar = QFontMetrics(self.valueFont).width('0')
                self.valuelabel.setMinimumSize(QSize(onechar * (value + .5), 0))
        elif pname == 'istext':
            self.valuelabel.setFont(value and self.font() or self.valueFont)
            self.width = self.width
        elif pname == 'valueFont':
            self.valuelabel.setFont(self.valueFont)
            self.width = self.width  # update char width calculation
        elif pname == 'showName':
            self.namelabel.setVisible(value)
        elif pname == 'showStatus':
            if not value:
                setBothColors(self.valuelabel,
                              (self._colorscheme['fore'][UNKNOWN],
                               self._colorscheme['back'][UNKNOWN]))
        elif pname == 'horizontal':
            self.reinitLayout()
        if pname in ('dev', 'name', 'unit'):
            self.update_namelabel()
        NicosWidget.propertyUpdated(self, pname, value)

    def initUi(self):
        self.namelabel = QLabel(' ', self, textFormat=Qt.RichText)
        self.update_namelabel()

        valuelabel = SensitiveSMLabel('----', self, self._label_entered,
                                      self._label_left)
        valuelabel.setFrameShape(QFrame.Panel)
        valuelabel.setAlignment(Qt.AlignHCenter)
        valuelabel.setFrameShadow(QFrame.Sunken)
        valuelabel.setAutoFillBackground(True)
        setBothColors(valuelabel, (self._colorscheme['fore'][UNKNOWN],
                                   self._colorscheme['back'][UNKNOWN]))
        valuelabel.setLineWidth(2)
        self.valuelabel = valuelabel
        self.width = 8

        self.reinitLayout()

    def reinitLayout(self):
        # reinitialize UI after switching horizontal/vertical layout
        if self.props['horizontal']:
            new_layout = QHBoxLayout()
            new_layout.addWidget(self.namelabel)
            new_layout.addStretch()
            new_layout.addWidget(self.valuelabel)
            self.namelabel.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
        else:
            new_layout = QVBoxLayout()
            new_layout.addWidget(self.namelabel)
            tmplayout = QHBoxLayout()
            if self.width >= 0:
                tmplayout.addStretch()
            tmplayout.addWidget(self.valuelabel)
            if self.width >= 0:
                tmplayout.addStretch()
            new_layout.addLayout(tmplayout)
            self.namelabel.setAlignment(Qt.AlignHCenter)
        if self.layout():
            sip.delete(self.layout())
        new_layout.setContentsMargins(1, 1, 1, 1)  # save space
        self.setLayout(new_layout)

    def registerKeys(self):
        if self.props['dev']:
            self.registerDevice(self.props['dev'],
                                self.props['unit'], self.props['format'])
        else:
            self.registerKey(self.props['key'], self.props['statuskey'],
                             self.props['unit'], self.props['format'])

    def on_devValueChange(self, dev, value, strvalue, unitvalue, expired):
        # check expired values
        self._expired = expired
        self._lastvalue = value
        self._lastchange = currenttime()
        if self.props['maxlen'] > -1:
            self.valuelabel.setText(strvalue[:self.props['maxlen']])
        else:
            self.valuelabel.setText(strvalue)
        if self._expired:
            setBothColors(self.valuelabel, (self._colorscheme['fore'][UNKNOWN],
                                            self._colorscheme['expired']))
            if self.props['showExpiration']:
                self.valuelabel.setText(NOT_AVAILABLE)
        elif not self.props['istext']:
            setBothColors(self.valuelabel, (self._colorscheme['fore'][BUSY],
                                            self._colorscheme['back'][BUSY]))
            QTimer.singleShot(1000, self._applystatuscolor)
        else:
            self._applystatuscolor()

    def _applystatuscolor(self):
        if self._expired:
            setBothColors(self.valuelabel, (self._colorscheme['fore'][UNKNOWN],
                                            self._colorscheme['expired']))
        else:
            setBothColors(self.valuelabel, self._statuscolors)
            if self._labelcolor:
                self.namelabel.setAutoFillBackground(True)
                setBackgroundColor(self.namelabel, self._labelcolor)
            else:
                self.namelabel.setAutoFillBackground(False)

    def on_devStatusChange(self, dev, code, status, expired):
        if self.props['showStatus']:
            self._statuscolors = self._colorscheme['fore'][code], \
                self._colorscheme['back'][code]
            self._labelcolor = self._colorscheme['label'][code]
            self._laststatus = code, status
            self._applystatuscolor()

    def on_devMetaChange(self, dev, fmtstr, unit, fixed):
        self._isfixed = fixed and ' (F)'
        self.format = fmtstr
        self.unit = unit or ''

    def update_namelabel(self):
        name = self.props['name'] or self.props['dev'] or self.props['key']
        self.namelabel.setText(
            html.escape(str(name)) +
            ' <font color="#888888">%s</font><font color="#0000ff">%s</font> '
            % (html.escape(self.props['unit'].strip()), self._isfixed))

    def _label_entered(self, widget, event, from_mouse=True):
        infotext = '%s = %s' % (self.props['name'] or self.props['dev']
                                or self.props['key'], self.valuelabel.text())
        if self.props['unit'].strip():
            infotext += ' %s' % self.props['unit']
        if self.props['statuskey']:
            try:
                const, msg = self._laststatus
            except ValueError:
                const, msg = self._laststatus, ''
            infotext += ', status is %s: %s' % (statuses.get(const, '?'), msg)
        infotext += ', changed %s ago' % (
            nicedelta(currenttime() - self._lastchange))
        self.widgetInfo.emit(infotext)
        if from_mouse:
            self._mousetimer = QTimer(self, timeout=lambda:
                                      self._label_entered(widget, event, False)
                                      )
            self._mousetimer.start(1000)

    def _label_left(self, widget, event):
        if self._mousetimer:
            self._mousetimer.stop()
            self._mousetimer = None
            self.widgetInfo.emit('')
示例#9
0
class ToftofProfileWindow(DlgUtils, QMainWindow):
    def __init__(self, parent):
        QMainWindow.__init__(self, parent)
        DlgUtils.__init__(self, 'Live data')
        self.panel = parent
        layout1 = QVBoxLayout()
        self.plot = QwtPlot(self)
        layout1.addWidget(self.plot)
        self.curve = QwtPlotCurve()
        self.curve.setRenderHint(QwtPlotCurve.RenderAntialiased)
        self.curve.attach(self.plot)
        self.marker = QwtPlotMarker()
        self.marker.attach(self.plot)
        self.markerpen = QPen(Qt.red)
        self.marker.setSymbol(
            QwtSymbol(QwtSymbol.Ellipse, QBrush(), self.markerpen, QSize(7,
                                                                         7)))
        self.zoomer = QwtPlotZoomer(self.plot.canvas())
        self.zoomer.setMousePattern(QwtPlotZoomer.MouseSelect3, Qt.NoButton)
        self.picker = QwtPlotPicker(self.plot.canvas())
        self.picker.setSelectionFlags(QwtPlotPicker.PointSelection
                                      | QwtPlotPicker.ClickSelection)
        self.picker.setMousePattern(QwtPlotPicker.MouseSelect1, Qt.MidButton)
        self.picker.selected.connect(self.pickerSelected)
        layout2 = QHBoxLayout()
        layout2.addWidget(QLabel('Scale:', self))
        self.scale = QComboBox(self)
        self.scale.addItems([
            'Single detectors, sorted by angle',
            'Scattering angle 2theta (deg)', 'Q value (A-1)'
        ])
        self.scale.currentIndexChanged[int].connect(self.scaleChanged)
        layout2.addWidget(self.scale)
        layout2.addStretch()
        self.scaleframe = QFrame(self)
        self.scaleframe.setLayout(layout2)
        self.scaleframe.setVisible(False)
        layout1.addWidget(self.scaleframe)
        mainframe = QFrame(self)
        mainframe.setLayout(layout1)
        self.setCentralWidget(mainframe)
        self.setContentsMargins(6, 6, 6, 6)
        plotfont = scaledFont(self.font(), 0.7)
        self.plot.setAxisFont(QwtPlot.xBottom, plotfont)
        self.plot.setAxisFont(QwtPlot.yLeft, plotfont)
        self.plot.setCanvasBackground(Qt.white)
        self.resize(800, 200)

        self._detinfo = None
        self._anglemap = None
        self._infowindow = None
        self._infolabel = None
        self._xs = self._ys = None
        self._type = None

    def _retrieve_detinfo(self):
        if self._detinfo is None:
            info = self.panel.client.eval(
                'det._detinfo_parsed, '
                'det._anglemap', None)
            if not info:
                return self.showError('Cannot retrieve detector info.')
            self._lambda = self.panel.client.eval('chWL()', None)
            if not self._lambda:
                return self.showError('Cannot retrieve wavelength.')
            self._detinfo, self._anglemap = info
            self._inverse_anglemap = 0
            self._infowindow = QMainWindow(self)
            self._infolabel = QLabel(self._infowindow)
            self._infolabel.setTextFormat(Qt.RichText)
            self._infowindow.setCentralWidget(self._infolabel)
            self._infowindow.setContentsMargins(10, 10, 10, 10)
            self._inv_anglemap = [[
                entry for entry in self._detinfo[1:]
                if entry[12] == self._anglemap[detnr] + 1
            ][0] for detnr in range(len(self._xs))]

    def scaleChanged(self, scale):
        self.update(self._type, self._orig_nbins, self._orig_x, self._orig_y)

    def update(self, proftype, nbins, x, y):
        self._orig_x = x
        self._orig_y = y
        self._orig_nbins = nbins
        x.setsize(8 * nbins)
        y.setsize(8 * nbins)
        xs = struct.unpack('d' * nbins, x)
        ys = struct.unpack('d' * nbins, y)
        if proftype == 0:
            if self.scale.currentIndex() == 0:
                xs = xs
            elif self.scale.currentIndex() == 1:
                self._retrieve_detinfo()
                xs = [self._inv_anglemap[int(xi)][5] for xi in xs]
            else:
                self._retrieve_detinfo()
                if self._lambda is None:
                    self.showError('Could not determine wavelength.')
                    self.scale.setCurrentIndex(1)
                    return
                xs = [
                    4 * pi / self._lambda *
                    sin(radians(self._inv_anglemap[int(xi)][5] / 2.))
                    for xi in xs
                ]
        self._xs = xs
        self._ys = ys
        self.curve.setData(xs, ys)
        self.plot.setAxisAutoScale(QwtPlot.xBottom)
        self.plot.setAxisAutoScale(QwtPlot.yLeft)
        self.marker.setVisible(False)
        self.zoomer.setZoomBase(True)
        self._type = proftype
        if proftype == 0:
            self.setWindowTitle(
                'Single detector view (time-channel integrated)')
            self.scaleframe.setVisible(True)
        elif proftype == 1:
            self.setWindowTitle('Time channel view (detector integrated)')
            self.scaleframe.setVisible(False)
        else:
            self.scaleframe.setVisible(False)

    def pickerSelected(self, point):
        if self._type != 0:
            return
        self._retrieve_detinfo()
        index = self.curve.closestPoint(self.picker.transform(point))[0]
        detentry = self._inv_anglemap[index][:]
        detentry.append(self._xs[index])
        detentry.append(self._ys[index])
        self.marker.setXValue(self._xs[index])
        self.marker.setYValue(self._ys[index])
        self.marker.setVisible(True)
        self.plot.replot()
        self._infowindow.show()
        entrynames = [
            'EntryNr', 'Rack', 'Plate', 'Pos', 'RPos', '2Theta', 'CableNr',
            'CableType', 'CableLen', 'CableEmpty', 'Card', 'Chan', 'Total',
            'DetName', 'BoxNr', 'BoxChan', 'XValue', 'Counts'
        ]
        formats = [
            '%s', '%d', '%d', '%d', '%d', '%.3f', '%d', '%d', '%.2f', '%d',
            '%d', '%d', '%d', '%r', '%d', '%d', '%s', '%d'
        ]
        empties = [1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0]
        self._infolabel.setText('Detector info:<br><table>' + ''.join(
            '<tr><td>%s</td><td></td><td>%s</td></tr>%s' %
            (name, format % value, '<tr></tr>' if empty else '')
            for (name, format, empty,
                 value) in zip(entrynames, formats, empties, detentry)) +
                                '</table>')

    def closeEvent(self, event):
        if self._infowindow:
            self._infowindow.close()
示例#10
0
文件: qt.py 项目: ess-dmsc/nicos
class Monitor(BaseMonitor):
    """Qt specific implementation of instrument monitor."""

    parameters = {
        'noexpired': Param('If true, show expired values as "n/a"', type=bool)
    }

    _master = None

    def mainLoop(self):
        self._qtapp.exec_()

    def closeGui(self):
        if self._master:
            self._master.close()

    def _class_import(self, clsname):
        modname, member = clsname.rsplit('.', 1)
        mod = __import__(modname, None, None, [member])
        return getattr(mod, member)

    # pylint: disable=too-many-statements
    def initGui(self):
        def log_unhandled(*exc_info):
            traceback.print_exception(*exc_info)
            self.log.exception('unhandled exception in QT callback',
                               exc_info=exc_info)
        sys.excepthook = log_unhandled

        self._qtapp = QApplication(['qtapp'], organizationName='nicos',
                                   applicationName='gui')
        self._master = master = MonitorWindow()

        if self._geometry == 'fullscreen':
            master.showFullScreen()
            master._wantFullScreen = True
            # In some Qt5 versions, showFullScreen is buggy and doesn't
            # actually resize the window (but hides decoration etc).
            # So, explicitly set the geometry of the first screen.
            master.setGeometry(QApplication.screens()[0].geometry())
            QCursor.setPos(master.geometry().bottomRight())
        elif isinstance(self._geometry, tuple):
            w, h, x, y = self._geometry
            master.setGeometry(x, y, w, h)

        # colors used for the display of watchdog warnings, not for the
        # individual value displays
        self._bgcolor = QColor('gray')
        self._black = QColor('black')
        self._red = QColor('red')
        self._gray = QColor('gray')

        master.setWindowTitle(self.title)
        self._bgcolor = master.palette().color(QPalette.Window)

        timefont  = QFont(self.font, self._timefontsize)
        blockfont = QFont(self.font, self._fontsizebig)
        warnfont  = QFont(self.font, self._fontsizebig)
        warnfont.setBold(True)
        labelfont = QFont(self.font, self._fontsize)
        stbarfont = QFont(self.font, int(self._fontsize * 0.8))
        valuefont = QFont(self.valuefont or self.font, self._fontsize)

        blheight = QFontMetrics(blockfont).height()
        tiheight = QFontMetrics(timefont).height()

        # split window into to panels/frames below each other:
        # one displays time, the other is divided further to display blocks.
        # first the timeframe:
        masterframe = QFrame(master)
        masterlayout = QVBoxLayout()
        if self.title:
            self._titlelabel = QLabel(
                '', master, font=timefont, autoFillBackground=True,
                alignment=Qt.AlignHCenter)
            pal = self._titlelabel.palette()
            pal.setColor(QPalette.WindowText, self._gray)
            self._titlelabel.setPalette(pal)
            self._titlelabel.setSizePolicy(QSizePolicy.Preferred,
                                           QSizePolicy.Fixed)
            self._master.updateTitle.connect(self._titlelabel.setText)
            masterlayout.addWidget(self._titlelabel)
            masterlayout.addSpacing(0.2 * tiheight)
        else:
            self._titlelabel = None

        self._warnpanel = QFrame(master)
        self._warnpanel.setVisible(False)

        warningslayout = QVBoxLayout()
        lbl = QLabel('Warnings', self._warnpanel, font=warnfont)
        lbl.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
        warningslayout.addWidget(lbl)
        self._warnlabel = SqueezedLabel('', self._warnpanel, font=blockfont)
        warningslayout.addWidget(self._warnlabel)
        self._warnpanel.setLayout(warningslayout)
        masterlayout.addWidget(self._warnpanel)
        master.switchWarnPanel.connect(self._switch_warnpanel)

        displayframe = QFrame(master)
        self._plots = {}

        colorScheme = lightColorScheme if self.colors == 'light' else None
        fontCache = {1.0: valuefont}

        def _create_field(groupframe, field):

            def _setup(widget):
                fontscale = field.get('fontscale', 1.0)
                if fontscale not in fontCache:
                    fontCache[fontscale] = scaledFont(valuefont, fontscale)
                widget.valueFont = fontCache[fontscale]
                widget.setFont(labelfont)
                for key in field:
                    if key in widget.properties:
                        setattr(widget, key, field[key])
                widget.setSource(self)
                if hasattr(widget, 'widgetInfo'):
                    widget.widgetInfo.connect(self.newWidgetInfo)
                return widget

            if isinstance(field, str):
                field = {'dev': field}
            if 'min' in field:
                field['min'] = repr(field['min'])
            if 'max' in field:
                field['max'] = repr(field['max'])
            setups = field.get('setups', None)

            if 'gui' in field:
                resource = findResource(field.pop('gui'))
                try:
                    instance = uic.loadUi(resource)
                except Exception as err:
                    self.log.exception('could not load .ui file %r, ignoring',
                                       resource)
                    instance = QLabel('%r could not be loaded:\n%s' %
                                      (resource, err))
                else:
                    for child in instance.findChildren(NicosWidget):
                        _setup(child)
                instance.setups = setups
                return instance
            elif 'widget' in field:
                widget_class = self._class_import(field.pop('widget'))
                widget = widget_class(groupframe)
                if isinstance(widget, NicosWidget):
                    _setup(widget)
                for child in widget.findChildren(NicosWidget):
                    _setup(child)
                widget.setups = setups
                return widget
            elif 'plot' in field and plot_available:
                # XXX make this more standard
                plotwidget = self._plots.get(field['plot'])
                if plotwidget:
                    plotwidget.devices += [field.get('dev', field.get('key', ''))]
                    plotwidget.names += [field.get('name', field.get('dev', field.get('key', '')))]
                    return None
                plotwidget = TrendPlot(groupframe)
                _setup(plotwidget)
                plotwidget.legend = field.get('legend', True)
                plotwidget.plotwindow = field.get('plotwindow', 3600)
                plotwidget.plotinterval = field.get('plotinterval', 2)
                self._plots[field['plot']] = plotwidget
                plotwidget.devices = [field.get('dev', field.get('key', ''))]
                plotwidget.names = [field.get('name', field.get('dev', field.get('key', '')))]
                plotwidget.setups = setups
                return plotwidget
            elif 'picture' in field:
                picwidget = PictureDisplay(groupframe)
                picwidget.filepath = field['picture']
                picwidget.setups = setups
                return _setup(picwidget)
            else:
                display = ValueDisplay(groupframe, colorScheme=colorScheme,
                                       showExpiration=self.noexpired)
                display.setups = setups
                return _setup(display)

        # now iterate through the layout and create the widgets to display it
        displaylayout = QVBoxLayout(spacing=20)
        for superrow in self.layout:
            boxlayout = QHBoxLayout(spacing=20)
            boxlayout.setContentsMargins(10, 10, 10, 10)
            for column in superrow:
                columnlayout = QVBoxLayout(spacing=0.8*blheight)
                for block in column:
                    block = self._resolve_block(block)
                    blocklayout_outer = QHBoxLayout()
                    blocklayout_outer.addStretch()
                    blocklayout = QVBoxLayout()
                    blocklayout.addSpacing(0.5 * blheight)
                    blockbox = BlockBox(displayframe, block._title, blockfont,
                                        block._options)
                    for row in block:
                        if row in (None, '---'):
                            blocklayout.addSpacing(12)
                        else:
                            rowlayout = QHBoxLayout()
                            rowlayout.addStretch()
                            rowlayout.addSpacing(self._padding)
                            for field in row:
                                fieldwidget = _create_field(blockbox, field)
                                if fieldwidget:
                                    rowlayout.addWidget(fieldwidget)
                                    rowlayout.addSpacing(self._padding)
                                    if fieldwidget.setups:
                                        if blockbox.setups:
                                            blockbox._onlyfields.append(fieldwidget)
                                        else:
                                            self._onlyfields.append(fieldwidget)
                                            # start hidden
                                            fieldwidget.setHidden(True)
                            rowlayout.addStretch()
                            blocklayout.addLayout(rowlayout)
                    if blockbox.setups:
                        self._onlyblocks.append((blocklayout_outer, blockbox))
                        blockbox.setHidden(True)  # start hidden
                    blocklayout.addSpacing(0.3 * blheight)
                    blockbox.setLayout(blocklayout)
                    blocklayout_outer.addWidget(blockbox)
                    blocklayout_outer.addStretch()
                    columnlayout.addLayout(blocklayout_outer)
                columnlayout.addStretch()
                boxlayout.addLayout(columnlayout)
            displaylayout.addLayout(boxlayout)
        displayframe.setLayout(displaylayout)

        for plot in self._plots.values():
            plot.setSource(self)

        masterlayout.addWidget(displayframe)

        masterframe.setLayout(masterlayout)
        master.setCentralWidget(masterframe)

        # initialize status bar
        self._statuslabel = QLabel(font=stbarfont)
        master.statusBar().addWidget(self._statuslabel)
        self._statustimer = None
        master.show()

    def signalKeyChange(self, obj, *args):
        self._master.keyChange.emit(obj, args)

    def newWidgetInfo(self, info):
        self._statuslabel.setText(info)

    def updateTitle(self, title):
        self._master.updateTitle.emit(title)

    def switchWarnPanel(self, on):
        self._master.switchWarnPanel.emit(on)

    def _switch_warnpanel(self, on):
        if on:
            if self._titlelabel:
                pal = self._titlelabel.palette()
                pal.setColor(QPalette.WindowText, self._black)
                pal.setColor(QPalette.Window, self._red)
                self._titlelabel.setPalette(pal)
            self._warnlabel.setText(self._currwarnings)
            self._warnpanel.setVisible(True)
            self._master.update()
        else:
            self._warnpanel.setVisible(False)
            if self._titlelabel:
                pal = self._titlelabel.palette()
                pal.setColor(QPalette.WindowText, self._gray)
                pal.setColor(QPalette.Window, self._bgcolor)
                self._titlelabel.setPalette(pal)
            # resize to minimum
            self.reconfigureBoxes()
            # self._master.update()

    def reconfigureBoxes(self):
        emitdict = {}
        fields = []
        for (layout, box) in self._onlyblocks:
            emitdict[layout, box] = checkSetupSpec(box.setups, self._setups,
                                                   log=self.log)
            # check fields inside the block, if the block isn't invisible
            if emitdict[layout, box]:
                fields.extend(box._onlyfields)
        # always check fields not in a setup controlled group
        fields.extend(self._onlyfields)
        for field in fields:
            emitdict[None, field] = checkSetupSpec(field.setups, self._setups,
                                                   log=self.log)
        self._master.reconfigure.emit(emitdict)