Source code for taurus.qt.qtgui.input.qwheel

#!/usr/bin/env python

#############################################################################
##
# This file is part of Taurus
##
# http://taurus-scada.org
##
# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
##
# Taurus is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
##
# Taurus is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
##
# You should have received a copy of the GNU Lesser General Public License
# along with Taurus.  If not, see <http://www.gnu.org/licenses/>.
##
#############################################################################

"""This module provides an arrow based widget."""

from builtins import map
from builtins import range

import os
import math
import numpy

from taurus.external.qt import Qt
from taurus.core.units import Q_


__all__ = ["QWheelEdit"]

__docformat__ = 'restructuredtext'


class _ArrowButton(Qt.QPushButton):
    """Private class to be used by QWheelEdit for an arrow button"""

    ArrowPixmapName = "extra_icons:arrow01.svg"

    ButtonSize = 14
    IconSize = ButtonSize - 2

    def __init__(self, id, parent=None):
        Qt.QPushButton.__init__(self, parent)
        self.setAutoDefault(False)
        pixmap = self.getPixmap()
        self.setIcon(Qt.QIcon(pixmap))
        self.setIconSize(
            Qt.QSize(_ArrowButton.IconSize, _ArrowButton.IconSize))
        self.setFocusPolicy(Qt.Qt.ClickFocus)
        self.setFlat(True)
        self.setStyleSheet('_ArrowButton { border: 0px; }')
        self.setMaximumSize(_ArrowButton.ButtonSize, _ArrowButton.ButtonSize)
        #self.setMinimumSize(_ArrowButton.ButtonSize, _ArrowButton.ButtonSize)
        self._id = id
        self._inc = math.pow(10, id)


class _UpArrowButton(_ArrowButton):
    """Private class to be used by QWheelEdit for an up arrow button"""

    ArrowPixmapKey = "upArrow01"

    def __init__(self, id, parent=None):
        _ArrowButton.__init__(self, id, parent)

    def getPixmap(self):
        pm = Qt.QPixmapCache.find(_UpArrowButton.ArrowPixmapKey)
        if pm is None:
            pm = Qt.QPixmap(self.ArrowPixmapName)
            Qt.QPixmapCache.insert(_UpArrowButton.ArrowPixmapKey, pm)
        return pm


class _DownArrowButton(_ArrowButton):
    """Private class to be used by QWheelEdit for a down arrow button"""

    ArrowPixmapKey = "downArrow01"

    def __init__(self, id, parent=None):
        _ArrowButton.__init__(self, id, parent)
        self._inc = -self._inc

    def getPixmap(self):
        pm = Qt.QPixmapCache.find(_DownArrowButton.ArrowPixmapKey)
        if pm is None:
            pm = Qt.QPixmap(self.ArrowPixmapName)
            pm = pm.transformed(Qt.QTransform().rotate(180))
            Qt.QPixmapCache.insert(_DownArrowButton.ArrowPixmapKey, pm)
        return pm

class _DigitLabel(Qt.QLabel):
    """A private single digit label to be used by QWheelEdit widget"""

    PixmapKeys = list(map(str, range(10))) + ['blank', 'minus', 'point']

    def __init__(self, lbl, parent=None):
        Qt.QLabel.__init__(self, parent)
        self.setAlignment(Qt.Qt.AlignCenter)
        self.setFocusPolicy(Qt.Qt.StrongFocus)
        self.setStyleSheet(
            """QLabel:focus {background-color: rgb(180,180,255); border-width: 1px; border-style: solid; border-color: rgb(200,200,255);}""")
        self.resetSkin()
        self.setText(lbl)
        self._upButton = None
        self._downButton = None

    def setButtons(self, up, down):
        self._upButton = up
        self._downButton = down

    def keyPressEvent(self, key_event):
        if key_event.key() == Qt.Qt.Key_Up:
            self._upButton.click()
        elif key_event.key() == Qt.Qt.Key_Down:
            self._downButton.click()
        elif key_event.key() == Qt.Qt.Key_Right:
            self.focusNextChild()
        elif key_event.key() == Qt.Qt.Key_Left:
            self.focusPreviousChild()
        Qt.QLabel.keyPressEvent(self, key_event)

    def _update_skin_cache(self):
        skin = os.path.join('digits', self.getSkin())

        for i, d in enumerate(self.PixmapKeys):
            full_name = os.path.join(skin, d)
            pm = Qt.QPixmapCache.find(full_name)
            if pm is None:
                file_name = '%s.png' % full_name
                pm = Qt.QPixmap(file_name)
                if pm is None:
                    continue
                if not pm.isNull():
                    Qt.QPixmapCache.insert(full_name, pm)

    def setSkin(self, skin_name):
        self._skin = skin_name
        self._update_skin_cache()
        self.update()

    def getSkin(self):
        return self._skin

    def resetSkin(self):
        self.setSkin('Nixie')

    def setText(self, t):
        k = t
        if k == '.':
            k = 'point'
        elif k == '-':
            k = 'minus'
        elif k is None or k == '+':
            k = 'blank'

        k = os.path.join('digits', self.getSkin(), k)
        pm = Qt.QPixmapCache.find(k)
        if pm is None:
            Qt.QLabel.setText(self, t)
            return
        Qt.QLabel.setText(self, '')
        self.setPixmap(pm)

    skin = Qt.pyqtProperty('QString', getSkin, setSkin, resetSkin)


class _NumericEditor(Qt.QLineEdit):
    """A private editor to be used by QWheelEdit widget"""

    def __init__(self, parent=None):
        Qt.QLineEdit.__init__(self, parent)
        self.setValidator(Qt.QDoubleValidator(self))
        self.setFrame(False)


[docs]class QWheelEdit(Qt.QFrame): """A widget designed to handle numeric scalar values. It allows interaction based on single digit as well as normal value edition.""" numberChanged = Qt.pyqtSignal(float) numberEdited = Qt.pyqtSignal(float) returnPressed = Qt.pyqtSignal() DefaultIntDigitCount = 6 DefaultDecDigitCount = 2 def __init__(self, parent=None): """__init__(self, parent = None) -> QWheelEdit Constructor @param[in] parent (QWidget) the parent widget (optional, default is None meaning there is no parent """ Qt.QFrame.__init__(self, parent) Qt.QGridLayout(self) self._roundFunc = None self._previous_value = 0 self._value = 0 self._value_str = '0' self._minValue = numpy.finfo('d').min # -inf self._maxValue = numpy.finfo('d').max # inf self._editor = None self._editing = False self._showArrowButtons = True self._setDigits(QWheelEdit.DefaultIntDigitCount, QWheelEdit.DefaultDecDigitCount) self._setValue(0) self._build() def _getMinPossibleValue(self): """_getMinPossibleValue(self) -> None Determines which is the minimum possible value that can be represented with the current total number of digits. @return (float) the minimum possible value """ decmax = 0 for i in range(self.getDecDigitCount()): decmax += 9 * math.pow(10, -(i + 1)) return -math.pow(10.0, self.getIntDigitCount()) + 1 - decmax def _getMaxPossibleValue(self): """_getMaxPossibleValue(self) -> None Determines which is the maximum possible value that can be represented with the current total number of digits. @return (float) the maximum possible value """ decmax = 0 for i in range(self.getDecDigitCount()): decmax += 9 * math.pow(10, -(i + 1)) return math.pow(10.0, self.getIntDigitCount()) - 1 + decmax def _build(self): """_build(self) -> None Builds this widget sub-items""" l = self.layout() l.setSpacing(0) l.setContentsMargins(0, 0, 0, 0) id = self.getIntDigitCount() dd = self.getDecDigitCount() digits = self.getDigitCount() self._upButtons = Qt.QButtonGroup() self._downButtons = Qt.QButtonGroup() self._digitLabels = [] for l in self._digitLabels: l.setAlignment(Qt.AlignCenter) showDot = self.getDecDigitCount() > 0 signLabel = _DigitLabel('+') signLabel.setFocusPolicy(Qt.Qt.NoFocus) signLabel.setAlignment(Qt.Qt.AlignRight | Qt.Qt.AlignVCenter) self._digitLabels.append(signLabel) l.addWidget(signLabel, 1, 0) l.setRowMinimumHeight(1, signLabel.minimumSizeHint().height()) l.setColumnMinimumWidth(0, _ArrowButton.ButtonSize) l.setColumnStretch(0, 1) for i in range(id): col = i + 1 d = _DigitLabel('0') up = _UpArrowButton(id - i - 1) down = _DownArrowButton(id - i - 1) d.setButtons(up, down) up.setFocusProxy(d) down.setFocusProxy(d) self._upButtons.addButton(up, col) self._downButtons.addButton(down, col) self._digitLabels.append(d) if self.getShowArrowButtons(): l.addWidget(up, 0, col) l.addWidget(down, 2, col) l.addWidget(d, 1, col) if showDot: dotLabel = _DigitLabel('.') dotLabel.setFocusPolicy(Qt.Qt.NoFocus) dotLabel.setAlignment(Qt.Qt.AlignCenter) self._digitLabels.append(dotLabel) l.addWidget(dotLabel, 1, id + 1) for i in range(id, digits): col = i + 1 if showDot: col += 1 d = _DigitLabel('0') up = _UpArrowButton(id - i - 1) down = _DownArrowButton(id - i - 1) d.setButtons(up, down) up.setFocusProxy(d) down.setFocusProxy(d) self._upButtons.addButton(up, col) self._downButtons.addButton(down, col) self._digitLabels.append(d) if self.getShowArrowButtons(): l.addWidget(up, 0, col) l.addWidget(down, 2, col) l.addWidget(d, 1, col) self._upButtons.buttonClicked.connect(self.buttonPressed) self._downButtons.buttonClicked.connect(self.buttonPressed) ed = _NumericEditor(self) ed.returnPressed.connect(self.editingFinished) ed.editingFinished.connect(ed.hide) rect = Qt.QRect(l.cellRect(1, 0).topLeft(), l.cellRect(1, l.columnCount() - 1).bottomRight()) ed.setGeometry(rect) ed.setAlignment(Qt.Qt.AlignRight) ed.validator().setRange(self.getMinValue(), self.getMaxValue(), self.getDecDigitCount()) ed.setVisible(False) self._editor = ed # set the minimum height for the widget # (otherwise the hints seem to be ignored by the layouts) min_height = max(ed.minimumSizeHint().height(), signLabel.minimumSizeHint().height()) if self.getShowArrowButtons(): min_height += 2 * _ArrowButton.ButtonSize self.setMinimumHeight(min_height) self.clearWarning() def _clear(self): """_clear(self) -> None Clears this widget sub-items""" self._upButtons.buttonClicked.disconnect(self.buttonPressed) self._downButtons.buttonClicked.disconnect(self.buttonPressed) for b in self._upButtons.buttons(): self._upButtons.removeButton(b) b.setParent(None) b.destroy() for b in self._downButtons.buttons(): self._downButtons.removeButton(b) b.setParent(None) b.destroy() for label in self._digitLabels: label.setParent(None) label.destroy() self._digitLabels = None self._upButtons.setParent(None) self._downButtons.setParent(None) self._upButtons = None self._downButtons = None self._editor.setParent(None) self._editor.destroy() self._editor = None def _setMinMax(self, min, max): """_setMinMax(self, min, max) -> None Sets the minimum and maximum values for this widget @param[in] min(float) minimum value @param[in] max(float) maximum value """ self._minValue = min self._maxValue = max def _setDigits(self, int_nb=None, dec_nb=None): """_setDigits(self, int_nb=None, dec_nb=None) -> None Sets the number of digits that this widget shows. It will ensure that the current value can be displayed (i.e., int_nb will be forced to be large enough for displaying the integer representation of the value) @param[in] int_nb (int) number of integer digits (optional, default is None, meaning use the existing number of integer digits @param[in] dec_nb (int) number of decimal digits (optional, default is None, meaning use the existing number of decimal digits """ if not int_nb is None: self._intDigitCount = int_nb if not dec_nb is None: self._decDigitCount = dec_nb # make sure that the current value can be displayed self._intDigitCount = max(self._intDigitCount, len("%d" % self._value)) self._digitCount = self._intDigitCount + self._decDigitCount total_chars = self._digitCount total_chars += 1 # for sign if self._decDigitCount > 0: total_chars += 1 # for dot self._valueFormat = '%%+0%d.%df' % (total_chars, self._decDigitCount) self._setMinMax(self._getMinPossibleValue(), self._getMaxPossibleValue()) # we call setValue to update the self._value_str self._setValue(self.getValue()) def _buildValueStr(self, v): """_buildValueStr(self, v) -> str Builds a string representation of the given value according to the number of digits this widget can currently represent @param[in] v (float) the value to be translated @return (str) a proper string representation of the given value """ if v is None: ret = (self._valueFormat % 0).replace('0', '-') else: ret = self._valueFormat % v if ret.endswith('nan'): ret = ret.replace('0', ' ') self._value_str = ret return ret def _updateDigits(self): """_updateDigits(self) -> None Updates this widget contents (sub-widgets) according to the current widget configuration """ self._clear() self._build() self._updateValue(False, False) def _updateValue(self, trigValueChanged=True, trigValueEdited=True): """_updateValue(self, trigValueChanged=True, trigValueEdited=True) -> None Updates this widget displayed value and potentially send signal(s) @param[in] trigValueChanged (bool) (optional, default is True) wheather or not to send signal 'valueChanged(double)' @param[in] trigValueEdited (bool) (optional, default is True) wheather or not to send signal 'valueEdit(double)' """ v, v_str = self.getValue(), self.getValueStr() if len(v_str) > len(self._digitLabels): # do auto adjust if '.' in v_str: dc = list(map(len, v_str.split('.'))) else: dc = len(v_str), 0 self._setDigits(*dc) v_str = self._buildValueStr(v) self._clear() self._build() for i, c in enumerate(v_str): self._digitLabels[i].setText(c) if trigValueChanged: self.numberChanged.emit(v) if trigValueEdited: self.numberEdited.emit(v)
[docs] def setRoundFunc(self, roundFunc): """setRoundFunc(self, roundFunc) -> None Sets the rounding function to use when calling _setValue(). This allows you to filter invalid user input @param[in] roundFunc (callable) the rounding function to use """ self._roundFunc = roundFunc
[docs] def getPreviousValue(self): """getPreviousValue(self) -> float Gives the previous value of this widget @return (float) the previous value of this widget """ return self._previous_value
def _setValue(self, v): """_setValue(self, v) -> None Sets value of this widget. If the given value exceeds any limit, the value is NOT set. """ if self._roundFunc: v = self._roundFunc(v) if v > self._maxValue or v < self._minValue: return self._previous_value = self._value self._value = v self._buildValueStr(v)
[docs] def setWarning(self, msg): """setWarning(self, msg) -> None Activates the warning style for this widget. This means a violet border and a tooltip with the given message. @param[in] msg (str) the message to be displayed as tooltip """ self.setStyleSheet( 'QWheelEdit {border: 1px solid; border-radius: 4px; border-color: violet}') self.setToolTip(msg)
[docs] def clearWarning(self): """clearWarning(self) -> None Clears the warning style. If not in warning mode, nothing is done. """ self.setStyleSheet( 'QWheelEdit {border: 1px solid; border-radius: 4px; border-color: rgba(0,0,0,0)}') self.setToolTip('')
[docs] def buttonPressed(self, b): """buttonPressed(self, b) -> None Slot executed when an arrow button is pressed from the button group @param[in] b (_ArrowButton) the button which was pressed """ self._setValue(self.getValue() + b._inc) self._updateValue()
[docs] def setDigitCount(self, int_nb, dec_nb): """setDigitCount(self, int_nb, dec_nb) -> None Updates the displayed digits. @param[in] int_nb(int) number of integer digits @param[in] dec_nb(int) number of decimal digits """ self._setDigits(int_nb=int_nb, dec_nb=dec_nb) self._updateDigits()
[docs] def getDigitCount(self): """getDigitCount(self) -> int Gets the total number of digits this widget displays @return (int) the total number of digits this widget displays """ return self._digitCount
[docs] def getIntDigitCount(self): """getIntDigitCount(self) -> int Gets the number of integer digits this widget displays @return (int) the number of integer digits this widget displays """ return self._intDigitCount
[docs] def setIntDigitCount(self, n): """setIntDigitCount(self, n) -> None Sets the number of integer digits this widget displays @param[in] n (int) the number of integer digits to display """ self._setDigits(int_nb=n) self._updateDigits()
[docs] def resetIntDigitCount(self): """resetIntDigitCount(self) -> None Resets the number of integer digits this widget displays to DefaultIntDigitCount """ self.setIntDigitCount(QWheelEdit.DefaultIntDigitCount)
[docs] def getDecDigitCount(self): """getDecDigitCount(self) -> int Gets the number of decimal digits this widget displays @return (int) the number of decimal digits this widget displays """ return self._decDigitCount
[docs] def setDecDigitCount(self, n): """setDecDigitCount(self, n) -> None Sets the number of decimal digits this widget displays @param[in] n (int) the number of decimal digits to display """ self._setDigits(dec_nb=n) self._updateDigits()
[docs] def resetDecDigitCount(self): """resetDecDigitCount(self) -> None Resets the number of decimal digits this widget displays to DefaultDecDigitCount """ self.setDecDigitCount(QWheelEdit.DefaultDecDigitCount)
[docs] def setValue(self, v): """setValue(self, v) -> None Sets the value of this widget. Send a 'valueChanged(double)' Qt signal @param[in] v (float/Quantity) the value to be set """ if isinstance(v, Q_): v = v.magnitude self._setValue(v) self._updateValue(trigValueEdited=False)
[docs] def resetValue(self): """resetValue(self) -> None Resets the value of this widget to 0.0 """ self.setValue(0.0)
[docs] def getValue(self): """getValue(self) -> float Gets the current value of this widget @return (float) the value currently displayed by the widget """ return self._value
[docs] def getValueStr(self): """getValueStr(self) -> str Gets the current value string of this widget @return (str) the value currently displayed by the widget """ return self._value_str
[docs] def getMinValue(self): """getMinValue(self) -> float Gets the minimum allowed value @return (float) the minimum allowed value """ return self._minValue
[docs] def setMinValue(self, v): """setMinValue(self, v) -> None Sets the minimum allowed value for the widget @param[in] v (float) the new minimum allowed value """ self._minValue = v w = self.getEditWidget() if not w is None: w.validator().setRange(self._minValue, self._maxValue, self._decDigitCount)
[docs] def resetMinValue(self): """resetMinValue(self) -> None Resets the minimum allowed value to the minimum possible according to the current total number of digits """ self.setMinValue(self._getMinPossibleValue())
[docs] def getMaxValue(self): """getMaxValue(self) -> float Gets the maximum allowed value @return (float) the maximum allowed value """ return self._maxValue
[docs] def setMaxValue(self, v): """setMaxValue(self, v) -> None Sets the maximum allowed value for the widget @param[in] v (float) the new maximum allowed value """ self._maxValue = v w = self.getEditWidget() if not w is None: w.validator().setRange(self._minValue, self._maxValue, self._decDigitCount)
[docs] def resetMaxValue(self): """resetMaxValue(self) -> None Resets the maximum allowed value to the maximum possible according to the current total number of digits """ self.setMaxValue(self._getMaxPossibleValue())
[docs] def getAutoRepeat(self): return self._upButtons.buttons()[0].autoRepeat()
[docs] def setAutoRepeat(self, v): for b in self._upButtons.buttons(): b.setAutoRepeat(v) for b in self._downButtons.buttons(): b.setAutoRepeat(v)
[docs] def resetAutoRepeat(self): self.setAutoRepeat(False)
[docs] def getAutoRepeatDelay(self): return self._upButtons.buttons()[0].autoRepeatDelay()
[docs] def setAutoRepeatDelay(self, milisecs): for b in self._upButtons.buttons(): b.setAutoRepeatDelay(milisecs) for b in self._downButtons.buttons(): b.setAutoRepeatDelay(milisecs)
[docs] def getAutoRepeatInterval(self): return self._upButtons.buttons()[0].autoRepeatInterval()
[docs] def setAutoRepeatInterval(self, milisecs): for b in self._upButtons.buttons(): b.setAutoRepeatInterval(milisecs) for b in self._downButtons.buttons(): b.setAutoRepeatInterval(milisecs)
[docs] def getEditWidget(self): """getEditWidget(self) -> QWidget Gets the widget object used when the user manually sets the value @return (QWidget) the widget used for editing """ return self._editor
[docs] def editingFinished(self): """editingFinished(self) -> None Slot called when the user finishes editing """ ed = self.getEditWidget() v = float(ed.text()) self._setValue(v) self._updateValue()
[docs] def showEditWidget(self): """showEditWidget(self) -> None Forces the edition widget to be displayed """ ed, l = self.getEditWidget(), self.layout() rect = Qt.QRect(l.cellRect(1, 0).topLeft(), l.cellRect(1, l.columnCount() - 1).bottomRight()) ed.setGeometry(rect) ed.setAlignment(Qt.Qt.AlignRight) ed.setMaxLength(self.getDigitCount() + 2) ed.setText(self.getValueStr()) ed.selectAll() ed.setFocus() ed.setVisible(True)
[docs] def hideEditWidget(self): """hideEditWidget(self) -> None Forces the edition widget to be hidden """ ed = self.getEditWidget() ed.setVisible(False) self.setFocus()
[docs] def wheelEvent(self, evt): numDegrees = evt.delta() // 8 numSteps = numDegrees // 15 #w = Qt.QApplication.focusWidget() w = self.focusWidget() if not isinstance(w, _DigitLabel): return Qt.QFrame.wheelEvent(self, evt) if numSteps > 0: inc = w._upButton._inc else: inc = -w._downButton._inc numSteps *= inc self.setValue(self.getValue() + numSteps) evt.accept()
[docs] def mouseDoubleClickEvent(self, mouse_event): """mouseDoubleClickEvent(self, mouse_event) Executed when user presses double click. This widget shows the edition widget when this happens """ self.showEditWidget() self._editing = True
[docs] def keyPressEvent(self, key_event): """keyPressEvent(self, key_event) -> None Exectuted when the user presses a key. F2 enters/leaves edition mode. ESC leaves edition mode """ k = key_event.key() if k == Qt.Qt.Key_F2: if self._editing: self.hideEditWidget() self._editing = False else: self.showEditWidget() self._editing = True return elif k == Qt.Qt.Key_Escape: if self._editing: self.hideEditWidget() self._editing = False return elif k in (Qt.Qt.Key_Return, Qt.Qt.Key_Enter): if self._editing: self.hideEditWidget() self._editing = False else: self.returnPressed.emit() # TODO Decide when to emit editingFinished for completeness Qt.QWidget.keyPressEvent(self, key_event)
[docs] def getShowArrowButtons(self): return self._showArrowButtons
[docs] def setShowArrowButtons(self, yesno): self._showArrowButtons = yesno self._updateDigits()
[docs] def resetShowArrowButtons(self): self.setShowArrowButtons(True)
#-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # QT properties #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- showArrowButtons = Qt.pyqtProperty("bool", getShowArrowButtons, setShowArrowButtons, resetShowArrowButtons) integerDigits = Qt.pyqtProperty("int", getIntDigitCount, setIntDigitCount, resetIntDigitCount) decimalDigits = Qt.pyqtProperty("int", getDecDigitCount, setDecDigitCount, resetDecDigitCount) value = Qt.pyqtProperty("double", getValue, setValue, resetValue) minValue = Qt.pyqtProperty("double", getMinValue, setMinValue, resetMinValue) maxValue = Qt.pyqtProperty("double", getMaxValue, setMaxValue, resetMaxValue) autoRepeat = Qt.pyqtProperty("bool", getAutoRepeat, setAutoRepeat, resetAutoRepeat) autoRepeatDelay = Qt.pyqtProperty("int", getAutoRepeatDelay, setAutoRepeatDelay) autoRepeatInterval = Qt.pyqtProperty("int", getAutoRepeatInterval, setAutoRepeatInterval)
def main(): import taurus.qt.qtgui.icon # otherwise the arrows don't show in the demo global arrowWidget def resetAll(): arrowWidget.resetIntDigitCount() arrowWidget.resetDecDigitCount() arrowWidget.resetMinValue() arrowWidget.resetMaxValue() arrowWidget.resetValue() def setNAN(): arrowWidget.setValue(float('nan')) def setNone(): arrowWidget.setValue(None) a = Qt.QApplication([]) panel = Qt.QWidget() l = Qt.QFormLayout(panel) button_layout = Qt.QVBoxLayout() arrowWidget = QWheelEdit(panel) isb, dsb = Qt.QSpinBox(panel), Qt.QSpinBox(panel) minv, maxv = Qt.QDoubleSpinBox(panel), Qt.QDoubleSpinBox(panel) resetbutton = Qt.QPushButton("Reset", panel) resetbutton.setDefault(True) nanbutton = Qt.QPushButton("Set NAN", panel) nonebutton = Qt.QPushButton("Set None", panel) showarrowbutton = Qt.QCheckBox("", panel) l.addRow("Value", arrowWidget) l.addRow("Integer digits:", isb) l.addRow("Decimal digits:", dsb) l.addRow("Minimum value:", minv) l.addRow("Maximum value:", maxv) l.addRow("Show arrows:", showarrowbutton) l.addRow(button_layout) button_layout.addWidget(nanbutton) button_layout.addWidget(nonebutton) button_layout.addWidget(resetbutton) isb.setValue(arrowWidget.getIntDigitCount()) dsb.setValue(arrowWidget.getDecDigitCount()) minv.setRange(numpy.finfo('d').min, numpy.finfo('d').max) maxv.setRange(numpy.finfo('d').min, numpy.finfo('d').max) minv.setValue(arrowWidget.getMinValue()) maxv.setValue(arrowWidget.getMaxValue()) showarrowbutton.setChecked(arrowWidget.getShowArrowButtons()) isb.valueChanged.connect(arrowWidget.setIntDigitCount) dsb.valueChanged.connect(arrowWidget.setDecDigitCount) minv.valueChanged.connect(arrowWidget.setMinValue) showarrowbutton.stateChanged.connect(arrowWidget.setShowArrowButtons) nanbutton.clicked.connect(setNAN) nonebutton.clicked.connect(setNone) resetbutton.clicked.connect(resetAll) panel.setVisible(True) a.exec_() if __name__ == "__main__": main()