Objective: create a line item object that contains a textbox for a label, value, and value units in PySide.
Background: I am creating a control panel for a device that is run off of a Raspberry Pi using Python PySide (QtPython) to handle the GUI. I am using the grid layout, and have a common motif I am trying to encapsulate in a class to avoid repeating myself. I need some help building that class.
Typically, my code looks like this:
class Form(QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
self.pressure_label = QLabel('Pressure:')
self.pressure_value = QLabel()
self.pressure_units = QLabel('psi')
self.temperature_label = QLabel('Temperature:')
self.temperature_value = QLabel()
self.temperature_units = QLabel('oC')
...
grid = QGridLayout()
grid.addWidget(pressure_label, 0, 0)
grid.addWidget(pressure_value, 0, 1)
grid.addWidget(pressure_units, 0, 1)
grid.addWidget(temperature_label, 1, 0)
grid.addWidget(temperature_value, 1, 1)
grid.addWidget(temperature_units, 1, 1)
...
self.setLayout(grid)
def update(self):
self.temperature_value.setText(t_sensor.read())
self.pressure_value.setText(p_sensor.read())
What I have tried:
With GUI elements, I am not really sure where I need to put my classes, or what parent object they need to inherit. I have tried to create an object in the following way, but it is just a framework, and obviously won't compile.
class LineItem(object):
def __init__(self, label_text, unit_text, grid, row):
self.value = None
self.units = None
self.label_field = QLabel(label_text)
self.value_field = QLabel()
self.units_field = QLabel(unit_text)
grid.addWidget(self.label_field, row, 0)
grid.addWidget(self.value_field, row, 1)
grid.addWidget(self.units_field, row, 2)
@property
def value(self):
return self.value
@value.setter
def value(self, val):
self.value = val
self.value_field.setText(val)
@property
def units(self):
return self.value
@value.setter
def units(self, val):
self.units = val
self.units_field.setText(val)
class Form(QDialog):
def __init__(self, parent=None):
grid = QGridLayout()
row_number = itertools.count()
tb_encoder_1 = LineItem('Distance:', 'm', grid, next(row_number))
tb_encoder_2 = LineItem('Distance:', 'm', grid, next(row_number))
self.setLayout(grid)
What I need:
What I am hoping to do is encapsulate this label, value, units structure into a class, so that I don't have to repeat myself so much.
Where does a class like this go? What does it inherit? How do I give it access to the grid
object (does it even need access)?
What I struggle with is understanding how classes and encapsulation translate to PySide forms and widgets. Most of the tutorials I have seen so far don't go that route, they just put all the logic and creating in one big Form(QDialog)
class.
You just need a QWidget
subclass to act as a container for the other widgets. Its structure will be very similar to a normal form - the main difference is that it will end up as a child widget of another form, rather than as a top-level window.
class LineItem(QWidget):
def __init__(self, label_text, unit_text, parent=None):
super(LineItem, self).__init__(parent)
self.label_field = QLabel(label_text)
self.value_field = QLabel()
self.units_field = QLabel(unit_text)
layout = QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(self.label_field)
layout.addWidget(self.value_field)
layout.addWidget(self.units_field)
self.setLayout(layout)
class Form(QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
self.pressure_line = LineItem('Pressure:', 'psi', self)
self.temperature_line = LineItem('Temperature:', 'oC', self)
layout = QHBoxLayout()
layout.addWidget(self.pressure_line)
layout.addWidget(self.temperature_line)
self.setLayout(layout)