Compare commits
2 Commits
0edcc108bc
...
bacbe09641
| Author | SHA1 | Date | |
|---|---|---|---|
| bacbe09641 | |||
| aad524e182 |
70
src/gui.py
70
src/gui.py
@@ -55,7 +55,6 @@ class DHCPApp(tk.Frame):
|
|||||||
def __init__(self, master: tk.Tk) -> None:
|
def __init__(self, master: tk.Tk) -> None:
|
||||||
super().__init__(master)
|
super().__init__(master)
|
||||||
master.title("Simple DHCP Server (Lab)")
|
master.title("Simple DHCP Server (Lab)")
|
||||||
master.minsize(700, 500)
|
|
||||||
self.pack(fill="both", expand=True, padx=12, pady=12)
|
self.pack(fill="both", expand=True, padx=12, pady=12)
|
||||||
|
|
||||||
# Single server instance
|
# Single server instance
|
||||||
@@ -68,7 +67,7 @@ class DHCPApp(tk.Frame):
|
|||||||
# Zeile 0
|
# Zeile 0
|
||||||
ttk.Label(form, text="Interface:").grid(row=0, column=0, sticky="w")
|
ttk.Label(form, text="Interface:").grid(row=0, column=0, sticky="w")
|
||||||
self.if_var = tk.StringVar()
|
self.if_var = tk.StringVar()
|
||||||
self.if_menu = ttk.OptionMenu(form, self.if_var, None, *utils.get_network_interfaces(), command=self.on_iface_change)
|
self.if_menu = ttk.OptionMenu(form, self.if_var, None, command=self.on_iface_change)
|
||||||
self.if_menu.grid(row=0, column=1, sticky="ew", padx=(6, 16))
|
self.if_menu.grid(row=0, column=1, sticky="ew", padx=(6, 16))
|
||||||
form.columnconfigure(1, weight=1)
|
form.columnconfigure(1, weight=1)
|
||||||
|
|
||||||
@@ -98,8 +97,10 @@ class DHCPApp(tk.Frame):
|
|||||||
btns.pack(fill="x", pady=(8, 8))
|
btns.pack(fill="x", pady=(8, 8))
|
||||||
self.btn_start = ttk.Button(btns, text="Start", command=self.start_server)
|
self.btn_start = ttk.Button(btns, text="Start", command=self.start_server)
|
||||||
self.btn_stop = ttk.Button(btns, text="Stop", command=self.stop_server, state="disabled")
|
self.btn_stop = ttk.Button(btns, text="Stop", command=self.stop_server, state="disabled")
|
||||||
|
self.btn_rescan = ttk.Button(btns, text="Interfaces neu scannen", command=self.rescan_interfaces)
|
||||||
self.btn_start.pack(side="left")
|
self.btn_start.pack(side="left")
|
||||||
self.btn_stop.pack(side="left", padx=(8, 0))
|
self.btn_stop.pack(side="left", padx=(8, 0))
|
||||||
|
self.btn_rescan.pack(side="left", padx=(8, 0))
|
||||||
|
|
||||||
# --- Clients & Logs Paned Layout ---
|
# --- Clients & Logs Paned Layout ---
|
||||||
paned = ttk.Panedwindow(self, orient="horizontal")
|
paned = ttk.Panedwindow(self, orient="horizontal")
|
||||||
@@ -109,24 +110,21 @@ class DHCPApp(tk.Frame):
|
|||||||
left = ttk.Labelframe(paned, text="Aktive Clients / Leases")
|
left = ttk.Labelframe(paned, text="Aktive Clients / Leases")
|
||||||
self.clients = tk.Listbox(left, height=12)
|
self.clients = tk.Listbox(left, height=12)
|
||||||
self.clients.pack(fill="both", expand=True, padx=6, pady=6)
|
self.clients.pack(fill="both", expand=True, padx=6, pady=6)
|
||||||
paned.add(left, weight=1)
|
paned.add(left, weight=1, minsize=240)
|
||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
right = ttk.Labelframe(paned, text="Log")
|
right = ttk.Labelframe(paned, text="Log")
|
||||||
self.log = tk.Text(right, height=12, state="disabled")
|
self.log = tk.Text(right, height=12, state="disabled")
|
||||||
self.log.pack(fill="both", expand=True, padx=6, pady=6)
|
self.log.pack(fill="both", expand=True, padx=6, pady=6)
|
||||||
paned.add(right, weight=2)
|
paned.add(right, weight=2, minsize=360)
|
||||||
|
|
||||||
# --- Status bar ---
|
# --- Status bar ---
|
||||||
self.status_var = tk.StringVar(value="Bereit.")
|
self.status_var = tk.StringVar(value="Bereit.")
|
||||||
status = ttk.Label(self, textvariable=self.status_var, anchor="w", relief="sunken")
|
status = ttk.Label(self, textvariable=self.status_var, anchor="w", relief="sunken")
|
||||||
status.pack(fill="x", side="bottom")
|
status.pack(fill="x", side="bottom")
|
||||||
|
|
||||||
# initial iface autofill (if any interface exists)
|
self._refresh_interface_list(initial=True)
|
||||||
ifaces = utils.get_network_interfaces()
|
self._apply_min_sizes()
|
||||||
if ifaces:
|
|
||||||
self.if_var.set(ifaces[0])
|
|
||||||
self.on_iface_change(ifaces[0])
|
|
||||||
|
|
||||||
# periodic refresh
|
# periodic refresh
|
||||||
self.after(400, self._refresh)
|
self.after(400, self._refresh)
|
||||||
@@ -134,7 +132,12 @@ class DHCPApp(tk.Frame):
|
|||||||
# -------------------- UI logic --------------------
|
# -------------------- UI logic --------------------
|
||||||
def on_iface_change(self, _sel=None):
|
def on_iface_change(self, _sel=None):
|
||||||
iface = self.if_var.get().strip()
|
iface = self.if_var.get().strip()
|
||||||
|
if not iface:
|
||||||
|
self._clear_iface_fields()
|
||||||
|
return
|
||||||
|
|
||||||
ip, mask = utils.get_iface_ipv4_config(iface)
|
ip, mask = utils.get_iface_ipv4_config(iface)
|
||||||
|
self._clear_iface_fields()
|
||||||
if ip:
|
if ip:
|
||||||
self.ip_var.set(ip)
|
self.ip_var.set(ip)
|
||||||
# sinnvolles Default: Primary DNS = Interface-IP
|
# sinnvolles Default: Primary DNS = Interface-IP
|
||||||
@@ -150,9 +153,58 @@ class DHCPApp(tk.Frame):
|
|||||||
self.mask_entry.configure(state=state)
|
self.mask_entry.configure(state=state)
|
||||||
self.dns1_entry.configure(state=state)
|
self.dns1_entry.configure(state=state)
|
||||||
self.dns2_entry.configure(state=state)
|
self.dns2_entry.configure(state=state)
|
||||||
|
self.btn_rescan.configure(state=state)
|
||||||
self.btn_start.configure(state="normal" if enabled else "disabled")
|
self.btn_start.configure(state="normal" if enabled else "disabled")
|
||||||
self.btn_stop.configure(state="disabled" if enabled else "normal")
|
self.btn_stop.configure(state="disabled" if enabled else "normal")
|
||||||
|
|
||||||
|
def _clear_iface_fields(self) -> None:
|
||||||
|
self.ip_var.set("")
|
||||||
|
self.mask_var.set("")
|
||||||
|
self.dns1_var.set("")
|
||||||
|
self.dns2_var.set("")
|
||||||
|
|
||||||
|
def _select_iface(self, iface: str) -> None:
|
||||||
|
self.if_var.set(iface)
|
||||||
|
self.on_iface_change(iface)
|
||||||
|
|
||||||
|
def _refresh_interface_list(self, initial: bool = False) -> None:
|
||||||
|
interfaces = utils.get_network_interfaces()
|
||||||
|
current = self.if_var.get().strip()
|
||||||
|
menu = self.if_menu["menu"]
|
||||||
|
menu.delete(0, "end")
|
||||||
|
for iface in interfaces:
|
||||||
|
menu.add_command(label=iface, command=lambda val=iface: self._select_iface(val))
|
||||||
|
|
||||||
|
if current in interfaces:
|
||||||
|
selection = current
|
||||||
|
elif interfaces:
|
||||||
|
selection = interfaces[0]
|
||||||
|
else:
|
||||||
|
selection = ""
|
||||||
|
|
||||||
|
if selection:
|
||||||
|
self._select_iface(selection)
|
||||||
|
if not initial:
|
||||||
|
self.status_var.set(f"{len(interfaces)} Interface(s) geladen.")
|
||||||
|
else:
|
||||||
|
self.if_var.set("")
|
||||||
|
self._clear_iface_fields()
|
||||||
|
if not initial:
|
||||||
|
self.status_var.set("Keine Netzwerk-Interfaces gefunden.")
|
||||||
|
|
||||||
|
def _apply_min_sizes(self) -> None:
|
||||||
|
# Ensure window cannot shrink below a comfortable layout
|
||||||
|
self.update_idletasks()
|
||||||
|
min_w = max(self.winfo_reqwidth() + 16, 720)
|
||||||
|
min_h = max(self.winfo_reqheight() + 16, 540)
|
||||||
|
self.master.minsize(min_w, min_h)
|
||||||
|
|
||||||
|
def rescan_interfaces(self) -> None:
|
||||||
|
if self.server and self.server.is_running():
|
||||||
|
messagebox.showinfo("Server läuft", "Stoppe den Server, bevor du Interfaces neu scannst.")
|
||||||
|
return
|
||||||
|
self._refresh_interface_list()
|
||||||
|
|
||||||
def start_server(self) -> None:
|
def start_server(self) -> None:
|
||||||
if self.server and self.server.is_running():
|
if self.server and self.server.is_running():
|
||||||
messagebox.showinfo("Info", "Server läuft bereits.")
|
messagebox.showinfo("Info", "Server läuft bereits.")
|
||||||
|
|||||||
Reference in New Issue
Block a user