Adjust GUI layout for compact header and larger plots

This commit is contained in:
jens 2026-04-11 23:02:24 +02:00
parent 2103601efa
commit f4f3a69adf

View File

@ -3,9 +3,9 @@ import serial
import serial.tools.list_ports import serial.tools.list_ports
from PyQt6.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, from PyQt6.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout,
QWidget, QLabel, QPushButton, QComboBox, QDoubleSpinBox, QWidget, QLabel, QPushButton, QComboBox, QDoubleSpinBox,
QGroupBox, QStatusBar, QMessageBox, QCheckBox) QGroupBox, QStatusBar, QMessageBox, QCheckBox, QScrollArea, QSizePolicy)
from PyQt6.QtCore import QTimer, Qt from PyQt6.QtCore import QTimer, Qt
from PyQt6.QtGui import QFont from PyQt6.QtGui import QFont, QGuiApplication
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure from matplotlib.figure import Figure
@ -19,32 +19,33 @@ class PHControllerGUI(QMainWindow):
self.serial_connection = None self.serial_connection = None
self.updating_tube_combo = False # Flag to prevent recursive tube commands self.updating_tube_combo = False # Flag to prevent recursive tube commands
self.setWindowTitle("Arduino pH Controller") self.setWindowTitle("Arduino pH Controller")
self.setGeometry(100, 100, 900, 800) # Larger window for plot self.setMinimumSize(900, 650)
# Central Widget # Scrollable central widget keeps the full UI reachable on small screens.
scroll_area = QScrollArea()
scroll_area.setWidgetResizable(True)
central_widget = QWidget() central_widget = QWidget()
self.setCentralWidget(central_widget) scroll_area.setWidget(central_widget)
self.setCentralWidget(scroll_area)
main_layout = QVBoxLayout(central_widget) main_layout = QVBoxLayout(central_widget)
# Connection Group # Connection + Status Group
connection_group = QGroupBox("Verbindung") connection_group = QGroupBox("Verbindung & Status")
connection_group_layout = QVBoxLayout()
connection_group_layout.setContentsMargins(8, 8, 8, 8)
connection_group_layout.setSpacing(6)
connection_layout = QHBoxLayout() connection_layout = QHBoxLayout()
connection_layout.setContentsMargins(0, 0, 0, 0)
connection_layout.setSpacing(10)
self.port_combo = QComboBox() self.port_combo = QComboBox()
self.port_combo.setMaximumWidth(180)
self.refresh_ports() self.refresh_ports()
self.connect_btn = QPushButton("Verbinden") self.connect_btn = QPushButton("Verbinden")
self.connect_btn.clicked.connect(self.toggle_connection) self.connect_btn.clicked.connect(self.toggle_connection)
connection_layout.addWidget(QLabel("Port:"))
connection_layout.addWidget(self.port_combo, 1)
connection_layout.addWidget(self.connect_btn)
connection_group.setLayout(connection_layout)
# Status Group
status_group = QGroupBox("Status")
status_layout = QHBoxLayout()
self.ph_label = QLabel("pH: --") self.ph_label = QLabel("pH: --")
self.ph_label.setFont(QFont('Arial', 24)) self.ph_label.setFont(QFont('Arial', 24))
self.ph_label.setAlignment(Qt.AlignmentFlag.AlignCenter) self.ph_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
@ -63,15 +64,24 @@ class PHControllerGUI(QMainWindow):
self.total_volume_label.setAlignment(Qt.AlignmentFlag.AlignCenter) self.total_volume_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.total_volume_label.setVisible(False) # Initially hidden self.total_volume_label.setVisible(False) # Initially hidden
status_layout.addWidget(self.ph_label) connection_layout.addWidget(QLabel("Port:"))
status_layout.addWidget(self.pump_status) connection_layout.addWidget(self.port_combo)
status_layout.addWidget(self.flow_rate_label) connection_layout.addWidget(self.connect_btn)
status_layout.addWidget(self.total_volume_label) connection_layout.addSpacing(10)
status_group.setLayout(status_layout) connection_layout.addWidget(self.ph_label)
connection_layout.addWidget(self.pump_status)
connection_layout.addWidget(self.flow_rate_label)
connection_layout.addWidget(self.total_volume_label)
connection_group_layout.addLayout(connection_layout)
connection_group.setLayout(connection_group_layout)
connection_group.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Maximum)
connection_group.setMaximumHeight(95)
# Control Group # Control Group
control_group = QGroupBox("Steuerung") control_group = QGroupBox("Steuerung")
control_layout = QVBoxLayout() control_layout = QVBoxLayout()
control_layout.setContentsMargins(8, 8, 8, 8)
control_layout.setSpacing(6)
# Pump Control # Pump Control
pump_control_layout = QHBoxLayout() pump_control_layout = QHBoxLayout()
@ -91,6 +101,7 @@ class PHControllerGUI(QMainWindow):
# Tube Selection # Tube Selection
tube_layout = QHBoxLayout() tube_layout = QHBoxLayout()
self.tube_combo = QComboBox() self.tube_combo = QComboBox()
self.tube_combo.setMaximumWidth(130)
self.tube_combo.addItems([ self.tube_combo.addItems([
"0.13 mm", "0.19 mm", "0.25 mm", "0.38 mm", "0.44 mm", "0.13 mm", "0.19 mm", "0.25 mm", "0.38 mm", "0.44 mm",
"0.51 mm", "0.57 mm", "0.64 mm", "0.76 mm", "0.89 mm", "0.51 mm", "0.57 mm", "0.64 mm", "0.76 mm", "0.89 mm",
@ -136,10 +147,11 @@ class PHControllerGUI(QMainWindow):
control_layout.addLayout(calibration_layout) control_layout.addLayout(calibration_layout)
control_layout.addLayout(auto_mode_layout) control_layout.addLayout(auto_mode_layout)
control_group.setLayout(control_layout) control_group.setLayout(control_layout)
control_group.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Maximum)
control_group.setMaximumHeight(185)
# Add groups to main layout # Add groups to main layout
main_layout.addWidget(connection_group) main_layout.addWidget(connection_group)
main_layout.addWidget(status_group)
main_layout.addWidget(control_group) main_layout.addWidget(control_group)
# pH Plot Group # pH Plot Group
@ -171,6 +183,7 @@ class PHControllerGUI(QMainWindow):
plot_layout.addLayout(plot_controls_layout) plot_layout.addLayout(plot_controls_layout)
plot_layout.addWidget(self.ph_plot) plot_layout.addWidget(self.ph_plot)
plot_group.setLayout(plot_layout) plot_group.setLayout(plot_layout)
plot_group.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Expanding)
main_layout.addWidget(plot_group) main_layout.addWidget(plot_group)
@ -212,8 +225,13 @@ class PHControllerGUI(QMainWindow):
titration_layout.addLayout(titration_controls_layout) titration_layout.addLayout(titration_controls_layout)
titration_layout.addWidget(self.titration_plot) titration_layout.addWidget(self.titration_plot)
titration_group.setLayout(titration_layout) titration_group.setLayout(titration_layout)
titration_group.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Expanding)
main_layout.addWidget(titration_group) main_layout.addWidget(titration_group)
main_layout.setStretch(0, 0) # Verbindung & Status
main_layout.setStretch(1, 0) # Steuerung
main_layout.setStretch(2, 3) # pH-Verlauf
main_layout.setStretch(3, 3) # Titration
# Status Bar # Status Bar
self.status_bar = QStatusBar() self.status_bar = QStatusBar()
@ -272,6 +290,31 @@ class PHControllerGUI(QMainWindow):
# Enable/disable controls based on connection # Enable/disable controls based on connection
self.set_controls_enabled(False) self.set_controls_enabled(False)
# Match the initial window size to the current screen.
self.fit_window_to_screen()
def fit_window_to_screen(self):
"""Set an initial window size that fits the available screen area and center it."""
screen = QGuiApplication.primaryScreen()
if screen is None:
self.resize(1200, 900)
return
available = screen.availableGeometry()
# Use most of the available screen while staying within sensible bounds.
target_width = min(1500, int(available.width() * 0.95))
target_height = min(1000, int(available.height() * 0.95))
target_width = max(900, min(target_width, available.width()))
target_height = max(650, min(target_height, available.height()))
self.resize(target_width, target_height)
centered_x = available.x() + (available.width() - target_width) // 2
centered_y = available.y() + (available.height() - target_height) // 2
self.move(centered_x, centered_y)
def refresh_ports(self): def refresh_ports(self):
self.port_combo.clear() self.port_combo.clear()
ports = serial.tools.list_ports.comports() ports = serial.tools.list_ports.comports()