refactored heavily

This commit is contained in:
2026-05-17 17:00:48 +02:00
parent deee78e2d5
commit dc05be751b
11 changed files with 685 additions and 638 deletions
+211
View File
@@ -0,0 +1,211 @@
# ---------------------------------------------------------------------------
# Verbindungs-Panel
# ---------------------------------------------------------------------------
import serial
from serial.tools.list_ports import comports
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QGroupBox, QVBoxLayout, QTabWidget, QWidget, QFormLayout, QComboBox, QPushButton, \
QHBoxLayout, QLineEdit, QSpinBox
from lru_store import LruStore
from transport_network import TcpTransport
from transport_serial import SerialTransport
# ---------------------------------------------------------------------------
# Stil-Konstante
# ---------------------------------------------------------------------------
FIELD_STYLE = """
QLineEdit, QComboBox, QSpinBox {
background-color: #0d1b2a;
color: #cccccc;
border: 1px solid #2a4a6a;
padding: 3px 6px;
border-radius: 3px;
}
QComboBox QAbstractItemView {
background-color: #0d1b2a;
color: #cccccc;
selection-background-color: #1a3a5c;
}
"""
class ConnectionPanel(QGroupBox):
connect_requested = pyqtSignal(object, str)
disconnect_requested = pyqtSignal()
def __init__(self, parent=None):
super().__init__("Verbindung", parent)
self.setStyleSheet("""
QGroupBox { color: #7ab7d4; border: 1px solid #2a4a6a;
border-radius: 4px; margin-top: 8px; padding: 6px; }
QGroupBox::title { subcontrol-origin: margin; left: 8px; }
""" + FIELD_STYLE)
self._lru = LruStore(max_size=5)
self._build_ui()
def _build_ui(self):
root = QVBoxLayout(self)
self._tabs = QTabWidget()
self._tabs.setStyleSheet("""
QTabBar::tab { background: #1a3a5c; color: #cccccc;
padding: 4px 12px; border-radius: 3px; }
QTabBar::tab:selected { background: #2a5a8c; color: #ffffff; }
""")
# ── Tab: Seriell ─────────────────────────────────────────────────────
serial_widget = QWidget()
serial_form = QFormLayout(serial_widget)
serial_form.setContentsMargins(6, 6, 6, 6)
self._port_combo = QComboBox()
self._port_combo.setMinimumWidth(200)
refresh_btn = QPushButton("")
refresh_btn.setFixedWidth(28)
refresh_btn.clicked.connect(self._refresh_ports)
port_row = QHBoxLayout()
port_row.addWidget(self._port_combo)
port_row.addWidget(refresh_btn)
serial_form.addRow("Port:", port_row)
self._baud_combo = QComboBox()
for b in ("9600", "19200", "38400", "57600", "115200", "230400", "460800"):
self._baud_combo.addItem(b)
self._baud_combo.setCurrentText("9600")
serial_form.addRow("Baudrate:", self._baud_combo)
self._tabs.addTab(serial_widget, "🔌 Seriell")
# ── Tab: TCP/IP ───────────────────────────────────────────────────────
tcp_widget = QWidget()
tcp_layout = QVBoxLayout(tcp_widget)
tcp_layout.setContentsMargins(6, 6, 6, 6)
tcp_layout.setSpacing(6)
# LRU-Gruppe
lru_group = QGroupBox("Letzte Verbindungen")
lru_group.setStyleSheet("""
QGroupBox { color: #7ab7d4; border: 1px solid #2a4a6a;
border-radius: 3px; margin-top: 6px; padding: 4px; }
QGroupBox::title { subcontrol-origin: margin; left: 6px; }
""" + FIELD_STYLE)
lru_layout = QHBoxLayout(lru_group)
lru_layout.setContentsMargins(4, 10, 4, 4)
self._lru_combo = QComboBox()
self._lru_combo.setMinimumWidth(220)
self._lru_combo.setPlaceholderText(" Frühere Verbindung wählen ")
self._lru_combo.currentIndexChanged.connect(self._on_lru_selected)
lru_layout.addWidget(self._lru_combo, stretch=1)
clear_btn = QPushButton("🗑")
clear_btn.setFixedWidth(28)
clear_btn.setToolTip("Liste leeren")
clear_btn.clicked.connect(self._clear_lru)
lru_layout.addWidget(clear_btn)
tcp_layout.addWidget(lru_group)
# Manuelle Eingabe
tcp_form = QFormLayout()
tcp_form.setSpacing(6)
self._tcp_host = QLineEdit()
self._tcp_host.setPlaceholderText("IP-Adresse oder Hostname")
tcp_form.addRow("Host:", self._tcp_host)
self._tcp_port = QSpinBox()
self._tcp_port.setRange(1, 65535)
self._tcp_port.setValue(4001)
tcp_form.addRow("Port:", self._tcp_port)
self._tcp_timeout = QSpinBox()
self._tcp_timeout.setRange(1, 30)
self._tcp_timeout.setValue(5)
self._tcp_timeout.setSuffix(" s")
tcp_form.addRow("Timeout:", self._tcp_timeout)
tcp_layout.addLayout(tcp_form)
tcp_layout.addStretch()
self._tabs.addTab(tcp_widget, "🌐 TCP/IP")
root.addWidget(self._tabs)
# Verbinden-Knopf
btn_row = QHBoxLayout()
self._connect_btn = QPushButton("▶ Verbinden")
self._connect_btn.clicked.connect(self._on_connect_clicked)
btn_row.addStretch()
btn_row.addWidget(self._connect_btn)
root.addLayout(btn_row)
self._refresh_ports()
self._refresh_lru_combo()
# ── LRU ──────────────────────────────────────────────────────────────────
def _refresh_lru_combo(self):
self._lru_combo.blockSignals(True)
self._lru_combo.clear()
for entry in self._lru.entries():
self._lru_combo.addItem(entry)
self._lru_combo.setCurrentIndex(-1)
self._lru_combo.blockSignals(False)
def _on_lru_selected(self, index: int):
if index < 0:
return
entry = self._lru_combo.currentText()
if not entry:
return
try:
host, port = self._lru.parse(entry)
self._tcp_host.setText(host)
self._tcp_port.setValue(port)
except (ValueError, IndexError):
pass
def _clear_lru(self):
self._lru.clear()
self._refresh_lru_combo()
# ── Seriell ───────────────────────────────────────────────────────────────
def _refresh_ports(self):
self._port_combo.clear()
for p in comports():
self._port_combo.addItem(f"{p.device} {p.description}", p.device)
if self._port_combo.count() == 0:
self._port_combo.addItem("Kein Port gefunden", None)
# ── Verbinden ─────────────────────────────────────────────────────────────
def _on_connect_clicked(self):
if self._connect_btn.text().startswith(""):
self.disconnect_requested.emit()
return
if self._tabs.currentIndex() == 0:
port = self._port_combo.currentData()
baud = int(self._baud_combo.currentText())
if not port:
return
factory = lambda p=port, b=baud: SerialTransport(p, b)
label = f"{port} @ {baud} Baud"
else:
host = self._tcp_host.text().strip()
port = self._tcp_port.value()
timeout = self._tcp_timeout.value()
if not host:
return
self._lru.add(host, port)
self._refresh_lru_combo()
factory = lambda h=host, p=port, t=timeout: TcpTransport(h, p, t)
label = f"{host}:{port}"
self.connect_requested.emit(factory, label)
def set_connected(self, connected: bool):
self._connect_btn.setText("■ Trennen" if connected else "▶ Verbinden")
self._tabs.setEnabled(not connected)