From 8726b0a62d0663f7373cb32a8f6667af112b85bf Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Mon, 22 Jun 2026 22:52:36 +0200 Subject: [PATCH] GUI: use a spinbox for ambient temperature instead of a text entry Replaces lineEdit_ambient (QLineEdit) with doubleSpinBox_ambient (QDoubleSpinBox, 0-50 degC, 0.5 deg steps) in brewpi.ui, regenerated main_window.py via pyuic5 (same generator version, verified minimal diff). brewpi_gui.py wires valueChanged instead of returnPressed - no more manual float()/ValueError parsing of typed text, the signal already hands over a valid float - with blockSignals guards around server-driven updates (mirroring the existing doubleSpinBox_heatrate_soll pattern) so applying a server echo doesn't immediately re-send the same value back. Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_01DkkuG48uHFCGKe6dPSERFk --- client/brewpi.ui | 16 ++++++++++++++-- client/brewpi_gui.py | 26 ++++++++++++++------------ client/main_window.py | 12 ++++++++---- 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/client/brewpi.ui b/client/brewpi.ui index db17a49..9b13aff 100644 --- a/client/brewpi.ui +++ b/client/brewpi.ui @@ -3714,7 +3714,7 @@ Qt::AlignCenter - + 620 @@ -3724,7 +3724,19 @@ - Set the simulated/assumed ambient temperature - press Enter to apply + Set the simulated/assumed ambient temperature + + + 1 + + + 0.000000000000000 + + + 50.000000000000000 + + + 0.500000000000000 diff --git a/client/brewpi_gui.py b/client/brewpi_gui.py index 188ebea..ad95762 100755 --- a/client/brewpi_gui.py +++ b/client/brewpi_gui.py @@ -365,7 +365,7 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow): self.checkbox_heater_activate.stateChanged.connect(self.on_checkbox_changed) self.checkbox_stirrer_activate.stateChanged.connect(self.on_checkbox_stirrer_activate_changed) self.checkbox_tc_enable.stateChanged.connect(self.on_checkbox_tc_enable_changed) - self.lineEdit_ambient.returnPressed.connect(self.on_ambient_entry_changed) + self.doubleSpinBox_ambient.valueChanged.connect(self.on_ambient_entry_changed) self.btn_pot_reset.clicked.connect(self.on_action_pot_reset) # Only meaningful (and only shown) once the server confirms its Pot # is simulated - see on_system_changed()'s "PlantSim" handling. @@ -494,7 +494,9 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow): self.Slider_temp_soll.setEnabled(False) self.doubleSpinBox_heatrate_soll.setEnabled(False) self.ambient_temp = None - self.lineEdit_ambient.clear() + self.doubleSpinBox_ambient.blockSignals(True) + self.doubleSpinBox_ambient.setValue(self.doubleSpinBox_ambient.minimum()) + self.doubleSpinBox_ambient.blockSignals(False) self.btn_pot_reset.setVisible(False) self.warp_factor = 1.0 self.sud_elapsed_seconds = None @@ -528,11 +530,15 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow): for key in msg: if "AmbientTemp" in key: self.ambient_temp = msg['AmbientTemp'] - # Only sync the entry's text while the user isn't actively - # editing it, so a server echo doesn't clobber in-progress - # typing. - if not self.lineEdit_ambient.hasFocus(): - self.lineEdit_ambient.setText("{:.1f}".format(self.ambient_temp)) + # Only sync the spinbox while the user isn't actively + # interacting with it, so a server echo doesn't clobber an + # in-progress edit - blockSignals avoids this setValue() + # itself re-triggering on_ambient_entry_changed() and + # echoing the same value straight back. + if not self.doubleSpinBox_ambient.hasFocus(): + self.doubleSpinBox_ambient.blockSignals(True) + self.doubleSpinBox_ambient.setValue(self.ambient_temp) + self.doubleSpinBox_ambient.blockSignals(False) elif "WarpFactor" in key: self.warp_factor = msg['WarpFactor'] elif "PlantSim" in key: @@ -542,11 +548,7 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow): def on_action_pot_reset(self): self.msg_pot.send({'Reset': True}) - def on_ambient_entry_changed(self): - try: - value = float(self.lineEdit_ambient.text()) - except ValueError: - return + def on_ambient_entry_changed(self, value): self.user_config.set('ambient_temperature', value) self.msg_system.send({'AmbientTemp': value}) diff --git a/client/main_window.py b/client/main_window.py index 9cc0c29..93c02a4 100644 --- a/client/main_window.py +++ b/client/main_window.py @@ -1237,9 +1237,13 @@ class Ui_MainWindow(object): self.label_ambient.setGeometry(QtCore.QRect(520, 500, 91, 31)) self.label_ambient.setAlignment(QtCore.Qt.AlignCenter) self.label_ambient.setObjectName("label_ambient") - self.lineEdit_ambient = QtWidgets.QLineEdit(self.centralwidget) - self.lineEdit_ambient.setGeometry(QtCore.QRect(620, 500, 70, 31)) - self.lineEdit_ambient.setObjectName("lineEdit_ambient") + self.doubleSpinBox_ambient = QtWidgets.QDoubleSpinBox(self.centralwidget) + self.doubleSpinBox_ambient.setGeometry(QtCore.QRect(620, 500, 70, 31)) + self.doubleSpinBox_ambient.setDecimals(1) + self.doubleSpinBox_ambient.setMinimum(0.0) + self.doubleSpinBox_ambient.setMaximum(50.0) + self.doubleSpinBox_ambient.setSingleStep(0.5) + self.doubleSpinBox_ambient.setObjectName("doubleSpinBox_ambient") self.btn_pot_reset = QtWidgets.QPushButton(self.centralwidget) self.btn_pot_reset.setGeometry(QtCore.QRect(700, 500, 220, 31)) self.btn_pot_reset.setObjectName("btn_pot_reset") @@ -1314,7 +1318,7 @@ class Ui_MainWindow(object): self.plainTextUri.setPlainText(_translate("MainWindow", "ws://localhost:8765")) self.btn_connect.setText(_translate("MainWindow", "Connect")) self.label_ambient.setText(_translate("MainWindow", "Ambient [°C]")) - self.lineEdit_ambient.setToolTip(_translate("MainWindow", "Set the simulated/assumed ambient temperature - press Enter to apply")) + self.doubleSpinBox_ambient.setToolTip(_translate("MainWindow", "Set the simulated/assumed ambient temperature")) self.btn_pot_reset.setToolTip(_translate("MainWindow", "Only available when the server\'s Pot is simulated")) self.btn_pot_reset.setText(_translate("MainWindow", "Pot reset to ambient temperature")) self.label_8.setText(_translate("MainWindow", "Host"))