From f4f3a69adfd307adc0959aad2ed6305e2b2c7af8 Mon Sep 17 00:00:00 2001 From: jens Date: Sat, 11 Apr 2026 23:02:24 +0200 Subject: [PATCH] Adjust GUI layout for compact header and larger plots --- gui/main.py | 89 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 23 deletions(-) diff --git a/gui/main.py b/gui/main.py index ce05541..517980a 100644 --- a/gui/main.py +++ b/gui/main.py @@ -3,9 +3,9 @@ import serial import serial.tools.list_ports from PyQt6.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, QWidget, QLabel, QPushButton, QComboBox, QDoubleSpinBox, - QGroupBox, QStatusBar, QMessageBox, QCheckBox) + QGroupBox, QStatusBar, QMessageBox, QCheckBox, QScrollArea, QSizePolicy) from PyQt6.QtCore import QTimer, Qt -from PyQt6.QtGui import QFont +from PyQt6.QtGui import QFont, QGuiApplication import matplotlib.pyplot as plt from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.figure import Figure @@ -19,32 +19,33 @@ class PHControllerGUI(QMainWindow): self.serial_connection = None self.updating_tube_combo = False # Flag to prevent recursive tube commands 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() - self.setCentralWidget(central_widget) + scroll_area.setWidget(central_widget) + self.setCentralWidget(scroll_area) main_layout = QVBoxLayout(central_widget) - # Connection Group - connection_group = QGroupBox("Verbindung") + # Connection + Status Group + 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.setContentsMargins(0, 0, 0, 0) + connection_layout.setSpacing(10) self.port_combo = QComboBox() + self.port_combo.setMaximumWidth(180) self.refresh_ports() self.connect_btn = QPushButton("Verbinden") 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.setFont(QFont('Arial', 24)) self.ph_label.setAlignment(Qt.AlignmentFlag.AlignCenter) @@ -62,16 +63,25 @@ class PHControllerGUI(QMainWindow): self.total_volume_label.setFont(QFont('Arial', 12)) self.total_volume_label.setAlignment(Qt.AlignmentFlag.AlignCenter) self.total_volume_label.setVisible(False) # Initially hidden - - status_layout.addWidget(self.ph_label) - status_layout.addWidget(self.pump_status) - status_layout.addWidget(self.flow_rate_label) - status_layout.addWidget(self.total_volume_label) - status_group.setLayout(status_layout) + + connection_layout.addWidget(QLabel("Port:")) + connection_layout.addWidget(self.port_combo) + connection_layout.addWidget(self.connect_btn) + connection_layout.addSpacing(10) + 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 = QGroupBox("Steuerung") control_layout = QVBoxLayout() + control_layout.setContentsMargins(8, 8, 8, 8) + control_layout.setSpacing(6) # Pump Control pump_control_layout = QHBoxLayout() @@ -91,6 +101,7 @@ class PHControllerGUI(QMainWindow): # Tube Selection tube_layout = QHBoxLayout() self.tube_combo = QComboBox() + self.tube_combo.setMaximumWidth(130) self.tube_combo.addItems([ "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", @@ -136,10 +147,11 @@ class PHControllerGUI(QMainWindow): control_layout.addLayout(calibration_layout) control_layout.addLayout(auto_mode_layout) control_group.setLayout(control_layout) + control_group.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Maximum) + control_group.setMaximumHeight(185) # Add groups to main layout main_layout.addWidget(connection_group) - main_layout.addWidget(status_group) main_layout.addWidget(control_group) # pH Plot Group @@ -171,6 +183,7 @@ class PHControllerGUI(QMainWindow): plot_layout.addLayout(plot_controls_layout) plot_layout.addWidget(self.ph_plot) plot_group.setLayout(plot_layout) + plot_group.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Expanding) main_layout.addWidget(plot_group) @@ -212,8 +225,13 @@ class PHControllerGUI(QMainWindow): titration_layout.addLayout(titration_controls_layout) titration_layout.addWidget(self.titration_plot) titration_group.setLayout(titration_layout) + titration_group.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Expanding) 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 self.status_bar = QStatusBar() @@ -271,6 +289,31 @@ class PHControllerGUI(QMainWindow): # Enable/disable controls based on connection 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): self.port_combo.clear()