Source code for taurus.qt.qtgui.panel.taurusinputpanel
#!/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 Input panel (usually used inside a TaurusDialog)
"""
from collections.abc import Sequence, Mapping
import numpy
from taurus.external.qt import Qt
from taurus.qt.qtgui.util.ui import UILoadable
__docformat__ = "restructuredtext"
[docs]
@UILoadable(with_ui="_ui")
class TaurusInputPanel(Qt.QWidget):
"""A panel design to get an input from the user.
The input_data is a dictionary which contains information on how to build
the input dialog. It **must** contains the following keys:
- *prompt* <str>: message to be displayed
The following are optional keys (and their corresponding default values):
- *title* <str> (doesn't have default value)
- *key* <str> (doesn't have default value):
a label to be presented left to the input box represeting the label
- *unit* <str> (doesn't have default value):
a label to be presented right to the input box representing the units
- *data_type* <str or sequence> ('String'):
type of data to be requested. Standard
accepted data types are 'String', 'Integer', 'Float', 'Boolean',
'Text'. A list of elements will be interpreted as a selection.
Default TaurusInputPanel class will interpret any custom data types
as 'String' and will display input widget accordingly. Custom data
types can be handled differently by supplying a different
input_panel_klass.
- *minimum* <int/float>:
minimum value (makes sense when data_type is 'Integer' or 'Float')
- *maximum* <int/float>:
maximum value (makes sense when data_type is 'Integer' or 'Float')
- *step* <int/float> (1):
step size value (makes sense when data_type is 'Integer' or 'Float')
- *decimals* <int> (1):
number of decimal places to show (makes sense when data_type is
'Float')
- *default_value* <obj> (doesn't have default value):
default value
- *allow_multiple* <bool> (False):
allow more than one value to be selected (makes sense when data_type
is a sequence of possibilities)
Example::
app = Qt.QApplication([])
class Listener(object):
def on_accept(self):
print("user selected", self.panel.value())
d = dict(
prompt="What's your favourite car brand?",
data_type=["Mazda", "Skoda", "Citroen", "Mercedes", "Audi"],
default_value="Mercedes"
)
w = TaurusInputPanel(d)
l = Listener()
l.panel = w
w.connect(w.buttonBox(), Qt.SIGNAL("accepted()"), l.on_accept)
w.show()
app.exec_()
"""
def __init__(self, input_data, parent=None):
Qt.QWidget.__init__(self, parent)
self._input_data = input_data
self.loadUi()
self.fill_main_panel(self._ui._inputPanel, input_data)
[docs]
def fill_main_panel(self, panel, input_data):
layout = Qt.QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
panel.setLayout(layout)
if isinstance(input_data, Mapping):
single_panel, getter = self.create_single_input_panel(input_data)
layout.addWidget(single_panel)
self.value = getter
if "title" in input_data:
self.setWindowTitle(input_data["title"])
[docs]
def create_single_input_panel(self, input_data):
style = Qt.QApplication.instance().style()
icon = style.standardIcon(Qt.QStyle.SP_MessageBoxQuestion)
self.setIconPixmap(icon.pixmap(64))
self.setText(input_data["prompt"])
data_type = input_data.get("data_type", "String")
is_seq = not isinstance(data_type, str) and isinstance(
data_type, Sequence
)
if is_seq:
panel, getter = self.create_selection_panel(input_data)
else:
data_type_l = data_type.lower()
creator = getattr(
self,
"create_" + data_type_l + "_panel",
self.create_custom_panel,
)
if creator:
panel, getter = creator(input_data)
if panel is None:
panel = Qt.QLabel(
"Cannot create widget for data type '%s'" % data_type
)
getter = lambda: None # noqa: E731
return panel, getter
[docs]
def create_selection_panel(self, input_data):
allow_multiple = input_data.get("allow_multiple", False)
if allow_multiple:
return self._create_multi_selection_panel(input_data)
else:
return self._create_single_selection_panel(input_data)
def _create_single_selection_panel(self, input_data):
items = list(map(str, input_data["data_type"]))
if len(items) > 5:
return self._create_combobox_panel(input_data)
return self._create_radiobutton_panel(input_data)
def _create_combobox_panel(self, input_data):
panel = self._create_simple_panel(input_data)
layout = panel.layout()
self._ui.inputWidget = combobox = Qt.QComboBox()
items = input_data["data_type"]
for item in items:
is_seq = not isinstance(item, str) and isinstance(item, Sequence)
if is_seq:
text, userData = item
else:
text, userData = str(item), item
combobox.addItem(text, userData)
layout.addWidget(combobox, 0, 1)
return panel, self._get_combobox_value
def _get_combobox_value(self):
combo = self._ui.inputWidget
return combo.itemData(combo.currentIndex())
def _create_radiobutton_panel(self, input_data):
panel = self._create_group_panel(input_data)
layout = panel.layout()
items = input_data["data_type"]
default_value = input_data.get("default_value")
self._ui.inputWidget = buttongroup = Qt.QButtonGroup()
buttongroup.setExclusive(True)
for item in items:
is_seq = not isinstance(item, str) and isinstance(item, Sequence)
if is_seq:
text, userData = item
else:
text, userData = str(item), item
button = Qt.QRadioButton(text)
button._value = userData
if default_value == userData:
button.setChecked(True)
buttongroup.addButton(button)
layout.addWidget(button)
return panel, self._get_radiobutton_value
def _get_radiobutton_value(self):
buttongroup = self._ui.inputWidget
button = buttongroup.checkedButton()
if button is not None:
return button._value
def _create_multi_selection_panel(self, input_data):
panel = self._create_group_panel(input_data)
layout = panel.layout()
items = input_data["data_type"]
default_value = input_data.get("default_value")
if default_value is None:
default_value = ()
dft_is_seq = not isinstance(default_value, str) and isinstance(
default_value, Sequence
)
if not dft_is_seq:
default_value = (default_value,)
self._ui.inputWidget = listwidget = Qt.QListWidget()
listwidget.setSelectionMode(Qt.QAbstractItemView.MultiSelection)
for item in items:
is_seq = not isinstance(item, str) and isinstance(item, Sequence)
if is_seq:
text, userData = item
else:
text, userData = str(item), item
item_widget = Qt.QListWidgetItem(text, listwidget)
item_widget.setData(Qt.Qt.UserRole, userData)
if userData in default_value:
item_widget.setSelected(True)
layout.addWidget(listwidget)
return panel, self._get_multi_selection_value
def _get_multi_selection_value(self):
listwidget = self._ui.inputWidget
return [
item.data(Qt.Qt.UserRole) for item in listwidget.selectedItems()
]
def _create_group_panel(self, input_data):
title = input_data.get("key", "")
unit = input_data.get("unit", "")
if unit:
title += "(" + unit + ")"
panel = Qt.QGroupBox(title)
layout = Qt.QVBoxLayout()
panel.setLayout(layout)
self._ui.inputLabel = Qt.QLabel()
self._ui.unitLabel = Qt.QLabel()
return panel
def _create_simple_panel(self, input_data):
panel = Qt.QWidget()
key = input_data.get("key", "")
if key:
key += ":"
unit = input_data.get("unit", "")
layout = Qt.QGridLayout()
panel.setLayout(layout)
self._ui.inputLabel = label = Qt.QLabel(key)
layout.addWidget(label, 0, 0)
self._ui.unitLabel = unit = Qt.QLabel(unit)
layout.addWidget(unit, 0, 2)
layout.setColumnStretch(0, 0)
layout.setColumnStretch(1, 1)
layout.setColumnStretch(2, 0)
return panel
[docs]
def create_integer_panel(self, input_data):
panel = self._create_simple_panel(input_data)
minimum = input_data.get("minimum", numpy.iinfo("i").min)
maximum = input_data.get("maximum", numpy.iinfo("i").max)
step = input_data.get("step", 1)
layout = panel.layout()
self._ui.inputWidget = spinbox = Qt.QSpinBox()
spinbox.setMinimum(minimum)
spinbox.setMaximum(maximum)
spinbox.setSingleStep(step)
if "default_value" in input_data:
spinbox.setValue(input_data["default_value"])
layout.addWidget(spinbox, 0, 1)
return panel, self._get_integer_value
def _get_integer_value(self):
return int(self._ui.inputWidget.value())
[docs]
def create_float_panel(self, input_data):
panel = self._create_simple_panel(input_data)
minimum = input_data.get("minimum", numpy.finfo("d").min)
maximum = input_data.get("maximum", numpy.finfo("d").max)
step = input_data.get("step", 1)
decimals = input_data.get("decimals", 1)
layout = panel.layout()
self._ui.inputWidget = spinbox = Qt.QDoubleSpinBox()
spinbox.setMinimum(minimum)
spinbox.setMaximum(maximum)
spinbox.setSingleStep(step)
spinbox.setDecimals(decimals)
if "default_value" in input_data:
spinbox.setValue(input_data["default_value"])
layout.addWidget(spinbox, 0, 1)
return panel, self._get_float_value
def _get_float_value(self):
return float(self._ui.inputWidget.value())
[docs]
def create_string_panel(self, input_data):
panel = self._create_simple_panel(input_data)
layout = panel.layout()
self._ui.inputWidget = lineedit = Qt.QLineEdit()
if "default_value" in input_data:
lineedit.setText(str(input_data["default_value"]))
lineedit.selectAll()
layout.addWidget(lineedit, 0, 1)
return panel, self._get_string_value
def _get_string_value(self):
return str(self._ui.inputWidget.text())
[docs]
def create_text_panel(self, input_data):
panel = self._create_group_panel(input_data)
layout = panel.layout()
self._ui.inputWidget = textedit = Qt.QTextEdit()
textedit.setAcceptRichText(False)
if "default_value" in input_data:
textedit.setPlainText(str(input_data["default_value"]))
textedit.selectAll()
layout.addWidget(textedit)
return panel, self._get_text_value
def _get_text_value(self):
return str(self._ui.inputWidget.toPlainText())
[docs]
def create_boolean_panel(self, input_data):
panel = self._create_simple_panel(input_data)
layout = panel.layout()
self._ui.inputWidget = checkbox = Qt.QCheckBox()
value = input_data.get("default_value", False)
checkbox.setChecked(value)
layout.addWidget(checkbox, 0, 1)
return panel, self._get_boolean_value
def _get_boolean_value(self):
return self._ui.inputWidget.checkState() == Qt.Qt.Checked
[docs]
def buttonBox(self):
"""Returns the button box from this panel
:return: the button box from this panel
:rtype: PyQt5.Qt.QDialogButtonBox
"""
return self._ui._buttonBox
[docs]
def addButton(self, button, role=Qt.QDialogButtonBox.ActionRole):
"""Adds the given button with the given to the button box
:param button: the button to be added
:type button: PyQt5.Qt.QPushButton
:param role: button role
:type role: PyQt5.Qt.QDialogButtonBox.ButtonRole
"""
self._ui._buttonBox.addButton(button, role)
[docs]
def setIconPixmap(self, pixmap):
"""Sets the icon to the dialog
:param pixmap: the icon pixmap
:type pixmap: PyQt5.Qt.QPixmap
"""
self._ui.iconLabel.setPixmap(pixmap)
[docs]
def setText(self, text):
"""Sets the text of this panel
:param text: the new text
:type text: str
"""
self._ui.textLabel.setText(text)
[docs]
def getText(self):
"""Returns the current text of this panel
:return: the text for this panel
:rtype: str
"""
return self._ui.textLabel.text()
[docs]
def setInputFocus(self):
inputWidget = self._ui.inputWidget
if not inputWidget:
return
if isinstance(inputWidget, Qt.QWidget):
inputWidget.setFocus()
elif isinstance(inputWidget, Qt.QButtonGroup):
bid = inputWidget.checkedId()
if bid < 0:
button = inputWidget.buttons()[0]
else:
button = inputWidget.button(bid)
button.setFocus()
def main():
app = Qt.QApplication([])
class Listener(object):
def on_accept(self):
print("user selected", self.panel.value())
d = dict(
prompt="What's your favourite car brand?",
data_type=["Mazda", "Skoda", "Citroen", "Mercedes", "Audi", "Ferrari"],
default_value="Mercedes",
)
w = TaurusInputPanel(d)
listener = Listener()
listener.panel = w
w.buttonBox().accepted.connect(listener.on_accept)
w.show()
app.exec_()
if __name__ == "__main__":
main()