diff --git a/main.py b/main.py index 00c6513..13e2f20 100644 --- a/main.py +++ b/main.py @@ -1,1837 +1,1837 @@ -import tkinter as tk -from tkinter import messagebox -import math -import platform -import os -import sys -import datetime -import json -import sqlite3 -import threading -import urllib.request -import webbrowser - -VERSION_URL = "https://cloud.survivalful.de/s/ydLwqwXdJEj8XwR/download" - -def fetch_version_info(): - try: - with urllib.request.urlopen(VERSION_URL, timeout=5) as response: - return json.loads(response.read().decode()) - except Exception: - return None - -def version_is_newer(latest, current): - try: - l_parts = list(map(int, latest.split('.'))) - c_parts = list(map(int, current.split('.'))) - return l_parts > c_parts - except Exception: - return latest != current - - -def resource_path(relative_path): - if hasattr(sys, '_MEIPASS'): - return os.path.join(sys._MEIPASS, relative_path) - return os.path.join(os.path.dirname(__file__), relative_path) - -APP_DIR = os.path.join(os.environ.get("LOCALAPPDATA", os.path.expanduser("~")), "Survivalcalc") -SETTINGS_FILE = os.path.join(APP_DIR, "settings.json") -DB_FILE = os.path.join(APP_DIR, "history.db") -os.makedirs(APP_DIR, exist_ok=True) - -LANG = { - "DE": { - "menu": "Menü", - "info": "Info", - "calculator": "Rechner", - "shape": "Formen", - "area": "Fläche", - "volume": "Volumen", - "settings": "Einstellungen", - "exit": "Beenden", - "history": "Verlauf", - "appearance": "Darstellung", - "dark_mode": "Dark Mode", - "toggle": "Wechseln", - "on": "Ein ✓", - "off": "Aus", - "rounding": "Rundung", - "rounding_active": "Rundung aktiv", - "decimal_places": "Nachkommastellen", - "units": "Einheiten", - "default_unit": "Standardeinheit", - "language": "Sprache", - "delete_history": "Verlauf löschen", - "reset_settings": "Einstellungen zurücksetzen", - "confirm_del_h": "Verlauf wirklich löschen?", - "confirm_reset": "Einstellungen wirklich zurücksetzen?", - "yes": "Ja", - "no": "Nein", - "app_info": "App", - "support": "Support", - "system": "System", - "version": "Version", - "release": "Release", - "status": "Status", - "license": "Lizenz", - "installed": "Installiert am", - "website": "Website", - "email": "E-Mail", - "os": "Betriebssystem", - "os_version": "Version", - "arch": "Architektur", - "python": "Python-Version", - "error": "Bitte eine gültige Zahl eingeben.", - "area_square": "Fläche – Quadrat", - "area_rect": "Fläche – Rechteck", - "area_circle": "Fläche – Kreis", - "area_tri": "Fläche – Dreieck", - "area_trap": "Fläche – Trapez", - "area_cyl": "Fläche – Zylinder", - "area_sphere": "Fläche – Kugel", - "area_cone": "Fläche – Kegel", - "vol_cube": "Volumen – Würfel", - "vol_rect": "Volumen – Quader", - "vol_cyl": "Volumen – Zylinder", - "vol_cone": "Volumen – Kegel", - "vol_sphere": "Volumen – Kugel", - "vol_tetra": "Volumen – Tetraeder", - "vol_trap": "Volumen – Trapezprisma", - "side": "Seite", - "radius": "Radius r:", - "diameter": "Durchmesser d:", - "height": "Höhe h:", - "width": "Breite w:", - "length": "Länge l:", - "base": "Grundlinie g:", - "slant": "Mantellinie l:", - "depth": "Tiefe i:", - "with_radius": "Mit Radius", - "with_diameter": "Mit Durchmesser", - "result_area": "A", - "result_vol": "V", - "cube": "Würfel", - "rect_prism": "Quader", - "cylinder": "Zylinder", - "cone": "Kegel", - "sphere": "Kugel", - "tetrahedron": "Tetraeder", - "trap_prism": "Trapezprisma", - "square": "Quadrat", - "rectangle": "Rechteck", - "circle": "Kreis", - "triangle": "Dreieck", - "trapezoid": "Trapez", - "electricity": "Strom", - "result_voltage": "Spannung U", - "result_current": "Strom I", - "result_resistance": "Wiederstand R", - "voltage": "Spannung", - "current": "Strom", - "resistance": "Widerstand", - "power": "Leistung", - "u": "Spannung U", - "i": "Strom I", - "r": "Widerstand R", - "p": "Leistung P", - "u_i_r": "Mit Widerstand R und Strom I", - "u_p_i": "Mit Widerstand R und Leistung P", - "u_r_p": "Mit Leistung P und Strom I", - "update_available_title": "Update Verfügbar!", - "update_available_msg": ( - "Eine neue Version ({LATEST}) von Survivalcalc ist verfügbar.\n\n" - "Änderungen:\n{CHANGELOG}\n\n" - "Möchtest du die Download-Website öffnen?" - ), - "update_check_error": "Fehler bei der Update-Prüfung.", - }, - "EN": { - "menu": "Menu", - "info": "Info", - "calculator": "Calculator", - "shape": "Shapes", - "area": "Area", - "volume": "Volume", - "settings": "Settings", - "exit": "Exit", - "history": "History", - "appearance": "Appearance", - "dark_mode": "Dark Mode", - "toggle": "Toggle", - "on": "On ✓", - "off": "Off", - "rounding": "Rounding", - "rounding_active": "Rounding active", - "decimal_places": "Decimal places", - "units": "Units", - "default_unit": "Default unit", - "language": "Language", - "delete_history": "Delete history", - "reset_settings": "Reset settings", - "confirm_del_h": "Really delete history?", - "confirm_reset": "Really reset settings?", - "yes": "Yes", - "no": "No", - "app_info": "App", - "support": "Support", - "system": "System", - "version": "Version", - "release": "Release", - "status": "Status", - "license": "License", - "installed": "Installed on", - "website": "Website", - "email": "E-Mail", - "os": "Operating system", - "os_version": "Version", - "arch": "Architecture", - "python": "Python version", - "error": "Please enter a valid number.", - "area_square": "Area – Square", - "area_rect": "Area – Rectangle", - "area_circle": "Area – Circle", - "area_tri": "Area – Triangle", - "area_trap": "Area – Trapezoid", - "area_cyl": "Area – Cylinder", - "area_sphere": "Area – Sphere", - "area_cone": "Area – Cone", - "vol_cube": "Volume – Cube", - "vol_rect": "Volume – Rectangular prism", - "vol_cyl": "Volume – Cylinder", - "vol_cone": "Volume – Cone", - "vol_sphere": "Volume – Sphere", - "vol_tetra": "Volume – Tetrahedron", - "vol_trap": "Volume – Trapezoidal prism", - "side": "Side", - "radius": "Radius r:", - "diameter": "Diameter d:", - "height": "Height h:", - "width": "Width w:", - "length": "Length l:", - "base": "Base g:", - "slant": "Slant l:", - "depth": "Depth i:", - "with_radius": "With radius", - "with_diameter": "With diameter", - "result_area": "A", - "result_vol": "V", - "cube": "Cube", - "rect_prism": "Rect. prism", - "cylinder": "Cylinder", - "cone": "Cone", - "sphere": "Sphere", - "tetrahedron": "Tetrahedron", - "trap_prism": "Trapezoidal prism", - "square": "Square", - "rectangle": "Rectangle", - "circle": "Circle", - "triangle": "Triangle", - "trapezoid": "Trapezoid", - "electricity": "Electricity", - "voltage": "Voltage", - "current": "Current", - "resistance": "Resistance", - "power": "Power", - "u": "Voltage U", - "i": "Current I", - "r": "Resistance R", - "p": "Power P", - "u_i_r": "With Resistance R and Current I", - "u_p_i": "With Resistance R and Power P", - "u_r_p": "With Power P and Current I", - "i_u_r": "With Voltage U and Resistance R", - "i_p_u": "With Voltage U and Power P", - "i_r_p": "With Power P and Resistance R", - "r_u_i": "With Voltage U and Current I", - "r_u_p": "With Voltage U and Power P", - "r_p_i": "With Power P and Current I", - "update_available_title": "Update Available!", - "update_available_msg": ( - "A new version ({LATEST}) of Survivalcalc is available.\n\n" - "Changelog:\n{CHANGELOG}\n\n" - "Do you want to open the download website?" - ), - "update_check_error": "Error during update check.", - - } -} - -def t(key, **kwargs): - text = LANG[language].get(key, key) - try: - for k, v in kwargs.items(): - text = text.replace("{" + k + "}", str(v)) - except Exception: - pass - return text - -def get_install_date(): - """Liest das echte Installationsdatum aus der Registry (vom Installer gespeichert).""" - try: - import winreg - key_path = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Survivalcalc" - key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path) - install_date_str = winreg.QueryValueEx(key, "InstallDate")[0] - winreg.CloseKey(key) - return install_date_str - except Exception: - # Fallback: Nutze die Änderungszeit der Anwendung - try: - exe_path = os.path.join(os.environ.get("LOCALAPPDATA", os.path.expanduser("~")), "SurvivalCalc", "main.exe") - if os.path.exists(exe_path): - mtime = os.path.getmtime(exe_path) - return datetime.datetime.fromtimestamp(mtime).strftime("%d.%m.%Y %H:%M") - except Exception: - pass - # Fallback: Aktuelles Datum - return datetime.datetime.now().strftime("%d.%m.%Y %H:%M") - - -app_version = "1.0.2" -app_release = "24.3.2026" -app_status = "Stable" -dev_e_mail = "team@survivalful.de" -dev_website = "https://Survivalful.de/" -app_license = "GPL License © 2026 Survivalful" -sys_system = platform.system() -sys_version = platform.release() -sys_machine = platform.machine() -sys_python = platform.python_version() -install_date = get_install_date() - -DEFAULT_SETTINGS = { - "bg_dark": True, - "round_num": 2, - "round_en": True, - "default_unit": "m", - "language": "EN", -} - -DEBUG = True - -def load_settings(): - global bg_dark, round_num, round_en, default_unit, language, bg, fg - if os.path.exists(SETTINGS_FILE): - with open(SETTINGS_FILE, "r") as f: - s = json.load(f) - else: - s = DEFAULT_SETTINGS.copy() - bg_dark = s.get("bg_dark", DEFAULT_SETTINGS["bg_dark"]) - round_num = s.get("round_num", DEFAULT_SETTINGS["round_num"]) - round_en = s.get("round_en", DEFAULT_SETTINGS["round_en"]) - default_unit = s.get("default_unit", DEFAULT_SETTINGS["default_unit"]) - language = s.get("language", DEFAULT_SETTINGS["language"]) - bg = 'black' if bg_dark else 'white' - fg = 'white' if bg_dark else 'black' - -def save_settings(): - with open(SETTINGS_FILE, "w") as f: - json.dump({ - "bg_dark": bg_dark, - "round_num": round_num, - "round_en": round_en, - "default_unit": default_unit, - "language": language, - }, f, indent=2) - -def init_db(): - con = sqlite3.connect(DB_FILE) - con.execute("""CREATE TABLE IF NOT EXISTS history ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - expr TEXT, - result TEXT, - timestamp TEXT - )""") - con.commit() - con.close() - -def db_add(expr, result): - con = sqlite3.connect(DB_FILE) - con.execute("INSERT INTO history (expr, result, timestamp) VALUES (?,?,?)", - (expr, str(result), datetime.datetime.now().strftime("%d.%m.%Y %H:%M:%S"))) - con.commit() - con.close() - -def db_get_last(n=3): - con = sqlite3.connect(DB_FILE) - rows = con.execute( - "SELECT expr, result FROM history ORDER BY id DESC LIMIT ?", (n,) - ).fetchall() - con.close() - return rows - -def db_clear(): - con = sqlite3.connect(DB_FILE) - con.execute("DELETE FROM history") - con.commit() - con.close() - -load_settings() -init_db() - -def check_for_updates(): - try: - info = fetch_version_info() - if not info: - return - - latest_version = info.get("version") - changelog = info.get("changelog", "Keine Informationen verfügbar.") - download_url = info.get("installer_url") - - if not (latest_version and version_is_newer(latest_version, app_version)): - return - - def show_update_dialog(): - title = t("update_available_title") - message = t("update_available_msg", LATEST=latest_version, CHANGELOG=changelog) - - if not messagebox.askyesno(title, message): - return - - win = tk.Toplevel(root) - win.title("Update wird heruntergeladen...") - win.geometry("360x120") - win.resizable(False, False) - win.config(bg=bg) - win.grab_set() - - tk.Label(win, text=f"Version {latest_version} wird heruntergeladen...", - bg=bg, fg=fg, font=("Arial", 11)).pack(pady=(18, 6)) - - progress = tk.DoubleVar() - bar = tk.Scale(win, variable=progress, from_=0, to=100, - orient="horizontal", state="disabled", - bg=bg, fg=fg, troughcolor="#2c2c2e", - highlightthickness=0, relief="flat", sliderrelief="flat") - bar.pack(fill="x", padx=24) - - status_lbl = tk.Label(win, text="0%", bg=bg, fg="#888888", font=("Arial", 10)) - status_lbl.pack() - - def do_download(): - try: - import tempfile - tmp_dir = tempfile.gettempdir() - installer_path = os.path.join(tmp_dir, "Survivalcalc_Installer.exe") - - def reporthook(block_num, block_size, total_size): - if total_size > 0: - pct = min(100, block_num * block_size * 100 / total_size) - progress.set(pct) - status_lbl.config(text=f"{int(pct)}%") - win.update_idletasks() - - urllib.request.urlretrieve(download_url, installer_path, reporthook) - - win.destroy() - - import subprocess - subprocess.Popen([installer_path]) - root.quit() - - except Exception as e: - win.destroy() - messagebox.showerror("Fehler", f"Download fehlgeschlagen:\n{e}") - - threading.Thread(target=do_download, daemon=True).start() - - root.after(0, show_update_dialog) - - except Exception as e: - print(f"Update-Check fehlgeschlagen: {e}") - - -UNIT_FACTORS = { - "pm": 1e-12, "nm": 1e-9, "μm": 1e-6, "mm": 0.001, "cm": 0.01, "dm": 0.1, - "m": 1.0, "km": 1000, "Mm": 1e6, "Gm": 1e9 -} -UNITS = list(UNIT_FACTORS.keys()) - -ELECTRICITY_PREFIXES = { - "p": 1e-12, "n": 1e-9, "μ": 1e-6, "m": 0.001, "c": 0.01, "d": 0.1, - "": 1, "k": 1000, "M": 1e6, "G": 1e9 -} -VOLTAGE_UNITS = ["pV", "nV", "μV", "mV", "V", "kV", "MV", "GV"] -CURRENT_UNITS = ["pA", "nA", "μA", "mA", "A", "kA", "MA", "GA"] -RESISTANCE_UNITS = ["pΩ", "nΩ", "μΩ", "mΩ", "Ω", "kΩ", "MΩ", "GΩ"] -POWER_UNITS = ["pW", "nW", "μW", "mW", "W", "kW", "MW", "GW"] - -COLOR_DIGITS = { - "Black": 0, "Brown": 1, "Red": 2, "Orange": 3, "Yellow": 4, - "Green": 5, "Blue": 6, "Violet": 7, "Grey": 8, "White": 9 -} -COLOR_MULTIPLIER = { - "Black": 1, "Brown": 10, "Red": 100, "Orange": 1_000, "Yellow": 10_000, - "Green": 100_000, "Blue": 1_000_000, "Violet": 10_000_000, "Grey": 100_000_000, - "White": 1_000_000_000, "Gold": 0.1, "Silver": 0.01 -} -COLOR_TOLERANCE = { - "Brown": "±1%", "Red": "±2%", "Green": "±0.5%", "Blue": "±0.25%", - "Violet": "±0.1%", "Grey": "±0.05%", "Gold": "±5%", "Silver": "±10%", - "None": "±20%" -} - -COLOR_HEX = { - "Black": "#000000", "Brown": "#8B4513", "Red": "#FF0000", "Orange": "#FFA500", - "Yellow": "#FFFF00", "Green": "#008000", "Blue": "#0000FF", "Violet": "#8A2BE2", - "Grey": "#808080", "White": "#FFFFFF", "Gold": "#D4AF37", "Silver": "#C0C0C0", "None": "#CCCCCC" -} - -def half(first, last): - return first / last - -def make_section(parent, title, row): - parent.rowconfigure(row, weight=0) - f = tk.Frame(parent, bg=bg) - f.grid(row=row, column=0, columnspan=3, sticky="ew", padx=12, pady=(16, 4)) - tk.Label(f, text=title, bg=bg, fg="#7c5cbf", - font=("Arial", 10, "bold"), anchor="w").pack(side="left") - tk.Frame(f, bg="#333333" if bg_dark else "#cccccc", - height=1).pack(side="left", fill="x", expand=True, padx=(8, 0)) - -def make_input_row(parent, label_text, var, row, unit_var=None, units=UNITS): - parent.rowconfigure(row, weight=0) - parent.rowconfigure(row + 1, weight=0) - tk.Label(parent, text=label_text, bg=bg, fg=fg, - font=("Arial", 11), anchor="w").grid( - row=row, column=0, sticky="nw", padx=16, pady=(8, 0)) - row_frame = tk.Frame(parent, bg=bg) - row_frame.grid(row=row+1, column=0, sticky="ew", padx=16, pady=(2, 4)) - row_frame.columnconfigure(0, weight=1) - entry = tk.Entry(row_frame, textvariable=var, - bg="#2c2c2e" if bg_dark else "#f0f0f0", - fg=fg, insertbackground=fg, - font=("Arial", 14), relief="flat", bd=0, - highlightthickness=1, - highlightbackground="#444" if bg_dark else "#ccc", - highlightcolor="#7c5cbf") - entry.grid(row=0, column=0, sticky="ew", ipady=6) - if unit_var is not None: - um = tk.OptionMenu(row_frame, unit_var, *units) - um.config(bg="#2c2c2e" if bg_dark else "#f0f0f0", fg=fg, - activebackground="#3a3a3c", activeforeground=fg, - relief="flat", highlightthickness=0, - font=("Arial", 11), width=4) - um["menu"].config(bg="#2c2c2e" if bg_dark else "#f0f0f0", fg=fg) - um.grid(row=0, column=1, padx=(4, 0), ipady=3) - return entry - -def make_result_label(parent, row): - parent.rowconfigure(row, weight=0) - r = tk.Label(parent, text="", bg=bg, - fg="#bf9fff" if bg_dark else "#7c5cbf", - font=("Arial", 16, "bold"), anchor="w") - r.grid(row=row, column=0, sticky="nw", padx=16, pady=(4, 12)) - return r - -def make_title_label(parent, text, symbol, row): - parent.rowconfigure(row, weight=0) - frame = tk.Frame(parent, bg=bg) - frame.grid(row=row, column=0, sticky="nw", padx=16, pady=(12, 2)) - tk.Label(frame, text=text, bg=bg, fg=fg, - font=("Arial", 13, "bold"), anchor="w").pack(side="left") - tk.Label(frame, text=f" {symbol}", bg=bg, - fg="#888888" if bg_dark else "#aaaaaa", - font=("Arial", 11), anchor="w").pack(side="left") - return frame - -def get_m(var, unit_var): - return float(var.get()) * UNIT_FACTORS[unit_var.get()] - -def get_electricity_value(var, unit_var): - unit = unit_var.get() - prefix = unit[:-1] if len(unit) > 1 else "" - base_unit = unit[-1] - factor = ELECTRICITY_PREFIXES.get(prefix, 1) - return float(var.get()) * factor - -def format_result(val, unit_var): - return val / (UNIT_FACTORS[unit_var.get()] ** 2) - -def format_vol(val, unit_var): - return val / (UNIT_FACTORS[unit_var.get()] ** 3) - -def clear_frame(): - for widget in content_frame.winfo_children(): - widget.destroy() - for i in range(20): - content_frame.rowconfigure(i, weight=0) - content_frame.columnconfigure(0, weight=1) - -def make_scroll_frame(parent): - canvas = tk.Canvas(parent, bg=bg, highlightthickness=0) - scrollbar = tk.Scrollbar(parent, orient="vertical", command=canvas.yview) - inner = tk.Frame(canvas, bg=bg) - inner.bind("", - lambda e: canvas.configure(scrollregion=canvas.bbox("all"))) - canvas.create_window((0, 0), window=inner, anchor="nw") - canvas.configure(yscrollcommand=scrollbar.set) - canvas.pack(side="left", fill="both", expand=True) - scrollbar.pack(side="right", fill="y") - def on_mousewheel(event): - canvas.yview_scroll(int(-1*(event.delta/120)), "units") - canvas.bind_all("", on_mousewheel) - return inner - -def rebuild_menu(): - menubar.delete(0, "end") - menu.delete(0, "end") - shape_area.delete(0, "end") - shape_volume.delete(0, "end") - shape.delete(0, "end") - areacircle.delete(0, "end") - areacylinder.delete(0, "end") - areasphere.delete(0, "end") - areacone.delete(0, "end") - volumeclinder.delete(0, "end") - volumecone.delete(0, "end") - volumesphere.delete(0, "end") - electricity_menu.delete(0, "end") - voltage.delete(0, "end") - amper.delete(0, "end") - resistance.delete(0, "end") - power.delete(0, "end") - - areacircle.add_command(label=t("with_radius"), command=area_circle_radius) - areacircle.add_command(label=t("with_diameter"), command=area_circle_diameter) - areacylinder.add_command(label=t("with_radius"), command=area_cylinder_radius) - areacylinder.add_command(label=t("with_diameter"), command=area_cylinder_diameter) - areasphere.add_command(label=t("with_radius"), command=area_sphere_radius) - areasphere.add_command(label=t("with_diameter"), command=area_sphere_diameter) - areacone.add_command(label=t("with_radius"), command=area_cone_radius) - areacone.add_command(label=t("with_diameter"), command=area_cone_diameter) - volumeclinder.add_command(label=t("with_radius"), command=volume_cylinder_radius) - volumeclinder.add_command(label=t("with_diameter"), command=volume_cylinder_diameter) - volumecone.add_command(label=t("with_radius"), command=volume_cone_radius) - volumecone.add_command(label=t("with_diameter"), command=volume_cone_diameter) - volumesphere.add_command(label=t("with_radius"), command=volume_sphere_radius) - volumesphere.add_command(label=t("with_diameter"), command=volume_sphere_diameter) - shape_area.add_command(label=t("square"), command=area_square) - shape_area.add_command(label=t("rectangle"), command=area_rectangle) - shape_area.add_cascade(label=t("circle"), menu=areacircle) - shape_area.add_command(label=t("triangle"), command=area_triangle) - shape_area.add_command(label=t("trapezoid"), command=area_trapezoid) - shape_area.add_cascade(label=t("cylinder"), menu=areacylinder) - shape_area.add_cascade(label=t("sphere"), menu=areasphere) - shape_area.add_cascade(label=t("cone"), menu=areacone) - shape_volume.add_command(label=t("cube"), command=volume_cube) - shape_volume.add_command(label=t("rect_prism"), command=volume_rectangular_prism) - shape_volume.add_cascade(label=t("cylinder"), menu=volumeclinder) - shape_volume.add_cascade(label=t("cone"), menu=volumecone) - shape_volume.add_cascade(label=t("sphere"), menu=volumesphere) - shape_volume.add_command(label=t("tetrahedron"), command=volume_tetrahedron) - shape_volume.add_command(label=t("trap_prism"), command=volume_trapezoidal_prism) - electricity_menu.add_cascade(label=t("voltage"), menu=voltage) - voltage.add_command(label=t("u_i_r"), command=voltage_i_r) - voltage.add_command(label=t("u_p_i"), command=voltage_p_i) - voltage.add_command(label=t("u_r_p"), command=voltage_r_p) - electricity_menu.add_cascade(label=t("current"), menu=amper) - amper.add_command(label=t("i_u_r"), command=current_u_r) - amper.add_command(label=t("i_p_u"), command=current_p_u) - amper.add_command(label=t("i_r_p"), command=current_p_r) - electricity_menu.add_cascade(label=t("resistance"), menu=resistance) - resistance.add_command(label=t("r_u_i"), command=resistance_u_i) - resistance.add_command(label=t("r_u_p"), command=resistance_u_p) - resistance.add_command(label=t("r_p_i"), command=resistance_p_i) - electricity_menu.add_cascade(label=t("power"),menu=power) - electricity_menu.add_command(label="Widerstand (Farbcode)", command=resistance_color_bands) - power.add_command(label=t("u_i_r"), command=power_u_i) - power.add_command(label=t("u_r_p"), command=power_i_r) - power.add_command(label=t("r_p_i"), command=power_u_r) - shape.add_cascade(label=t("area"), menu=shape_area) - shape.add_cascade(label=t("volume"), menu=shape_volume) - menu.add_command(label=t("info"), command=info) - menu.add_command(label=t("calculator"), command=calculator) - menu.add_cascade(label=t("shape"), menu=shape) - menu.add_cascade(label=t("electricity"), menu=electricity_menu) - menu.add_command(label=t("settings"), command=settings) - menu.add_command(label=t("exit"), command=do_exit) - menubar.add_cascade(label=t("menu"), menu=menu) - -def info(): - clear_frame() - content_frame.rowconfigure(0, weight=1) - content_frame.columnconfigure(0, weight=1) - inner = make_scroll_frame(content_frame) - inner.columnconfigure(0, weight=1) - def info_row(parent, label, value, r): - tk.Label(parent, text=label, - bg="#1e1e1e" if bg_dark else "#f5f5f5", - fg="#888888" if bg_dark else "#777777", - font=("Arial", 10), anchor="w").grid( - row=r, column=0, sticky="w", padx=14, pady=(5, 0)) - tk.Label(parent, text=value, - bg="#1e1e1e" if bg_dark else "#f5f5f5", - fg=fg, font=("Arial", 11), anchor="w").grid( - row=r+1, column=0, sticky="w", padx=14, pady=(0, 5)) - def card(title, items, row): - inner.rowconfigure(row, weight=0) - outer = tk.Frame(inner, bg="#7c5cbf") - outer.grid(row=row, column=0, sticky="ew", padx=16, pady=(10, 0)) - outer.columnconfigure(0, weight=1) - tk.Label(outer, text=title, bg="#7c5cbf", fg="#ece8ff", - font=("Arial", 11, "bold"), anchor="w", - padx=10, pady=6).grid(row=0, column=0, sticky="w") - body = tk.Frame(outer, bg="#1e1e1e" if bg_dark else "#f5f5f5") - body.grid(row=1, column=0, sticky="ew", padx=1, pady=(0, 1)) - body.columnconfigure(0, weight=1) - for i, (lbl, val) in enumerate(items): - info_row(body, lbl, val, i*2) - card(t("app_info"), [ - (t("version"), app_version), - (t("release"), app_release), - (t("status"), app_status), - (t("license"), app_license), - (t("installed"), install_date), - ("App-Ordner", APP_DIR), - ], 0) - card(t("support"), [ - (t("website"), dev_website), - (t("email"), dev_e_mail), - ], 1) - card(t("system"), [ - (t("os"), sys_system), - (t("os_version"), sys_version), - (t("arch"), sys_machine), - (t("python"), sys_python), - ], 2) - -def do_exit(): - root.quit() - -def settings(): - clear_frame() - content_frame.rowconfigure(0, weight=1) - content_frame.columnconfigure(0, weight=1) - inner = make_scroll_frame(content_frame) - inner.columnconfigure(0, weight=1) - inner.columnconfigure(1, weight=1) - inner.columnconfigure(2, weight=0) - make_section(inner, t("appearance"), 0) - def bg_toggle(): - global bg_dark, bg, fg - bg_dark = not bg_dark - bg = 'black' if bg_dark else 'white' - fg = 'white' if bg_dark else 'black' - root.config(bg=bg) - content_frame.config(bg=bg) - creator.config(bg=bg, fg=fg) - save_settings() - settings() - inner.rowconfigure(1, weight=0) - tk.Label(inner, text=t("dark_mode"), bg=bg, fg=fg, - font=("Arial", 11), anchor="w").grid( - row=1, column=0, sticky="w", padx=16, pady=8) - tk.Label(inner, text=t("on") if bg_dark else t("off"), - bg=bg, fg="#bf9fff" if bg_dark else "#7c5cbf", - font=("Arial", 11)).grid(row=1, column=1, sticky="w") - tk.Button(inner, text=t("toggle"), command=bg_toggle, - bg="#2c2c2e" if bg_dark else "#eeeeee", fg=fg, - relief="flat", padx=10, pady=4, cursor="hand2").grid( - row=1, column=2, padx=16, pady=8, sticky="e") - make_section(inner, t("rounding"), 2) - def round_toggle(): - global round_en - round_en = not round_en - round_lbl.config(text=t("on") if round_en else t("off"), - fg="#bf9fff" if round_en else "#888888") - save_settings() - inner.rowconfigure(3, weight=0) - tk.Label(inner, text=t("rounding_active"), bg=bg, fg=fg, - font=("Arial", 11), anchor="w").grid( - row=3, column=0, sticky="w", padx=16, pady=8) - round_lbl = tk.Label(inner, - text=t("on") if round_en else t("off"), - bg=bg, - fg="#bf9fff" if round_en else "#888888", - font=("Arial", 11)) - round_lbl.grid(row=3, column=1, sticky="w") - tk.Button(inner, text=t("toggle"), command=round_toggle, - bg="#2c2c2e" if bg_dark else "#eeeeee", fg=fg, - relief="flat", padx=10, pady=4, cursor="hand2").grid( - row=3, column=2, padx=16, pady=8, sticky="e") - inner.rowconfigure(4, weight=0) - inner.rowconfigure(5, weight=0) - tk.Label(inner, text=t("decimal_places"), bg=bg, fg=fg, - font=("Arial", 11), anchor="w").grid( - row=4, column=0, sticky="w", padx=16, pady=(8, 0)) - slider_val = tk.Label(inner, text=str(round_num), - bg=bg, fg="#bf9fff" if bg_dark else "#7c5cbf", - font=("Arial", 11, "bold")) - slider_val.grid(row=4, column=1, sticky="w") - def on_slider(val): - global round_num - round_num = int(float(val)) - slider_val.config(text=str(round_num)) - save_settings() - tk.Scale(inner, from_=0, to=20, orient="horizontal", - command=on_slider, - bg=bg, fg=fg, - troughcolor="#2c2c2e" if bg_dark else "#dddddd", - highlightthickness=0, showvalue=False, - relief="flat", sliderrelief="flat", - activebackground="#7c5cbf").grid( - row=5, column=0, columnspan=3, sticky="ew", padx=16, pady=(0, 8)) - make_section(inner, t("units"), 6) - inner.rowconfigure(7, weight=0) - tk.Label(inner, text=t("default_unit"), bg=bg, fg=fg, - font=("Arial", 11), anchor="w").grid( - row=7, column=0, sticky="w", padx=16, pady=8) - unit_var = tk.StringVar(value=default_unit) - def on_unit(*args): - global default_unit - default_unit = unit_var.get() - save_settings() - unit_var.trace_add("write", on_unit) - um = tk.OptionMenu(inner, unit_var, *UNITS) - um.config(bg="#2c2c2e" if bg_dark else "#f0f0f0", fg=fg, - activebackground="#3a3a3c", activeforeground=fg, - relief="flat", highlightthickness=0, - font=("Arial", 11), width=4) - um["menu"].config(bg="#2c2c2e" if bg_dark else "#f0f0f0", fg=fg) - um.grid(row=7, column=1, columnspan=2, sticky="w", padx=4, pady=8) - make_section(inner, t("language"), 8) - inner.rowconfigure(9, weight=0) - tk.Label(inner, text=t("language"), bg=bg, fg=fg, - font=("Arial", 11), anchor="w").grid( - row=9, column=0, sticky="w", padx=16, pady=8) - lang_var = tk.StringVar(value=language) - def on_lang(*args): - global language - language = lang_var.get() - save_settings() - rebuild_menu() - settings() - lang_var.trace_add("write", on_lang) - for i, lang in enumerate(["DE", "EN"]): - tk.Radiobutton(inner, text=lang, variable=lang_var, value=lang, - bg=bg, fg=fg, - selectcolor="#2c2c2e" if bg_dark else "#dddddd", - activebackground=bg, activeforeground=fg, - font=("Arial", 11)).grid( - row=9, column=1+i, sticky="w", - padx=(4 if i == 0 else 0, 0), pady=8) - make_section(inner, "Datenverwaltung" if language == "DE" else "Data management", 10) - def del_history(): - if messagebox.askyesno(t("delete_history"), t("confirm_del_h")): - db_clear() - def reset_s(): - if messagebox.askyesno(t("reset_settings"), t("confirm_reset")): - global bg_dark, round_num, round_en, default_unit, language, bg, fg - bg_dark = DEFAULT_SETTINGS["bg_dark"] - round_num = DEFAULT_SETTINGS["round_num"] - round_en = DEFAULT_SETTINGS["round_en"] - default_unit = DEFAULT_SETTINGS["default_unit"] - language = DEFAULT_SETTINGS["language"] - bg = 'black' if bg_dark else 'white' - fg = 'white' if bg_dark else 'black' - save_settings() - root.config(bg=bg) - content_frame.config(bg=bg) - creator.config(bg=bg, fg=fg) - rebuild_menu() - settings() - inner.rowconfigure(11, weight=0) - inner.rowconfigure(12, weight=0) - tk.Button(inner, text=t("delete_history"), command=del_history, - bg="#3a1a1a", fg="#ff8080", - relief="flat", padx=10, pady=6, cursor="hand2", - font=("Arial", 11)).grid( - row=11, column=0, columnspan=3, sticky="ew", padx=16, pady=(8, 4)) - tk.Button(inner, text=t("reset_settings"), command=reset_s, - bg="#2a1a3a", fg="#bf9fff", - relief="flat", padx=10, pady=6, cursor="hand2", - font=("Arial", 11)).grid( - row=12, column=0, columnspan=3, sticky="ew", padx=16, pady=(0, 16)) - -def area_square(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var, unit_var = tk.StringVar(), tk.StringVar(value=default_unit) - def calc(*a): - try: - v = get_m(var, unit_var); s = v**2 - if DEBUG: print(f"Debug area_square: v={v}, s={s}, unit={unit_var.get()}") - if round_en: s = round(s, round_num) - result.config(text=f"{t('result_area')} = {s} m²") - except: result.config(text="") - var.trace_add("write", calc); unit_var.trace_add("write", calc) - make_title_label(content_frame, t("area_square"), "A = a²", 0) - make_input_row(content_frame, f"{t('side')} a:", var, 1, unit_var) - result = make_result_label(content_frame, 3) - -def area_rectangle(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_a, var_b = tk.StringVar(), tk.StringVar() - unit_a, unit_b = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) - def calc(*a): - try: - a = get_m(var_a, unit_a); b = get_m(var_b, unit_b); s = a * b - if DEBUG: print(f"Debug area_rectangle: a={a}, b={b}, s={s}, unit_a={unit_a.get()}, unit_b={unit_b.get()}") - if round_en: s = round(s, round_num) - result.config(text=f"{t('result_area')} = {s} m²") - except: result.config(text="") - var_a.trace_add("write", calc); var_b.trace_add("write", calc) - unit_a.trace_add("write", calc); unit_b.trace_add("write", calc) - make_title_label(content_frame, t("area_rect"), "A = a · b", 0) - make_input_row(content_frame, f"{t('side')} a:", var_a, 1, unit_a) - make_input_row(content_frame, f"{t('side')} b:", var_b, 3, unit_b) - result = make_result_label(content_frame, 5) - -def area_circle_radius(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_r, unit_var = tk.StringVar(), tk.StringVar(value=default_unit) - def calc(*a): - try: - r = get_m(var_r, unit_var); s = math.pi * r**2 - if DEBUG: print(f"Debug area_circle_radius: r={r}, s={s}, unit={unit_var.get()}") - if round_en: s = round(s, round_num) - result.config(text=f"{t('result_area')} = {s} m²") - except: result.config(text="") - var_r.trace_add("write", calc); unit_var.trace_add("write", calc) - make_title_label(content_frame, t("area_circle"), "A = π · r²", 0) - make_input_row(content_frame, t("radius"), var_r, 1, unit_var) - result = make_result_label(content_frame, 3) - -def area_circle_diameter(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_d, unit_var = tk.StringVar(), tk.StringVar(value=default_unit) - def calc(*a): - try: - r = get_m(var_d, unit_var)/2; s = math.pi * r**2 - if DEBUG: print(f"Debug area_circle_diameter: d={get_m(var_d, unit_var)}, r={r}, s={s}, unit={unit_var.get()}") - if round_en: s = round(s, round_num) - result.config(text=f"{t('result_area')} = {s} m²") - except: result.config(text="") - var_d.trace_add("write", calc); unit_var.trace_add("write", calc) - make_title_label(content_frame, t("area_circle"), "A = π · (d/2)²", 0) - make_input_row(content_frame, t("diameter"), var_d, 1, unit_var) - result = make_result_label(content_frame, 3) - -def area_triangle(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_g, var_h = tk.StringVar(), tk.StringVar() - unit_g, unit_h = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) - def calc(*a): - try: - g = get_m(var_g, unit_g); h = get_m(var_h, unit_h); s = 0.5 * g * h - if DEBUG: print(f"Debug area_triangle: g={g}, h={h}, s={s}, unit_g={unit_g.get()}, unit_h={unit_h.get()}") - if round_en: s = round(s, round_num) - result.config(text=f"{t('result_area')} = {s} m²") - except: result.config(text="") - var_g.trace_add("write", calc); var_h.trace_add("write", calc) - unit_g.trace_add("write", calc); unit_h.trace_add("write", calc) - make_title_label(content_frame, t("area_tri"), "A = g · h / 2", 0) - make_input_row(content_frame, t("base"), var_g, 1, unit_g) - make_input_row(content_frame, t("height"), var_h, 3, unit_h) - result = make_result_label(content_frame, 5) - -def area_trapezoid(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_a, var_b, var_h = tk.StringVar(), tk.StringVar(), tk.StringVar() - unit_a, unit_b, unit_h = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) - def calc(*a): - try: - a = get_m(var_a, unit_a); b = get_m(var_b, unit_b); h = get_m(var_h, unit_h); s = ((a + b) / 2) * h - if DEBUG: print(f"Debug area_trapezoid: a={a}, b={b}, h={h}, s={s}, unit_a={unit_a.get()}, unit_b={unit_b.get()}, unit_h={unit_h.get()}") - if round_en: s = round(s, round_num) - result.config(text=f"{t('result_area')} = {s} m²") - except: result.config(text="") - var_a.trace_add("write", calc); var_b.trace_add("write", calc); var_h.trace_add("write", calc) - unit_a.trace_add("write", calc); unit_b.trace_add("write", calc); unit_h.trace_add("write", calc) - make_title_label(content_frame, t("area_trap"), "A = (a+b)/2 · h", 0) - make_input_row(content_frame, f"{t('side')} a:", var_a, 1, unit_a) - make_input_row(content_frame, f"{t('side')} b:", var_b, 3, unit_b) - make_input_row(content_frame, t("height"), var_h, 5, unit_h) - result = make_result_label(content_frame, 7) - -def area_cylinder_radius(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_r, var_h = tk.StringVar(), tk.StringVar() - unit_r, unit_h = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) - def calc(*a): - try: - r, h = get_m(var_r,unit_r), get_m(var_h,unit_h) - s = 2*math.pi*r*h + 2*math.pi*r**2 - if DEBUG: print(f"Debug area_cylinder_radius: r={r}, h={h}, s={s}, unit_r={unit_r.get()}, unit_h={unit_h.get()}") - if round_en: s = round(s, round_num) - result.config(text=f"{t('result_area')} = {s} m²") - except: result.config(text="") - var_r.trace_add("write", calc); var_h.trace_add("write", calc) - unit_r.trace_add("write", calc); unit_h.trace_add("write", calc) - make_title_label(content_frame, t("area_cyl"), "A = 2πr(r+h)", 0) - make_input_row(content_frame, t("radius"), var_r, 1, unit_r) - make_input_row(content_frame, t("height"), var_h, 3, unit_h) - result = make_result_label(content_frame, 5) - -def area_cylinder_diameter(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_d, var_h = tk.StringVar(), tk.StringVar() - unit_d, unit_h = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) - def calc(*a): - try: - r, h = get_m(var_d,unit_d)/2, get_m(var_h,unit_h) - s = 2*math.pi*r*h + 2*math.pi*r**2 - if DEBUG: print(f"Debug area_cylinder_diameter: d={get_m(var_d,unit_d)}, r={r}, h={h}, s={s}, unit_d={unit_d.get()}, unit_h={unit_h.get()}") - if round_en: s = round(s, round_num) - result.config(text=f"{t('result_area')} = {s} m²") - except: result.config(text="") - var_d.trace_add("write", calc); var_h.trace_add("write", calc) - unit_d.trace_add("write", calc); unit_h.trace_add("write", calc) - make_title_label(content_frame, t("area_cyl"), "A = 2πr(r+h)", 0) - make_input_row(content_frame, t("diameter"), var_d, 1, unit_d) - make_input_row(content_frame, t("height"), var_h, 3, unit_h) - result = make_result_label(content_frame, 5) - -def area_sphere_radius(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_r = tk.StringVar() - unit_r = tk.StringVar(value=default_unit) - def calc(*a): - try: - s = 4*math.pi*get_m(var_r,unit_r)**2 - if DEBUG: print(f"Debug area_sphere_radius: r={get_m(var_r,unit_r)}, s={s}, unit={unit_r.get()}") - if round_en: s = round(s, round_num) - result.config(text=f"{t('result_area')} = {s} m²") - except: result.config(text="") - var_r.trace_add("write", calc); unit_r.trace_add("write", calc) - make_title_label(content_frame, t("area_sphere"), "A = 4πr²", 0) - make_input_row(content_frame, t("radius"), var_r, 1, unit_r) - result = make_result_label(content_frame, 3) - -def area_sphere_diameter(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_d = tk.StringVar() - unit_d = tk.StringVar(value=default_unit) - def calc(*a): - try: - s = 4*math.pi*(get_m(var_d,unit_d)/2)**2 - if DEBUG: print(f"Debug area_sphere_diameter: d={get_m(var_d,unit_d)}, r={get_m(var_d,unit_d)/2}, s={s}, unit={unit_d.get()}") - if round_en: s = round(s, round_num) - result.config(text=f"{t('result_area')} = {s} m²") - except: result.config(text="") - var_d.trace_add("write", calc); unit_d.trace_add("write", calc) - make_title_label(content_frame, t("area_sphere"), "A = 4π(d/2)²", 0) - make_input_row(content_frame, t("diameter"), var_d, 1, unit_d) - result = make_result_label(content_frame, 3) - -def area_cone_radius(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_r, var_l = tk.StringVar(), tk.StringVar() - unit_r, unit_l = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) - def calc(*a): - try: - r, l = get_m(var_r,unit_r), get_m(var_l,unit_l) - s = math.pi*r*(r+l) - if DEBUG: print(f"Debug area_cone_radius: r={r}, l={l}, s={s}, unit_r={unit_r.get()}, unit_l={unit_l.get()}") - if round_en: s = round(s, round_num) - result.config(text=f"{t('result_area')} = {s} m²") - except: result.config(text="") - var_r.trace_add("write", calc); var_l.trace_add("write", calc) - unit_r.trace_add("write", calc); unit_l.trace_add("write", calc) - make_title_label(content_frame, t("area_cone"), "A = πr(r+l)", 0) - make_input_row(content_frame, t("radius"), var_r, 1, unit_r) - make_input_row(content_frame, t("slant"), var_l, 3, unit_l) - result = make_result_label(content_frame, 5) - -def area_cone_diameter(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_d, var_l = tk.StringVar(), tk.StringVar() - unit_d, unit_l = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) - def calc(*a): - try: - r, l = get_m(var_d,unit_d)/2, get_m(var_l,unit_l) - s = math.pi*r*(r+l) - if DEBUG: print(f"Debug area_cone_diameter: d={get_m(var_d,unit_d)}, r={r}, l={l}, s={s}, unit_d={unit_d.get()}, unit_l={unit_l.get()}") - if round_en: s = round(s, round_num) - result.config(text=f"{t('result_area')} = {s} m²") - except: result.config(text="") - var_d.trace_add("write", calc); var_l.trace_add("write", calc) - unit_d.trace_add("write", calc); unit_l.trace_add("write", calc) - make_title_label(content_frame, t("area_cone"), "A = πr(r+l)", 0) - make_input_row(content_frame, t("diameter"), var_d, 1, unit_d) - make_input_row(content_frame, t("slant"), var_l, 3, unit_l) - result = make_result_label(content_frame, 5) - -def volume_cube(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_a = tk.StringVar() - unit_a = tk.StringVar(value=default_unit) - def calc(*a): - try: - a = get_m(var_a,unit_a); s = a**3 - if DEBUG: print(f"Debug volume_cube: a={a}, s={s}, unit={unit_a.get()}") - if round_en: s = round(s, round_num) - result.config(text=f"{t('result_vol')} = {s} m³") - except: result.config(text="") - var_a.trace_add("write", calc); unit_a.trace_add("write", calc) - make_title_label(content_frame, t("vol_cube"), "V = a³", 0) - make_input_row(content_frame, f"{t('side')} a:", var_a, 1, unit_a) - result = make_result_label(content_frame, 3) - -def volume_rectangular_prism(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_l, var_w, var_h = tk.StringVar(), tk.StringVar(), tk.StringVar() - unit_l, unit_w, unit_h = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) - def calc(*a): - try: - l = get_m(var_l,unit_l); w = get_m(var_w,unit_w); h = get_m(var_h,unit_h); s = l * w * h - if DEBUG: print(f"Debug volume_rectangular_prism: l={l}, w={w}, h={h}, s={s}, unit_l={unit_l.get()}, unit_w={unit_w.get()}, unit_h={unit_h.get()}") - if round_en: s = round(s, round_num) - result.config(text=f"{t('result_vol')} = {s} m³") - except: result.config(text="") - var_l.trace_add("write", calc); var_w.trace_add("write", calc); var_h.trace_add("write", calc) - unit_l.trace_add("write", calc); unit_w.trace_add("write", calc); unit_h.trace_add("write", calc) - make_title_label(content_frame, t("vol_rect"), "V = l · w · h", 0) - make_input_row(content_frame, t("length"), var_l, 1, unit_l) - make_input_row(content_frame, t("width"), var_w, 3, unit_w) - make_input_row(content_frame, t("height"), var_h, 5, unit_h) - result = make_result_label(content_frame, 7) - -def volume_cylinder_radius(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_r, var_h = tk.StringVar(), tk.StringVar() - unit_r, unit_h = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) - def calc(*a): - try: - r, h = get_m(var_r,unit_r), get_m(var_h,unit_h) - s = math.pi*r**2*h - if DEBUG: print(f"Debug volume_cylinder_radius: r={r}, h={h}, s={s}, unit_r={unit_r.get()}, unit_h={unit_h.get()}") - if round_en: s = round(s, round_num) - result.config(text=f"{t('result_vol')} = {s} m³") - except: result.config(text="") - var_r.trace_add("write", calc); var_h.trace_add("write", calc) - unit_r.trace_add("write", calc); unit_h.trace_add("write", calc) - make_title_label(content_frame, t("vol_cyl"), "V = π · r² · h", 0) - make_input_row(content_frame, t("radius"), var_r, 1, unit_r) - make_input_row(content_frame, t("height"), var_h, 3, unit_h) - result = make_result_label(content_frame, 5) - -def volume_cylinder_diameter(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_d, var_h = tk.StringVar(), tk.StringVar() - unit_d, unit_h = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) - def calc(*a): - try: - r, h = get_m(var_d,unit_d)/2, get_m(var_h,unit_h) - s = math.pi*r**2*h - if DEBUG: print(f"Debug volume_cylinder_diameter: d={get_m(var_d,unit_d)}, r={r}, h={h}, s={s}, unit_d={unit_d.get()}, unit_h={unit_h.get()}") - if round_en: s = round(s, round_num) - result.config(text=f"{t('result_vol')} = {s} m³") - except: result.config(text="") - var_d.trace_add("write", calc); var_h.trace_add("write", calc) - unit_d.trace_add("write", calc); unit_h.trace_add("write", calc) - make_title_label(content_frame, t("vol_cyl"), "V = π · (d/2)² · h", 0) - make_input_row(content_frame, t("diameter"), var_d, 1, unit_d) - make_input_row(content_frame, t("height"), var_h, 3, unit_h) - result = make_result_label(content_frame, 5) - -def volume_cone_radius(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_r, var_h = tk.StringVar(), tk.StringVar() - unit_r, unit_h = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) - def calc(*a): - try: - r, h = get_m(var_r,unit_r), get_m(var_h,unit_h) - s = (1/3)*math.pi*r**2*h - if DEBUG: print(f"Debug volume_cone_radius: r={r}, h={h}, s={s}, unit_r={unit_r.get()}, unit_h={unit_h.get()}") - if round_en: s = round(s, round_num) - result.config(text=f"{t('result_vol')} = {s} m³") - except: result.config(text="") - var_r.trace_add("write", calc); var_h.trace_add("write", calc) - unit_r.trace_add("write", calc); unit_h.trace_add("write", calc) - make_title_label(content_frame, t("vol_cone"), "V = π·r²·h / 3", 0) - make_input_row(content_frame, t("radius"), var_r, 1, unit_r) - make_input_row(content_frame, t("height"), var_h, 3, unit_h) - result = make_result_label(content_frame, 5) - -def volume_cone_diameter(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_d, var_h = tk.StringVar(), tk.StringVar() - unit_d, unit_h = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) - def calc(*a): - try: - r, h = get_m(var_d,unit_d)/2, get_m(var_h,unit_h) - s = (1/3)*math.pi*r**2*h - if DEBUG: print(f"Debug volume_cone_diameter: d={get_m(var_d,unit_d)}, r={r}, h={h}, s={s}, unit_d={unit_d.get()}, unit_h={unit_h.get()}") - if round_en: s = round(s, round_num) - result.config(text=f"{t('result_vol')} = {s} m³") - except: result.config(text="") - var_d.trace_add("write", calc); var_h.trace_add("write", calc) - unit_d.trace_add("write", calc); unit_h.trace_add("write", calc) - make_title_label(content_frame, t("vol_cone"), "V = π·(d/2)²·h / 3", 0) - make_input_row(content_frame, t("diameter"), var_d, 1, unit_d) - make_input_row(content_frame, t("height"), var_h, 3, unit_h) - result = make_result_label(content_frame, 5) - -def volume_sphere_radius(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_r = tk.StringVar() - unit_r = tk.StringVar(value=default_unit) - def calc(*a): - try: - s = (4/3)*math.pi*get_m(var_r,unit_r)**3 - if DEBUG: print(f"Debug volume_sphere_radius: r={get_m(var_r,unit_r)}, s={s}, unit={unit_r.get()}") - if round_en: s = round(s, round_num) - result.config(text=f"{t('result_vol')} = {s} m³") - except: result.config(text="") - var_r.trace_add("write", calc); unit_r.trace_add("write", calc) - make_title_label(content_frame, t("vol_sphere"), "V = 4/3 · π · r³", 0) - make_input_row(content_frame, t("radius"), var_r, 1, unit_r) - result = make_result_label(content_frame, 3) - -def volume_sphere_diameter(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_d = tk.StringVar() - unit_d = tk.StringVar(value=default_unit) - def calc(*a): - try: - s = (4/3)*math.pi*(get_m(var_d,unit_d)/2)**3 - if DEBUG: print(f"Debug volume_sphere_diameter: d={get_m(var_d,unit_d)}, r={get_m(var_d,unit_d)/2}, s={s}, unit={unit_d.get()}") - if round_en: s = round(s, round_num) - result.config(text=f"{t('result_vol')} = {s} m³") - except: result.config(text="") - var_d.trace_add("write", calc); unit_d.trace_add("write", calc) - make_title_label(content_frame, t("vol_sphere"), "V = 4/3 · π · (d/2)³", 0) - make_input_row(content_frame, t("diameter"), var_d, 1, unit_d) - result = make_result_label(content_frame, 3) - -def volume_tetrahedron(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_a = tk.StringVar() - unit_a = tk.StringVar(value=default_unit) - def calc(*a): - try: - s = get_m(var_a,unit_a)**3 / (6*2**0.5) - if DEBUG: print(f"Debug volume_tetrahedron: a={get_m(var_a,unit_a)}, s={s}, unit={unit_a.get()}") - if round_en: s = round(s, round_num) - result.config(text=f"{t('result_vol')} = {s} m³") - except: result.config(text="") - var_a.trace_add("write", calc); unit_a.trace_add("write", calc) - make_title_label(content_frame, t("vol_tetra"), "V = a³ / (6√2)", 0) - make_input_row(content_frame, f"{t('side')} a:", var_a, 1, unit_a) - result = make_result_label(content_frame, 3) - -def volume_trapezoidal_prism(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_b, var_B, var_h, var_i = tk.StringVar(), tk.StringVar(), tk.StringVar(), tk.StringVar() - unit_b, unit_B, unit_h, unit_i = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit), tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) - def calc(*a): - try: - b=get_m(var_b,unit_b); B=get_m(var_B,unit_B) - h=get_m(var_h,unit_h); i=get_m(var_i,unit_i) - s = ((b+B)/2)*h*i - if DEBUG: print(f"Debug volume_trapezoidal_prism: b={b}, B={B}, h={h}, i={i}, s={s}, unit_b={unit_b.get()}, unit_B={unit_B.get()}, unit_h={unit_h.get()}, unit_i={unit_i.get()}") - if round_en: s = round(s, round_num) - result.config(text=f"{t('result_vol')} = {s} m³") - except: result.config(text="") - for v in (var_b, var_B, var_h, var_i): v.trace_add("write", calc) - for u in (unit_b, unit_B, unit_h, unit_i): u.trace_add("write", calc) - make_title_label(content_frame, t("vol_trap"), "V = (b+B)/2 · h · i", 0) - make_input_row(content_frame, f"{t('side')} b:", var_b, 1, unit_b) - make_input_row(content_frame, f"{t('side')} B:", var_B, 3, unit_B) - make_input_row(content_frame, t("height"), var_h, 5, unit_h) - make_input_row(content_frame, t("depth"), var_i, 7, unit_i) - result = make_result_label(content_frame, 9) - -def voltage_i_r(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_i, var_r = tk.StringVar(), tk.StringVar() - unit_i, unit_r = tk.StringVar(value="A"), tk.StringVar(value="Ω") - - def calc(*a): - try: - i = get_electricity_value(var_i, unit_i) - r = get_electricity_value(var_r, unit_r) - if r == 0: - result.config(text="") - return - u = i * r - if DEBUG: print(f"Debug voltage_i_r: i={i} A, r={r} Ω, u={u} V") - if round_en: u = round(u, round_num) - result.config(text=f"{t('u')} = {u} V") - except: result.config(text="") - for v in (var_i, var_r, unit_i, unit_r): v.trace_add("write", calc) - make_title_label(content_frame, t("voltage"), "U = I · R", 0) - make_input_row(content_frame, t("i"), var_i, 1, unit_i, CURRENT_UNITS) - make_input_row(content_frame, t("r"), var_r, 3, unit_r, RESISTANCE_UNITS) - result = make_result_label(content_frame, 5) - -def voltage_p_i(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_i, var_p = tk.StringVar(), tk.StringVar() - unit_i, unit_p = tk.StringVar(value="A"), tk.StringVar(value="W") - - def calc(*a): - try: - i = get_electricity_value(var_i, unit_i) - p = get_electricity_value(var_p, unit_p) - if i == 0: - result.config(text="") - return - u = p / i - if DEBUG: print(f"Debug voltage_p_i: p={p} W, i={i} A, u={u} V") - if round_en: u = round(u, round_num) - result.config(text=f"{t('u')} = {u} V") - except: result.config(text="") - for v in (var_i, var_p, unit_i, unit_p): v.trace_add("write", calc) - make_title_label(content_frame, t("voltage"), "U = P / I", 0) - make_input_row(content_frame, t("p"), var_p, 1, unit_p, POWER_UNITS) - make_input_row(content_frame, t("i"), var_i, 3, unit_i, CURRENT_UNITS) - result = make_result_label(content_frame, 5) - -def voltage_r_p(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_r, var_p = tk.StringVar(), tk.StringVar() - unit_r, unit_p = tk.StringVar(value="Ω"), tk.StringVar(value="W") - - def calc(*a): - try: - r = get_electricity_value(var_r, unit_r) - p = get_electricity_value(var_p, unit_p) - if p == 0: - result.config(text="") - return - u = math.sqrt(p * r) - if DEBUG: print(f"Debug voltage_r_p: p={p} W, r={r} Ω, u={u} V") - if round_en: u = round(u, round_num) - result.config(text=f"{t('u')} = {u} V") - except: result.config(text="") - for v in (var_r, var_p, unit_r, unit_p): v.trace_add("write", calc) - make_title_label(content_frame, t("voltage"), "U = √(P · R)", 0) - make_input_row(content_frame, t("p"), var_p, 1, unit_p, POWER_UNITS) - make_input_row(content_frame, t("r"), var_r, 3, unit_r, RESISTANCE_UNITS) - result = make_result_label(content_frame, 5) - -def current_u_r(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_u, var_r = tk.StringVar(), tk.StringVar() - unit_u, unit_r = tk.StringVar(value="V"), tk.StringVar(value="Ω") - - def calc(*a): - try: - u = get_electricity_value(var_u, unit_u) - r = get_electricity_value(var_r, unit_r) - if r == 0: - result.config(text="") - return - i = u / r - if DEBUG: print(f"Debug current_u_r: u={u} V, r={r} Ω, i={i} A") - if round_en: i = round(i, round_num) - result.config(text=f"{t('i')} = {i} A") - except: result.config(text="") - for v in (var_u, var_r, unit_u, unit_r): v.trace_add("write", calc) - make_title_label(content_frame, t("current"), "I = U / R", 0) - make_input_row(content_frame, t("u"), var_u, 1, unit_u, VOLTAGE_UNITS) - make_input_row(content_frame, t("r"), var_r, 3, unit_r, RESISTANCE_UNITS) - result = make_result_label(content_frame, 5) - -def current_p_u(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_u, var_p = tk.StringVar(), tk.StringVar() - unit_u, unit_p = tk.StringVar(value="V"), tk.StringVar(value="W") - - def calc(*a): - try: - u = get_electricity_value(var_u, unit_u) - p = get_electricity_value(var_p, unit_p) - if u == 0: - result.config(text="") - return - i = p / u - if DEBUG: print(f"Debug current_p_u: p={p} W, u={u} V, i={i} A") - if round_en: i = round(i, round_num) - result.config(text=f"{t('i')} = {i} A") - except: result.config(text="") - for v in (var_u, var_p, unit_u, unit_p): v.trace_add("write", calc) - make_title_label(content_frame, t("current"), "I = P / U", 0) - make_input_row(content_frame, t("p"), var_p, 1, unit_p, POWER_UNITS) - make_input_row(content_frame, t("u"), var_u, 3, unit_u, VOLTAGE_UNITS) - result = make_result_label(content_frame, 5) - -def current_p_r(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_p, var_r = tk.StringVar(), tk.StringVar() - unit_p, unit_r = tk.StringVar(value="W"), tk.StringVar(value="Ω") - - def calc(*a): - try: - p = get_electricity_value(var_p, unit_p) - r = get_electricity_value(var_r, unit_r) - if r == 0: - result.config(text="") - return - i = math.sqrt(p / r) - if DEBUG: print(f"Debug current_p_r: p={p} W, r={r} Ω, i={i} A") - if round_en: i = round(i, round_num) - result.config(text=f"{t('i')} = {i} A") - except: result.config(text="") - for v in (var_p, var_r, unit_p, unit_r): v.trace_add("write", calc) - make_title_label(content_frame, t("current"), "I = √(P / R)", 0) - make_input_row(content_frame, t("p"), var_p, 1, unit_p, POWER_UNITS) - make_input_row(content_frame, t("r"), var_r, 3, unit_r, RESISTANCE_UNITS) - result = make_result_label(content_frame, 5) - - -def resistance_u_i(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_u, var_i = tk.StringVar(), tk.StringVar() - unit_u, unit_i = tk.StringVar(value="V"), tk.StringVar(value="A") - - def calc(*a): - try: - u = get_electricity_value(var_u, unit_u) - i = get_electricity_value(var_i, unit_i) - if i == 0: - result.config(text="") - return - r = u / i - if DEBUG: print(f"Debug resistance_u_i: u={u} V, i={i} A, r={r} Ω") - if round_en: r = round(r, round_num) - result.config(text=f"{t('r')} = {r} Ω") - except: result.config(text="") - for v in (var_u, var_i, unit_u, unit_i): v.trace_add("write", calc) - make_title_label(content_frame, t("resistance"), "R = U / I", 0) - make_input_row(content_frame, t("u"), var_u, 1, unit_u, VOLTAGE_UNITS) - make_input_row(content_frame, t("i"), var_i, 3, unit_i, CURRENT_UNITS) - result = make_result_label(content_frame, 5) - -def resistance_u_p(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_u, var_p = tk.StringVar(), tk.StringVar() - unit_u, unit_p = tk.StringVar(value="V"), tk.StringVar(value="W") - - def calc(*a): - try: - u = get_electricity_value(var_u, unit_u) - p = get_electricity_value(var_p, unit_p) - if u == 0: - result.config(text="") - return - r = u**2 / p - if DEBUG: print(f"Debug resistance_u_p: u={u} V, p={p} W, r={r} Ω") - if round_en: r = round(r, round_num) - result.config(text=f"{t('r')} = {r} Ω") - except: result.config(text="") - for v in (var_u, var_p, unit_u, unit_p): v.trace_add("write", calc) - make_title_label(content_frame, t("resistance"), "R = U² / P", 0) - make_input_row(content_frame, t("u"), var_u, 1, unit_u, VOLTAGE_UNITS) - make_input_row(content_frame, t("p"), var_p, 3, unit_p, POWER_UNITS) - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_p, var_i = tk.StringVar(), tk.StringVar() - -def resistance_p_i(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_p, var_i = tk.StringVar(), tk.StringVar() - unit_p, unit_i = tk.StringVar(value="W"), tk.StringVar(value="A") - - def calc(*a): - try: - p = get_electricity_value(var_p, unit_p) - i = get_electricity_value(var_i, unit_i) - if i == 0: - result.config(text="") - return - r = p / i**2 - if DEBUG: print(f"Debug resistance_p_i: p={p} W, i={i} A, r={r} Ω") - if round_en: r = round(r, round_num) - result.config(text=f"{t('r')} = {r} Ω") - except: result.config(text="") - for v in (var_p, var_i, unit_p, unit_i): v.trace_add("write", calc) - make_title_label(content_frame, t("resistance"), "R = P / I²", 0) - make_input_row(content_frame, t("p"), var_p, 1, unit_p, POWER_UNITS) - make_input_row(content_frame, t("i"), var_i, 3, unit_i, CURRENT_UNITS) - result = make_result_label(content_frame, 5) - -def resistance_color_bands(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - colors_digit = ["Black", "Brown", "Red", "Orange", "Yellow", "Green", "Blue", "Violet", "Grey", "White"] - colors_multiplier = ["Black", "Brown", "Red", "Orange", "Yellow", "Green", "Blue", "Violet", "Grey", "White", "Gold", "Silver"] - colors_tolerance = ["Brown", "Red", "Green", "Blue", "Violet", "Grey", "Gold", "Silver", "None"] - - b1 = tk.StringVar(value="Brown") - b2 = tk.StringVar(value="Black") - b3 = tk.StringVar(value="Black") - b4 = tk.StringVar(value="Brown") - b5 = tk.StringVar(value="Gold") - ring_mode = tk.IntVar(value=4) - - def format_value(r): - if r >= 1_000_000: - return f"{round(r/1_000_000, round_num)} MΩ" - if r >= 1_000: - return f"{round(r/1_000, round_num)} kΩ" - if r >= 1: - return f"{round(r, round_num)} Ω" - if r >= 0.001: - return f"{round(r*1000, round_num)} mΩ" - return f"{round(r*1_000_000, round_num)} μΩ" - - def update_bands(): - positions = bands_5 if ring_mode.get() == 5 else bands_4 - vars_active = [b1, b2, b3, b4, b5] if ring_mode.get() == 5 else [b1, b2, b3, b5] - for idx, item in enumerate(band_items): - if idx < len(positions): - x1, y1, x2, y2 = positions[idx] - canvas.coords(item, x1, y1, x2, y2) - color_key = vars_active[idx].get() - canvas.itemconfig(item, fill=COLOR_HEX.get(color_key, "#000000"), state="normal") - else: - canvas.itemconfig(item, state="hidden") - - def calc(*a): - try: - if ring_mode.get() == 4: - d1 = COLOR_DIGITS[b1.get()] - d2 = COLOR_DIGITS[b2.get()] - mul = COLOR_MULTIPLIER[b3.get()] - tol = COLOR_TOLERANCE[b5.get()] - r = (d1*10 + d2) * mul - else: - d1 = COLOR_DIGITS[b1.get()] - d2 = COLOR_DIGITS[b2.get()] - d3 = COLOR_DIGITS[b3.get()] - mul = COLOR_MULTIPLIER[b4.get()] - tol = COLOR_TOLERANCE[b5.get()] - r = (d1*100 + d2*10 + d3) * mul - update_bands() - result.config(text=f"R = {format_value(r)} {tol} ({r} Ω)") - except Exception: - result.config(text="") - - for v in (b1, b2, b3, b4, b5): v.trace_add("write", calc) - - def rebuild_dropdowns(): - for w in dropdown_widgets: - w.destroy() - dropdown_widgets.clear() - if ring_mode.get() == 4: - rows = [ - ("1. Band (Ziffer 1)", b1, colors_digit), - ("2. Band (Ziffer 2)", b2, colors_digit), - ("3. Band (Multiplikator)", b3, colors_multiplier), - ("4. Band (Toleranz)", b5, colors_tolerance), - ] - else: - rows = [ - ("1. Band (Ziffer 1)", b1, colors_digit), - ("2. Band (Ziffer 2)", b2, colors_digit), - ("3. Band (Ziffer 3)", b3, colors_digit), - ("4. Band (Multiplikator)", b4, colors_multiplier), - ("5. Band (Toleranz)", b5, colors_tolerance), - ] - for i, (lbl, var, opts) in enumerate(rows): - l, o = make_dropdown(dropdown_frame, lbl, var, i, opts) - dropdown_widgets.extend([l, o]) - - def on_mode_change(): - rebuild_dropdowns() - update_bands() - calc() - - make_title_label(content_frame, "Widerstand Farbcode", "", 0) - - mode_frame = tk.Frame(content_frame, bg=bg) - mode_frame.grid(row=1, column=0, sticky="w", padx=16, pady=(4, 0)) - tk.Label(mode_frame, text="Ringe:", bg=bg, fg=fg, font=("Arial", 11)).pack(side="left", padx=(0, 8)) - for val, label in [(4, "4-Ring"), (5, "5-Ring")]: - tk.Radiobutton( - mode_frame, text=label, variable=ring_mode, value=val, - bg=bg, fg=fg, - selectcolor="#2c2c2e" if bg_dark else "#dddddd", - activebackground=bg, activeforeground=fg, - font=("Arial", 11), - command=on_mode_change - ).pack(side="left", padx=4) - - canvas_width = 180 - body_left = 40 - body_right = 140 - body_top, body_bottom = 30, 50 - wire_y = 40 - - canvas = tk.Canvas(content_frame, height=70, width=canvas_width, - bg=bg, highlightthickness=0) - canvas.grid(row=2, column=0, sticky="w", padx=16, pady=(10, 4)) - - canvas.create_rectangle(body_left, body_top, body_right, body_bottom, - fill="#d2b48c", outline="#8b5a2b", width=2) - canvas.create_line(body_left, wire_y, 25, wire_y, fill="#8b5a2b", width=3) - canvas.create_line(body_right, wire_y, canvas_width-20, wire_y, fill="#8b5a2b", width=3) - - bands_4 = [ - (body_left+10, body_top, body_left+18, body_bottom), - (body_left+28, body_top, body_left+36, body_bottom), - (body_left+50, body_top, body_left+58, body_bottom), - (body_left+70, body_top, body_left+78, body_bottom), - ] - bands_5 = [ - (body_left+8, body_top, body_left+15, body_bottom), - (body_left+23, body_top, body_left+30, body_bottom), - (body_left+38, body_top, body_left+45, body_bottom), - (body_left+56, body_top, body_left+63, body_bottom), - (body_left+73, body_top, body_left+80, body_bottom), - ] - - band_items = [] - for coords in bands_4: - item = canvas.create_rectangle(*coords, fill="#000000", outline="black") - band_items.append(item) - item5 = canvas.create_rectangle(*bands_5[4], fill="#000000", outline="black", state="hidden") - band_items.append(item5) - - def make_dropdown(parent, label_text, var, row, options): - lbl = tk.Label(parent, text=label_text, bg=bg, fg=fg, - font=("Arial", 11), anchor="w") - lbl.grid(row=row*2, column=0, sticky="w", pady=(8, 0)) - om = tk.OptionMenu(parent, var, *options) - om.config(bg="#2c2c2e" if bg_dark else "#f0f0f0", fg=fg, - activebackground="#3a3a3c", activeforeground=fg, - relief="flat", highlightthickness=0, - font=("Arial", 11), width=12) - om["menu"].config(bg="#2c2c2e" if bg_dark else "#f0f0f0", fg=fg) - om.grid(row=row*2+1, column=0, sticky="ew", pady=(2, 2)) - return lbl, om - - dropdown_frame = tk.Frame(content_frame, bg=bg) - dropdown_frame.grid(row=3, column=0, sticky="ew", padx=16, pady=(8, 0)) - dropdown_frame.columnconfigure(0, weight=1) - dropdown_widgets = [] - - result = make_result_label(content_frame, 4) - - rebuild_dropdowns() - update_bands() - calc() - -def power_u_i(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_u, var_i = tk.StringVar(), tk.StringVar() - unit_u, unit_i = tk.StringVar(value="V"), tk.StringVar(value="A") - - def calc(*a): - try: - u = get_electricity_value(var_u, unit_u) - i = get_electricity_value(var_i, unit_i) - p = u * i - if DEBUG: print(f"Debug power_u_i: u={u} V, i={i} A, p={p} W") - if round_en: p = round(p, round_num) - result.config(text=f"{t('p')} = {p} W") - except: result.config(text="") - for v in (var_u, var_i, unit_u, unit_i): v.trace_add("write", calc) - make_title_label(content_frame, t("power"), "P = U * I", 0) - make_input_row(content_frame, t("u"), var_u, 1, unit_u, VOLTAGE_UNITS) - make_input_row(content_frame, t("i"), var_i, 3, unit_i, CURRENT_UNITS) - result = make_result_label(content_frame, 5) - -def power_i_r(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_i, var_r = tk.StringVar(), tk.StringVar() - - def calc(*a): - try: - i = get_electricity_value(var_i, unit_i) - r = get_electricity_value(var_r, unit_r) - if r == 0: - result.config(text="") - return - p = i**2 * r - if DEBUG: print(f"Debug power_i_r: i={i} A, r={r} Ω, p={p} W") - if round_en: p = round(p, round_num) - result.config(text=f"{t('p')} = {p} W") - except: result.config(text="") - for v in (var_i, var_r, unit_i, unit_r): v.trace_add("write", calc) - make_title_label(content_frame, t("power"), "P = I² * R", 0) - make_input_row(content_frame, t("i"), var_i, 1, unit_i, CURRENT_UNITS) - make_input_row(content_frame, t("r"), var_r, 3, unit_r, RESISTANCE_UNITS) - result = make_result_label(content_frame, 5) - -def power_u_r(): - clear_frame(); content_frame.columnconfigure(0, weight=1) - var_u, var_r = tk.StringVar(), tk.StringVar() - - def calc(*a): - try: - u = get_electricity_value(var_u, unit_u) - r = get_electricity_value(var_r, unit_r) - if r == 0: - result.config(text="") - return - p = u**2 / r - if DEBUG: print(f"Debug power_u_r: u={u} V, r={r} Ω, p={p} W") - if round_en: p = round(p, round_num) - result.config(text=f"{t('p')} = {p} W") - except: result.config(text="") - for v in (var_u, var_r, unit_u, unit_r): v.trace_add("write", calc) - make_title_label(content_frame, t("power"), "P = U² / R", 0) - make_input_row(content_frame, t("u"), var_u, 1, unit_u, VOLTAGE_UNITS) - make_input_row(content_frame, t("r"), var_r, 3, unit_r, RESISTANCE_UNITS) - result = make_result_label(content_frame, 5) - -def calculator(): - clear_frame() - display_var = tk.StringVar(value="0") - expr_var = tk.StringVar(value="") - - def button_click(z): - c = display_var.get() - display_var.set(str(z) if c in ("0", "Fehler", "Error") else c + str(z)) - - def clear(): - display_var.set("0"); expr_var.set("") - - def backspace(): - c = display_var.get() - display_var.set(c[:-1] if len(c) > 1 and c not in ("Fehler","Error") else "0") - - def toggle_sign(): - c = display_var.get() - try: - v = float(c) - display_var.set(("-"+c) if v > 0 else (c[1:] if v < 0 else c)) - except: pass - - def percent(): - try: - v = float(display_var.get()) / 100 - display_var.set(str(round(v, round_num) if round_en else v)) - except: pass - - def ausrechnen(event=None): - try: - ausdruck = display_var.get() - expr_var.set(ausdruck + " =") - ergebnis = eval(ausdruck) - if round_en: ergebnis = round(ergebnis, round_num) - display_var.set(str(ergebnis)) - db_add(ausdruck, ergebnis) - update_history() - except: - expr_var.set(""); display_var.set("Fehler" if language=="DE" else "Error") - - def tastatur_input(event): - if event.char in "0123456789+-*/.": button_click(event.char) - elif event.keysym == "Return": ausrechnen() - elif event.keysym in ("Escape","c","C","Delete","KP_Delete") or event.char in ("\x7f",): - clear() - elif event.keysym == "BackSpace": backspace() - - content_frame.bind_all("", tastatur_input) - - wrapper = tk.Frame(content_frame, bg="#1c1c1e") - wrapper.grid(row=0, column=0, sticky="nsew") - content_frame.rowconfigure(0, weight=1) - content_frame.columnconfigure(0, weight=1) - wrapper.columnconfigure(0, weight=1) - wrapper.rowconfigure(1, weight=1) - - display_frame = tk.Frame(wrapper, bg="#2c2c2e") - display_frame.grid(row=0, column=0, sticky="ew", padx=10, pady=(10, 6)) - tk.Label(display_frame, textvariable=expr_var, - font=("Arial", 12), bg="#2c2c2e", fg="#888888", - anchor="e", padx=12, pady=6).pack(fill="x", pady=(6, 0)) - tk.Label(display_frame, textvariable=display_var, - font=("Arial", 34, "bold"), bg="#2c2c2e", fg="white", - anchor="e", padx=12, pady=0).pack(fill="x", pady=(0, 10)) - - STYLE = { - "num": {"bg": "#2c2c2e", "fg": "white", "abg": "#3a3a3c"}, - "op": {"bg": "#3a3a3c", "fg": "#bf9fff", "abg": "#48484a"}, - "fn": {"bg": "#3a3a3c", "fg": "#aaaaaa", "abg": "#48484a"}, - "eq": {"bg": "#7c5cbf", "fg": "#ece8ff", "abg": "#5e42a0"}, - } - grid = tk.Frame(wrapper, bg="#1c1c1e") - grid.grid(row=1, column=0, sticky="nsew", padx=10, pady=(0, 6)) - for c in range(4): grid.columnconfigure(c, weight=1) - for r in range(5): grid.rowconfigure(r, weight=1) - - def make_btn(text, kind, cmd, row, col, colspan=1): - s = STYLE[kind] - tk.Button(grid, text=text, command=cmd, - bg=s["bg"], fg=s["fg"], - activebackground=s["abg"], activeforeground=s["fg"], - font=("Arial", 18), relief="flat", bd=0, - padx=0, pady=14, cursor="hand2").grid( - row=row, column=col, columnspan=colspan, - padx=4, pady=4, sticky="nsew") - - make_btn("AC", "fn", clear, 0, 0) - make_btn("+/-", "fn", toggle_sign, 0, 1) - make_btn("%", "fn", percent, 0, 2) - make_btn("÷", "op", lambda: button_click("/"), 0, 3) - make_btn("7", "num", lambda: button_click("7"), 1, 0) - make_btn("8", "num", lambda: button_click("8"), 1, 1) - make_btn("9", "num", lambda: button_click("9"), 1, 2) - make_btn("×", "op", lambda: button_click("*"), 1, 3) - make_btn("4", "num", lambda: button_click("4"), 2, 0) - make_btn("5", "num", lambda: button_click("5"), 2, 1) - make_btn("6", "num", lambda: button_click("6"), 2, 2) - make_btn("−", "op", lambda: button_click("-"), 2, 3) - make_btn("1", "num", lambda: button_click("1"), 3, 0) - make_btn("2", "num", lambda: button_click("2"), 3, 1) - make_btn("3", "num", lambda: button_click("3"), 3, 2) - make_btn("+", "op", lambda: button_click("+"), 3, 3) - make_btn("⌫", "fn", backspace, 4, 0) - make_btn("0", "num", lambda: button_click("0"), 4, 1) - make_btn(".", "num", lambda: button_click("."), 4, 2) - make_btn("=", "eq", ausrechnen, 4, 3) - - hist_frame = tk.Frame(wrapper, bg="#1c1c1e") - hist_frame.grid(row=2, column=0, sticky="ew", padx=10, pady=(0, 8)) - tk.Label(hist_frame, text=t("history"), bg="#1c1c1e", fg="#555555", - font=("Arial", 10), anchor="w").pack(fill="x", padx=6) - history_label = tk.Label(hist_frame, text="", bg="#1c1c1e", - fg="#666666", font=("Arial", 10), - anchor="e", justify="right") - history_label.pack(fill="x", padx=6) - - def update_history(): - rows = db_get_last(3) - lines = [f"{r[0]} = {r[1]}" for r in rows] - history_label.config(text="\n".join(lines)) - - update_history() - -root = tk.Tk() -root.title("Calculator") -root.geometry("500x640") -root.resizable(False, False) -root.iconbitmap(default=resource_path("bilder/icon.ico")) - -menubar = tk.Menu(root) -menu = tk.Menu(menubar, tearoff=0) -shape = tk.Menu(menu, tearoff=0) -shape_volume = tk.Menu(shape, tearoff=0) -shape_area = tk.Menu(shape, tearoff=0) -areacircle = tk.Menu(shape_area, tearoff=0) -areacylinder = tk.Menu(shape_area, tearoff=0) -areasphere = tk.Menu(shape_area, tearoff=0) -areacone = tk.Menu(shape_area, tearoff=0) -volumeclinder = tk.Menu(shape_volume, tearoff=0) -volumecone = tk.Menu(shape_volume, tearoff=0) -volumesphere = tk.Menu(shape_volume, tearoff=0) -electricity_menu = tk.Menu(menu, tearoff=0) -voltage = tk.Menu(electricity_menu, tearoff=0) -amper = tk.Menu(electricity_menu, tearoff=0) -resistance = tk.Menu(electricity_menu, tearoff=0) -power = tk.Menu(electricity_menu, tearoff=0) - -root.config(menu=menubar) - -content_frame = tk.Frame(root) -content_frame.grid(row=0, column=0, padx=10, pady=10, sticky="nsew") -root.columnconfigure(0, weight=1) -root.rowconfigure(0, weight=1) -content_frame.columnconfigure(0, weight=1) -root.config(bg=bg) -content_frame.config(bg=bg) - -creator = tk.Label(root, bg=bg, fg=fg) - -rebuild_menu() -calculator() - -threading.Thread(target=check_for_updates, daemon=True).start() - - -root.mainloop() +import tkinter as tk +from tkinter import messagebox +import math +import platform +import os +import sys +import datetime +import json +import sqlite3 +import threading +import urllib.request +import webbrowser + +VERSION_URL = "" + +def fetch_version_info(): + try: + with urllib.request.urlopen(VERSION_URL, timeout=5) as response: + return json.loads(response.read().decode()) + except Exception: + return None + +def version_is_newer(latest, current): + try: + l_parts = list(map(int, latest.split('.'))) + c_parts = list(map(int, current.split('.'))) + return l_parts > c_parts + except Exception: + return latest != current + + +def resource_path(relative_path): + if hasattr(sys, '_MEIPASS'): + return os.path.join(sys._MEIPASS, relative_path) + return os.path.join(os.path.dirname(__file__), relative_path) + +APP_DIR = os.path.join(os.environ.get("LOCALAPPDATA", os.path.expanduser("~")), "Survivalcalc") +SETTINGS_FILE = os.path.join(APP_DIR, "settings.json") +DB_FILE = os.path.join(APP_DIR, "history.db") +os.makedirs(APP_DIR, exist_ok=True) + +LANG = { + "DE": { + "menu": "Menü", + "info": "Info", + "calculator": "Rechner", + "shape": "Formen", + "area": "Fläche", + "volume": "Volumen", + "settings": "Einstellungen", + "exit": "Beenden", + "history": "Verlauf", + "appearance": "Darstellung", + "dark_mode": "Dark Mode", + "toggle": "Wechseln", + "on": "Ein ✓", + "off": "Aus", + "rounding": "Rundung", + "rounding_active": "Rundung aktiv", + "decimal_places": "Nachkommastellen", + "units": "Einheiten", + "default_unit": "Standardeinheit", + "language": "Sprache", + "delete_history": "Verlauf löschen", + "reset_settings": "Einstellungen zurücksetzen", + "confirm_del_h": "Verlauf wirklich löschen?", + "confirm_reset": "Einstellungen wirklich zurücksetzen?", + "yes": "Ja", + "no": "Nein", + "app_info": "App", + "support": "Support", + "system": "System", + "version": "Version", + "release": "Release", + "status": "Status", + "license": "Lizenz", + "installed": "Installiert am", + "website": "Website", + "email": "E-Mail", + "os": "Betriebssystem", + "os_version": "Version", + "arch": "Architektur", + "python": "Python-Version", + "error": "Bitte eine gültige Zahl eingeben.", + "area_square": "Fläche – Quadrat", + "area_rect": "Fläche – Rechteck", + "area_circle": "Fläche – Kreis", + "area_tri": "Fläche – Dreieck", + "area_trap": "Fläche – Trapez", + "area_cyl": "Fläche – Zylinder", + "area_sphere": "Fläche – Kugel", + "area_cone": "Fläche – Kegel", + "vol_cube": "Volumen – Würfel", + "vol_rect": "Volumen – Quader", + "vol_cyl": "Volumen – Zylinder", + "vol_cone": "Volumen – Kegel", + "vol_sphere": "Volumen – Kugel", + "vol_tetra": "Volumen – Tetraeder", + "vol_trap": "Volumen – Trapezprisma", + "side": "Seite", + "radius": "Radius r:", + "diameter": "Durchmesser d:", + "height": "Höhe h:", + "width": "Breite w:", + "length": "Länge l:", + "base": "Grundlinie g:", + "slant": "Mantellinie l:", + "depth": "Tiefe i:", + "with_radius": "Mit Radius", + "with_diameter": "Mit Durchmesser", + "result_area": "A", + "result_vol": "V", + "cube": "Würfel", + "rect_prism": "Quader", + "cylinder": "Zylinder", + "cone": "Kegel", + "sphere": "Kugel", + "tetrahedron": "Tetraeder", + "trap_prism": "Trapezprisma", + "square": "Quadrat", + "rectangle": "Rechteck", + "circle": "Kreis", + "triangle": "Dreieck", + "trapezoid": "Trapez", + "electricity": "Strom", + "result_voltage": "Spannung U", + "result_current": "Strom I", + "result_resistance": "Wiederstand R", + "voltage": "Spannung", + "current": "Strom", + "resistance": "Widerstand", + "power": "Leistung", + "u": "Spannung U", + "i": "Strom I", + "r": "Widerstand R", + "p": "Leistung P", + "u_i_r": "Mit Widerstand R und Strom I", + "u_p_i": "Mit Widerstand R und Leistung P", + "u_r_p": "Mit Leistung P und Strom I", + "update_available_title": "Update Verfügbar!", + "update_available_msg": ( + "Eine neue Version ({LATEST}) von Survivalcalc ist verfügbar.\n\n" + "Änderungen:\n{CHANGELOG}\n\n" + "Möchtest du die Download-Website öffnen?" + ), + "update_check_error": "Fehler bei der Update-Prüfung.", + }, + "EN": { + "menu": "Menu", + "info": "Info", + "calculator": "Calculator", + "shape": "Shapes", + "area": "Area", + "volume": "Volume", + "settings": "Settings", + "exit": "Exit", + "history": "History", + "appearance": "Appearance", + "dark_mode": "Dark Mode", + "toggle": "Toggle", + "on": "On ✓", + "off": "Off", + "rounding": "Rounding", + "rounding_active": "Rounding active", + "decimal_places": "Decimal places", + "units": "Units", + "default_unit": "Default unit", + "language": "Language", + "delete_history": "Delete history", + "reset_settings": "Reset settings", + "confirm_del_h": "Really delete history?", + "confirm_reset": "Really reset settings?", + "yes": "Yes", + "no": "No", + "app_info": "App", + "support": "Support", + "system": "System", + "version": "Version", + "release": "Release", + "status": "Status", + "license": "License", + "installed": "Installed on", + "website": "Website", + "email": "E-Mail", + "os": "Operating system", + "os_version": "Version", + "arch": "Architecture", + "python": "Python version", + "error": "Please enter a valid number.", + "area_square": "Area – Square", + "area_rect": "Area – Rectangle", + "area_circle": "Area – Circle", + "area_tri": "Area – Triangle", + "area_trap": "Area – Trapezoid", + "area_cyl": "Area – Cylinder", + "area_sphere": "Area – Sphere", + "area_cone": "Area – Cone", + "vol_cube": "Volume – Cube", + "vol_rect": "Volume – Rectangular prism", + "vol_cyl": "Volume – Cylinder", + "vol_cone": "Volume – Cone", + "vol_sphere": "Volume – Sphere", + "vol_tetra": "Volume – Tetrahedron", + "vol_trap": "Volume – Trapezoidal prism", + "side": "Side", + "radius": "Radius r:", + "diameter": "Diameter d:", + "height": "Height h:", + "width": "Width w:", + "length": "Length l:", + "base": "Base g:", + "slant": "Slant l:", + "depth": "Depth i:", + "with_radius": "With radius", + "with_diameter": "With diameter", + "result_area": "A", + "result_vol": "V", + "cube": "Cube", + "rect_prism": "Rect. prism", + "cylinder": "Cylinder", + "cone": "Cone", + "sphere": "Sphere", + "tetrahedron": "Tetrahedron", + "trap_prism": "Trapezoidal prism", + "square": "Square", + "rectangle": "Rectangle", + "circle": "Circle", + "triangle": "Triangle", + "trapezoid": "Trapezoid", + "electricity": "Electricity", + "voltage": "Voltage", + "current": "Current", + "resistance": "Resistance", + "power": "Power", + "u": "Voltage U", + "i": "Current I", + "r": "Resistance R", + "p": "Power P", + "u_i_r": "With Resistance R and Current I", + "u_p_i": "With Resistance R and Power P", + "u_r_p": "With Power P and Current I", + "i_u_r": "With Voltage U and Resistance R", + "i_p_u": "With Voltage U and Power P", + "i_r_p": "With Power P and Resistance R", + "r_u_i": "With Voltage U and Current I", + "r_u_p": "With Voltage U and Power P", + "r_p_i": "With Power P and Current I", + "update_available_title": "Update Available!", + "update_available_msg": ( + "A new version ({LATEST}) of Survivalcalc is available.\n\n" + "Changelog:\n{CHANGELOG}\n\n" + "Do you want to open the download website?" + ), + "update_check_error": "Error during update check.", + + } +} + +def t(key, **kwargs): + text = LANG[language].get(key, key) + try: + for k, v in kwargs.items(): + text = text.replace("{" + k + "}", str(v)) + except Exception: + pass + return text + +def get_install_date(): + """Liest das echte Installationsdatum aus der Registry (vom Installer gespeichert).""" + try: + import winreg + key_path = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Survivalcalc" + key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path) + install_date_str = winreg.QueryValueEx(key, "InstallDate")[0] + winreg.CloseKey(key) + return install_date_str + except Exception: + # Fallback: Nutze die Änderungszeit der Anwendung + try: + exe_path = os.path.join(os.environ.get("LOCALAPPDATA", os.path.expanduser("~")), "SurvivalCalc", "main.exe") + if os.path.exists(exe_path): + mtime = os.path.getmtime(exe_path) + return datetime.datetime.fromtimestamp(mtime).strftime("%d.%m.%Y %H:%M") + except Exception: + pass + # Fallback: Aktuelles Datum + return datetime.datetime.now().strftime("%d.%m.%Y %H:%M") + + +app_version = "1.0.2" +app_release = "24.3.2026" +app_status = "Stable" +dev_e_mail = "team@survivalful.de" +dev_website = "https://Survivalful.de/" +app_license = "GPL License © 2026 Survivalful" +sys_system = platform.system() +sys_version = platform.release() +sys_machine = platform.machine() +sys_python = platform.python_version() +install_date = get_install_date() + +DEFAULT_SETTINGS = { + "bg_dark": True, + "round_num": 2, + "round_en": True, + "default_unit": "m", + "language": "EN", +} + +DEBUG = True + +def load_settings(): + global bg_dark, round_num, round_en, default_unit, language, bg, fg + if os.path.exists(SETTINGS_FILE): + with open(SETTINGS_FILE, "r") as f: + s = json.load(f) + else: + s = DEFAULT_SETTINGS.copy() + bg_dark = s.get("bg_dark", DEFAULT_SETTINGS["bg_dark"]) + round_num = s.get("round_num", DEFAULT_SETTINGS["round_num"]) + round_en = s.get("round_en", DEFAULT_SETTINGS["round_en"]) + default_unit = s.get("default_unit", DEFAULT_SETTINGS["default_unit"]) + language = s.get("language", DEFAULT_SETTINGS["language"]) + bg = 'black' if bg_dark else 'white' + fg = 'white' if bg_dark else 'black' + +def save_settings(): + with open(SETTINGS_FILE, "w") as f: + json.dump({ + "bg_dark": bg_dark, + "round_num": round_num, + "round_en": round_en, + "default_unit": default_unit, + "language": language, + }, f, indent=2) + +def init_db(): + con = sqlite3.connect(DB_FILE) + con.execute("""CREATE TABLE IF NOT EXISTS history ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + expr TEXT, + result TEXT, + timestamp TEXT + )""") + con.commit() + con.close() + +def db_add(expr, result): + con = sqlite3.connect(DB_FILE) + con.execute("INSERT INTO history (expr, result, timestamp) VALUES (?,?,?)", + (expr, str(result), datetime.datetime.now().strftime("%d.%m.%Y %H:%M:%S"))) + con.commit() + con.close() + +def db_get_last(n=3): + con = sqlite3.connect(DB_FILE) + rows = con.execute( + "SELECT expr, result FROM history ORDER BY id DESC LIMIT ?", (n,) + ).fetchall() + con.close() + return rows + +def db_clear(): + con = sqlite3.connect(DB_FILE) + con.execute("DELETE FROM history") + con.commit() + con.close() + +load_settings() +init_db() + +def check_for_updates(): + try: + info = fetch_version_info() + if not info: + return + + latest_version = info.get("version") + changelog = info.get("changelog", "Keine Informationen verfügbar.") + download_url = info.get("installer_url") + + if not (latest_version and version_is_newer(latest_version, app_version)): + return + + def show_update_dialog(): + title = t("update_available_title") + message = t("update_available_msg", LATEST=latest_version, CHANGELOG=changelog) + + if not messagebox.askyesno(title, message): + return + + win = tk.Toplevel(root) + win.title("Update wird heruntergeladen...") + win.geometry("360x120") + win.resizable(False, False) + win.config(bg=bg) + win.grab_set() + + tk.Label(win, text=f"Version {latest_version} wird heruntergeladen...", + bg=bg, fg=fg, font=("Arial", 11)).pack(pady=(18, 6)) + + progress = tk.DoubleVar() + bar = tk.Scale(win, variable=progress, from_=0, to=100, + orient="horizontal", state="disabled", + bg=bg, fg=fg, troughcolor="#2c2c2e", + highlightthickness=0, relief="flat", sliderrelief="flat") + bar.pack(fill="x", padx=24) + + status_lbl = tk.Label(win, text="0%", bg=bg, fg="#888888", font=("Arial", 10)) + status_lbl.pack() + + def do_download(): + try: + import tempfile + tmp_dir = tempfile.gettempdir() + installer_path = os.path.join(tmp_dir, "Survivalcalc_Installer.exe") + + def reporthook(block_num, block_size, total_size): + if total_size > 0: + pct = min(100, block_num * block_size * 100 / total_size) + progress.set(pct) + status_lbl.config(text=f"{int(pct)}%") + win.update_idletasks() + + urllib.request.urlretrieve(download_url, installer_path, reporthook) + + win.destroy() + + import subprocess + subprocess.Popen([installer_path]) + root.quit() + + except Exception as e: + win.destroy() + messagebox.showerror("Fehler", f"Download fehlgeschlagen:\n{e}") + + threading.Thread(target=do_download, daemon=True).start() + + root.after(0, show_update_dialog) + + except Exception as e: + print(f"Update-Check fehlgeschlagen: {e}") + + +UNIT_FACTORS = { + "pm": 1e-12, "nm": 1e-9, "μm": 1e-6, "mm": 0.001, "cm": 0.01, "dm": 0.1, + "m": 1.0, "km": 1000, "Mm": 1e6, "Gm": 1e9 +} +UNITS = list(UNIT_FACTORS.keys()) + +ELECTRICITY_PREFIXES = { + "p": 1e-12, "n": 1e-9, "μ": 1e-6, "m": 0.001, "c": 0.01, "d": 0.1, + "": 1, "k": 1000, "M": 1e6, "G": 1e9 +} +VOLTAGE_UNITS = ["pV", "nV", "μV", "mV", "V", "kV", "MV", "GV"] +CURRENT_UNITS = ["pA", "nA", "μA", "mA", "A", "kA", "MA", "GA"] +RESISTANCE_UNITS = ["pΩ", "nΩ", "μΩ", "mΩ", "Ω", "kΩ", "MΩ", "GΩ"] +POWER_UNITS = ["pW", "nW", "μW", "mW", "W", "kW", "MW", "GW"] + +COLOR_DIGITS = { + "Black": 0, "Brown": 1, "Red": 2, "Orange": 3, "Yellow": 4, + "Green": 5, "Blue": 6, "Violet": 7, "Grey": 8, "White": 9 +} +COLOR_MULTIPLIER = { + "Black": 1, "Brown": 10, "Red": 100, "Orange": 1_000, "Yellow": 10_000, + "Green": 100_000, "Blue": 1_000_000, "Violet": 10_000_000, "Grey": 100_000_000, + "White": 1_000_000_000, "Gold": 0.1, "Silver": 0.01 +} +COLOR_TOLERANCE = { + "Brown": "±1%", "Red": "±2%", "Green": "±0.5%", "Blue": "±0.25%", + "Violet": "±0.1%", "Grey": "±0.05%", "Gold": "±5%", "Silver": "±10%", + "None": "±20%" +} + +COLOR_HEX = { + "Black": "#000000", "Brown": "#8B4513", "Red": "#FF0000", "Orange": "#FFA500", + "Yellow": "#FFFF00", "Green": "#008000", "Blue": "#0000FF", "Violet": "#8A2BE2", + "Grey": "#808080", "White": "#FFFFFF", "Gold": "#D4AF37", "Silver": "#C0C0C0", "None": "#CCCCCC" +} + +def half(first, last): + return first / last + +def make_section(parent, title, row): + parent.rowconfigure(row, weight=0) + f = tk.Frame(parent, bg=bg) + f.grid(row=row, column=0, columnspan=3, sticky="ew", padx=12, pady=(16, 4)) + tk.Label(f, text=title, bg=bg, fg="#7c5cbf", + font=("Arial", 10, "bold"), anchor="w").pack(side="left") + tk.Frame(f, bg="#333333" if bg_dark else "#cccccc", + height=1).pack(side="left", fill="x", expand=True, padx=(8, 0)) + +def make_input_row(parent, label_text, var, row, unit_var=None, units=UNITS): + parent.rowconfigure(row, weight=0) + parent.rowconfigure(row + 1, weight=0) + tk.Label(parent, text=label_text, bg=bg, fg=fg, + font=("Arial", 11), anchor="w").grid( + row=row, column=0, sticky="nw", padx=16, pady=(8, 0)) + row_frame = tk.Frame(parent, bg=bg) + row_frame.grid(row=row+1, column=0, sticky="ew", padx=16, pady=(2, 4)) + row_frame.columnconfigure(0, weight=1) + entry = tk.Entry(row_frame, textvariable=var, + bg="#2c2c2e" if bg_dark else "#f0f0f0", + fg=fg, insertbackground=fg, + font=("Arial", 14), relief="flat", bd=0, + highlightthickness=1, + highlightbackground="#444" if bg_dark else "#ccc", + highlightcolor="#7c5cbf") + entry.grid(row=0, column=0, sticky="ew", ipady=6) + if unit_var is not None: + um = tk.OptionMenu(row_frame, unit_var, *units) + um.config(bg="#2c2c2e" if bg_dark else "#f0f0f0", fg=fg, + activebackground="#3a3a3c", activeforeground=fg, + relief="flat", highlightthickness=0, + font=("Arial", 11), width=4) + um["menu"].config(bg="#2c2c2e" if bg_dark else "#f0f0f0", fg=fg) + um.grid(row=0, column=1, padx=(4, 0), ipady=3) + return entry + +def make_result_label(parent, row): + parent.rowconfigure(row, weight=0) + r = tk.Label(parent, text="", bg=bg, + fg="#bf9fff" if bg_dark else "#7c5cbf", + font=("Arial", 16, "bold"), anchor="w") + r.grid(row=row, column=0, sticky="nw", padx=16, pady=(4, 12)) + return r + +def make_title_label(parent, text, symbol, row): + parent.rowconfigure(row, weight=0) + frame = tk.Frame(parent, bg=bg) + frame.grid(row=row, column=0, sticky="nw", padx=16, pady=(12, 2)) + tk.Label(frame, text=text, bg=bg, fg=fg, + font=("Arial", 13, "bold"), anchor="w").pack(side="left") + tk.Label(frame, text=f" {symbol}", bg=bg, + fg="#888888" if bg_dark else "#aaaaaa", + font=("Arial", 11), anchor="w").pack(side="left") + return frame + +def get_m(var, unit_var): + return float(var.get()) * UNIT_FACTORS[unit_var.get()] + +def get_electricity_value(var, unit_var): + unit = unit_var.get() + prefix = unit[:-1] if len(unit) > 1 else "" + base_unit = unit[-1] + factor = ELECTRICITY_PREFIXES.get(prefix, 1) + return float(var.get()) * factor + +def format_result(val, unit_var): + return val / (UNIT_FACTORS[unit_var.get()] ** 2) + +def format_vol(val, unit_var): + return val / (UNIT_FACTORS[unit_var.get()] ** 3) + +def clear_frame(): + for widget in content_frame.winfo_children(): + widget.destroy() + for i in range(20): + content_frame.rowconfigure(i, weight=0) + content_frame.columnconfigure(0, weight=1) + +def make_scroll_frame(parent): + canvas = tk.Canvas(parent, bg=bg, highlightthickness=0) + scrollbar = tk.Scrollbar(parent, orient="vertical", command=canvas.yview) + inner = tk.Frame(canvas, bg=bg) + inner.bind("", + lambda e: canvas.configure(scrollregion=canvas.bbox("all"))) + canvas.create_window((0, 0), window=inner, anchor="nw") + canvas.configure(yscrollcommand=scrollbar.set) + canvas.pack(side="left", fill="both", expand=True) + scrollbar.pack(side="right", fill="y") + def on_mousewheel(event): + canvas.yview_scroll(int(-1*(event.delta/120)), "units") + canvas.bind_all("", on_mousewheel) + return inner + +def rebuild_menu(): + menubar.delete(0, "end") + menu.delete(0, "end") + shape_area.delete(0, "end") + shape_volume.delete(0, "end") + shape.delete(0, "end") + areacircle.delete(0, "end") + areacylinder.delete(0, "end") + areasphere.delete(0, "end") + areacone.delete(0, "end") + volumeclinder.delete(0, "end") + volumecone.delete(0, "end") + volumesphere.delete(0, "end") + electricity_menu.delete(0, "end") + voltage.delete(0, "end") + amper.delete(0, "end") + resistance.delete(0, "end") + power.delete(0, "end") + + areacircle.add_command(label=t("with_radius"), command=area_circle_radius) + areacircle.add_command(label=t("with_diameter"), command=area_circle_diameter) + areacylinder.add_command(label=t("with_radius"), command=area_cylinder_radius) + areacylinder.add_command(label=t("with_diameter"), command=area_cylinder_diameter) + areasphere.add_command(label=t("with_radius"), command=area_sphere_radius) + areasphere.add_command(label=t("with_diameter"), command=area_sphere_diameter) + areacone.add_command(label=t("with_radius"), command=area_cone_radius) + areacone.add_command(label=t("with_diameter"), command=area_cone_diameter) + volumeclinder.add_command(label=t("with_radius"), command=volume_cylinder_radius) + volumeclinder.add_command(label=t("with_diameter"), command=volume_cylinder_diameter) + volumecone.add_command(label=t("with_radius"), command=volume_cone_radius) + volumecone.add_command(label=t("with_diameter"), command=volume_cone_diameter) + volumesphere.add_command(label=t("with_radius"), command=volume_sphere_radius) + volumesphere.add_command(label=t("with_diameter"), command=volume_sphere_diameter) + shape_area.add_command(label=t("square"), command=area_square) + shape_area.add_command(label=t("rectangle"), command=area_rectangle) + shape_area.add_cascade(label=t("circle"), menu=areacircle) + shape_area.add_command(label=t("triangle"), command=area_triangle) + shape_area.add_command(label=t("trapezoid"), command=area_trapezoid) + shape_area.add_cascade(label=t("cylinder"), menu=areacylinder) + shape_area.add_cascade(label=t("sphere"), menu=areasphere) + shape_area.add_cascade(label=t("cone"), menu=areacone) + shape_volume.add_command(label=t("cube"), command=volume_cube) + shape_volume.add_command(label=t("rect_prism"), command=volume_rectangular_prism) + shape_volume.add_cascade(label=t("cylinder"), menu=volumeclinder) + shape_volume.add_cascade(label=t("cone"), menu=volumecone) + shape_volume.add_cascade(label=t("sphere"), menu=volumesphere) + shape_volume.add_command(label=t("tetrahedron"), command=volume_tetrahedron) + shape_volume.add_command(label=t("trap_prism"), command=volume_trapezoidal_prism) + electricity_menu.add_cascade(label=t("voltage"), menu=voltage) + voltage.add_command(label=t("u_i_r"), command=voltage_i_r) + voltage.add_command(label=t("u_p_i"), command=voltage_p_i) + voltage.add_command(label=t("u_r_p"), command=voltage_r_p) + electricity_menu.add_cascade(label=t("current"), menu=amper) + amper.add_command(label=t("i_u_r"), command=current_u_r) + amper.add_command(label=t("i_p_u"), command=current_p_u) + amper.add_command(label=t("i_r_p"), command=current_p_r) + electricity_menu.add_cascade(label=t("resistance"), menu=resistance) + resistance.add_command(label=t("r_u_i"), command=resistance_u_i) + resistance.add_command(label=t("r_u_p"), command=resistance_u_p) + resistance.add_command(label=t("r_p_i"), command=resistance_p_i) + electricity_menu.add_cascade(label=t("power"),menu=power) + electricity_menu.add_command(label="Widerstand (Farbcode)", command=resistance_color_bands) + power.add_command(label=t("u_i_r"), command=power_u_i) + power.add_command(label=t("u_r_p"), command=power_i_r) + power.add_command(label=t("r_p_i"), command=power_u_r) + shape.add_cascade(label=t("area"), menu=shape_area) + shape.add_cascade(label=t("volume"), menu=shape_volume) + menu.add_command(label=t("info"), command=info) + menu.add_command(label=t("calculator"), command=calculator) + menu.add_cascade(label=t("shape"), menu=shape) + menu.add_cascade(label=t("electricity"), menu=electricity_menu) + menu.add_command(label=t("settings"), command=settings) + menu.add_command(label=t("exit"), command=do_exit) + menubar.add_cascade(label=t("menu"), menu=menu) + +def info(): + clear_frame() + content_frame.rowconfigure(0, weight=1) + content_frame.columnconfigure(0, weight=1) + inner = make_scroll_frame(content_frame) + inner.columnconfigure(0, weight=1) + def info_row(parent, label, value, r): + tk.Label(parent, text=label, + bg="#1e1e1e" if bg_dark else "#f5f5f5", + fg="#888888" if bg_dark else "#777777", + font=("Arial", 10), anchor="w").grid( + row=r, column=0, sticky="w", padx=14, pady=(5, 0)) + tk.Label(parent, text=value, + bg="#1e1e1e" if bg_dark else "#f5f5f5", + fg=fg, font=("Arial", 11), anchor="w").grid( + row=r+1, column=0, sticky="w", padx=14, pady=(0, 5)) + def card(title, items, row): + inner.rowconfigure(row, weight=0) + outer = tk.Frame(inner, bg="#7c5cbf") + outer.grid(row=row, column=0, sticky="ew", padx=16, pady=(10, 0)) + outer.columnconfigure(0, weight=1) + tk.Label(outer, text=title, bg="#7c5cbf", fg="#ece8ff", + font=("Arial", 11, "bold"), anchor="w", + padx=10, pady=6).grid(row=0, column=0, sticky="w") + body = tk.Frame(outer, bg="#1e1e1e" if bg_dark else "#f5f5f5") + body.grid(row=1, column=0, sticky="ew", padx=1, pady=(0, 1)) + body.columnconfigure(0, weight=1) + for i, (lbl, val) in enumerate(items): + info_row(body, lbl, val, i*2) + card(t("app_info"), [ + (t("version"), app_version), + (t("release"), app_release), + (t("status"), app_status), + (t("license"), app_license), + (t("installed"), install_date), + ("App-Ordner", APP_DIR), + ], 0) + card(t("support"), [ + (t("website"), dev_website), + (t("email"), dev_e_mail), + ], 1) + card(t("system"), [ + (t("os"), sys_system), + (t("os_version"), sys_version), + (t("arch"), sys_machine), + (t("python"), sys_python), + ], 2) + +def do_exit(): + root.quit() + +def settings(): + clear_frame() + content_frame.rowconfigure(0, weight=1) + content_frame.columnconfigure(0, weight=1) + inner = make_scroll_frame(content_frame) + inner.columnconfigure(0, weight=1) + inner.columnconfigure(1, weight=1) + inner.columnconfigure(2, weight=0) + make_section(inner, t("appearance"), 0) + def bg_toggle(): + global bg_dark, bg, fg + bg_dark = not bg_dark + bg = 'black' if bg_dark else 'white' + fg = 'white' if bg_dark else 'black' + root.config(bg=bg) + content_frame.config(bg=bg) + creator.config(bg=bg, fg=fg) + save_settings() + settings() + inner.rowconfigure(1, weight=0) + tk.Label(inner, text=t("dark_mode"), bg=bg, fg=fg, + font=("Arial", 11), anchor="w").grid( + row=1, column=0, sticky="w", padx=16, pady=8) + tk.Label(inner, text=t("on") if bg_dark else t("off"), + bg=bg, fg="#bf9fff" if bg_dark else "#7c5cbf", + font=("Arial", 11)).grid(row=1, column=1, sticky="w") + tk.Button(inner, text=t("toggle"), command=bg_toggle, + bg="#2c2c2e" if bg_dark else "#eeeeee", fg=fg, + relief="flat", padx=10, pady=4, cursor="hand2").grid( + row=1, column=2, padx=16, pady=8, sticky="e") + make_section(inner, t("rounding"), 2) + def round_toggle(): + global round_en + round_en = not round_en + round_lbl.config(text=t("on") if round_en else t("off"), + fg="#bf9fff" if round_en else "#888888") + save_settings() + inner.rowconfigure(3, weight=0) + tk.Label(inner, text=t("rounding_active"), bg=bg, fg=fg, + font=("Arial", 11), anchor="w").grid( + row=3, column=0, sticky="w", padx=16, pady=8) + round_lbl = tk.Label(inner, + text=t("on") if round_en else t("off"), + bg=bg, + fg="#bf9fff" if round_en else "#888888", + font=("Arial", 11)) + round_lbl.grid(row=3, column=1, sticky="w") + tk.Button(inner, text=t("toggle"), command=round_toggle, + bg="#2c2c2e" if bg_dark else "#eeeeee", fg=fg, + relief="flat", padx=10, pady=4, cursor="hand2").grid( + row=3, column=2, padx=16, pady=8, sticky="e") + inner.rowconfigure(4, weight=0) + inner.rowconfigure(5, weight=0) + tk.Label(inner, text=t("decimal_places"), bg=bg, fg=fg, + font=("Arial", 11), anchor="w").grid( + row=4, column=0, sticky="w", padx=16, pady=(8, 0)) + slider_val = tk.Label(inner, text=str(round_num), + bg=bg, fg="#bf9fff" if bg_dark else "#7c5cbf", + font=("Arial", 11, "bold")) + slider_val.grid(row=4, column=1, sticky="w") + def on_slider(val): + global round_num + round_num = int(float(val)) + slider_val.config(text=str(round_num)) + save_settings() + tk.Scale(inner, from_=0, to=20, orient="horizontal", + command=on_slider, + bg=bg, fg=fg, + troughcolor="#2c2c2e" if bg_dark else "#dddddd", + highlightthickness=0, showvalue=False, + relief="flat", sliderrelief="flat", + activebackground="#7c5cbf").grid( + row=5, column=0, columnspan=3, sticky="ew", padx=16, pady=(0, 8)) + make_section(inner, t("units"), 6) + inner.rowconfigure(7, weight=0) + tk.Label(inner, text=t("default_unit"), bg=bg, fg=fg, + font=("Arial", 11), anchor="w").grid( + row=7, column=0, sticky="w", padx=16, pady=8) + unit_var = tk.StringVar(value=default_unit) + def on_unit(*args): + global default_unit + default_unit = unit_var.get() + save_settings() + unit_var.trace_add("write", on_unit) + um = tk.OptionMenu(inner, unit_var, *UNITS) + um.config(bg="#2c2c2e" if bg_dark else "#f0f0f0", fg=fg, + activebackground="#3a3a3c", activeforeground=fg, + relief="flat", highlightthickness=0, + font=("Arial", 11), width=4) + um["menu"].config(bg="#2c2c2e" if bg_dark else "#f0f0f0", fg=fg) + um.grid(row=7, column=1, columnspan=2, sticky="w", padx=4, pady=8) + make_section(inner, t("language"), 8) + inner.rowconfigure(9, weight=0) + tk.Label(inner, text=t("language"), bg=bg, fg=fg, + font=("Arial", 11), anchor="w").grid( + row=9, column=0, sticky="w", padx=16, pady=8) + lang_var = tk.StringVar(value=language) + def on_lang(*args): + global language + language = lang_var.get() + save_settings() + rebuild_menu() + settings() + lang_var.trace_add("write", on_lang) + for i, lang in enumerate(["DE", "EN"]): + tk.Radiobutton(inner, text=lang, variable=lang_var, value=lang, + bg=bg, fg=fg, + selectcolor="#2c2c2e" if bg_dark else "#dddddd", + activebackground=bg, activeforeground=fg, + font=("Arial", 11)).grid( + row=9, column=1+i, sticky="w", + padx=(4 if i == 0 else 0, 0), pady=8) + make_section(inner, "Datenverwaltung" if language == "DE" else "Data management", 10) + def del_history(): + if messagebox.askyesno(t("delete_history"), t("confirm_del_h")): + db_clear() + def reset_s(): + if messagebox.askyesno(t("reset_settings"), t("confirm_reset")): + global bg_dark, round_num, round_en, default_unit, language, bg, fg + bg_dark = DEFAULT_SETTINGS["bg_dark"] + round_num = DEFAULT_SETTINGS["round_num"] + round_en = DEFAULT_SETTINGS["round_en"] + default_unit = DEFAULT_SETTINGS["default_unit"] + language = DEFAULT_SETTINGS["language"] + bg = 'black' if bg_dark else 'white' + fg = 'white' if bg_dark else 'black' + save_settings() + root.config(bg=bg) + content_frame.config(bg=bg) + creator.config(bg=bg, fg=fg) + rebuild_menu() + settings() + inner.rowconfigure(11, weight=0) + inner.rowconfigure(12, weight=0) + tk.Button(inner, text=t("delete_history"), command=del_history, + bg="#3a1a1a", fg="#ff8080", + relief="flat", padx=10, pady=6, cursor="hand2", + font=("Arial", 11)).grid( + row=11, column=0, columnspan=3, sticky="ew", padx=16, pady=(8, 4)) + tk.Button(inner, text=t("reset_settings"), command=reset_s, + bg="#2a1a3a", fg="#bf9fff", + relief="flat", padx=10, pady=6, cursor="hand2", + font=("Arial", 11)).grid( + row=12, column=0, columnspan=3, sticky="ew", padx=16, pady=(0, 16)) + +def area_square(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var, unit_var = tk.StringVar(), tk.StringVar(value=default_unit) + def calc(*a): + try: + v = get_m(var, unit_var); s = v**2 + if DEBUG: print(f"Debug area_square: v={v}, s={s}, unit={unit_var.get()}") + if round_en: s = round(s, round_num) + result.config(text=f"{t('result_area')} = {s} m²") + except: result.config(text="") + var.trace_add("write", calc); unit_var.trace_add("write", calc) + make_title_label(content_frame, t("area_square"), "A = a²", 0) + make_input_row(content_frame, f"{t('side')} a:", var, 1, unit_var) + result = make_result_label(content_frame, 3) + +def area_rectangle(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_a, var_b = tk.StringVar(), tk.StringVar() + unit_a, unit_b = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) + def calc(*a): + try: + a = get_m(var_a, unit_a); b = get_m(var_b, unit_b); s = a * b + if DEBUG: print(f"Debug area_rectangle: a={a}, b={b}, s={s}, unit_a={unit_a.get()}, unit_b={unit_b.get()}") + if round_en: s = round(s, round_num) + result.config(text=f"{t('result_area')} = {s} m²") + except: result.config(text="") + var_a.trace_add("write", calc); var_b.trace_add("write", calc) + unit_a.trace_add("write", calc); unit_b.trace_add("write", calc) + make_title_label(content_frame, t("area_rect"), "A = a · b", 0) + make_input_row(content_frame, f"{t('side')} a:", var_a, 1, unit_a) + make_input_row(content_frame, f"{t('side')} b:", var_b, 3, unit_b) + result = make_result_label(content_frame, 5) + +def area_circle_radius(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_r, unit_var = tk.StringVar(), tk.StringVar(value=default_unit) + def calc(*a): + try: + r = get_m(var_r, unit_var); s = math.pi * r**2 + if DEBUG: print(f"Debug area_circle_radius: r={r}, s={s}, unit={unit_var.get()}") + if round_en: s = round(s, round_num) + result.config(text=f"{t('result_area')} = {s} m²") + except: result.config(text="") + var_r.trace_add("write", calc); unit_var.trace_add("write", calc) + make_title_label(content_frame, t("area_circle"), "A = π · r²", 0) + make_input_row(content_frame, t("radius"), var_r, 1, unit_var) + result = make_result_label(content_frame, 3) + +def area_circle_diameter(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_d, unit_var = tk.StringVar(), tk.StringVar(value=default_unit) + def calc(*a): + try: + r = get_m(var_d, unit_var)/2; s = math.pi * r**2 + if DEBUG: print(f"Debug area_circle_diameter: d={get_m(var_d, unit_var)}, r={r}, s={s}, unit={unit_var.get()}") + if round_en: s = round(s, round_num) + result.config(text=f"{t('result_area')} = {s} m²") + except: result.config(text="") + var_d.trace_add("write", calc); unit_var.trace_add("write", calc) + make_title_label(content_frame, t("area_circle"), "A = π · (d/2)²", 0) + make_input_row(content_frame, t("diameter"), var_d, 1, unit_var) + result = make_result_label(content_frame, 3) + +def area_triangle(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_g, var_h = tk.StringVar(), tk.StringVar() + unit_g, unit_h = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) + def calc(*a): + try: + g = get_m(var_g, unit_g); h = get_m(var_h, unit_h); s = 0.5 * g * h + if DEBUG: print(f"Debug area_triangle: g={g}, h={h}, s={s}, unit_g={unit_g.get()}, unit_h={unit_h.get()}") + if round_en: s = round(s, round_num) + result.config(text=f"{t('result_area')} = {s} m²") + except: result.config(text="") + var_g.trace_add("write", calc); var_h.trace_add("write", calc) + unit_g.trace_add("write", calc); unit_h.trace_add("write", calc) + make_title_label(content_frame, t("area_tri"), "A = g · h / 2", 0) + make_input_row(content_frame, t("base"), var_g, 1, unit_g) + make_input_row(content_frame, t("height"), var_h, 3, unit_h) + result = make_result_label(content_frame, 5) + +def area_trapezoid(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_a, var_b, var_h = tk.StringVar(), tk.StringVar(), tk.StringVar() + unit_a, unit_b, unit_h = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) + def calc(*a): + try: + a = get_m(var_a, unit_a); b = get_m(var_b, unit_b); h = get_m(var_h, unit_h); s = ((a + b) / 2) * h + if DEBUG: print(f"Debug area_trapezoid: a={a}, b={b}, h={h}, s={s}, unit_a={unit_a.get()}, unit_b={unit_b.get()}, unit_h={unit_h.get()}") + if round_en: s = round(s, round_num) + result.config(text=f"{t('result_area')} = {s} m²") + except: result.config(text="") + var_a.trace_add("write", calc); var_b.trace_add("write", calc); var_h.trace_add("write", calc) + unit_a.trace_add("write", calc); unit_b.trace_add("write", calc); unit_h.trace_add("write", calc) + make_title_label(content_frame, t("area_trap"), "A = (a+b)/2 · h", 0) + make_input_row(content_frame, f"{t('side')} a:", var_a, 1, unit_a) + make_input_row(content_frame, f"{t('side')} b:", var_b, 3, unit_b) + make_input_row(content_frame, t("height"), var_h, 5, unit_h) + result = make_result_label(content_frame, 7) + +def area_cylinder_radius(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_r, var_h = tk.StringVar(), tk.StringVar() + unit_r, unit_h = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) + def calc(*a): + try: + r, h = get_m(var_r,unit_r), get_m(var_h,unit_h) + s = 2*math.pi*r*h + 2*math.pi*r**2 + if DEBUG: print(f"Debug area_cylinder_radius: r={r}, h={h}, s={s}, unit_r={unit_r.get()}, unit_h={unit_h.get()}") + if round_en: s = round(s, round_num) + result.config(text=f"{t('result_area')} = {s} m²") + except: result.config(text="") + var_r.trace_add("write", calc); var_h.trace_add("write", calc) + unit_r.trace_add("write", calc); unit_h.trace_add("write", calc) + make_title_label(content_frame, t("area_cyl"), "A = 2πr(r+h)", 0) + make_input_row(content_frame, t("radius"), var_r, 1, unit_r) + make_input_row(content_frame, t("height"), var_h, 3, unit_h) + result = make_result_label(content_frame, 5) + +def area_cylinder_diameter(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_d, var_h = tk.StringVar(), tk.StringVar() + unit_d, unit_h = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) + def calc(*a): + try: + r, h = get_m(var_d,unit_d)/2, get_m(var_h,unit_h) + s = 2*math.pi*r*h + 2*math.pi*r**2 + if DEBUG: print(f"Debug area_cylinder_diameter: d={get_m(var_d,unit_d)}, r={r}, h={h}, s={s}, unit_d={unit_d.get()}, unit_h={unit_h.get()}") + if round_en: s = round(s, round_num) + result.config(text=f"{t('result_area')} = {s} m²") + except: result.config(text="") + var_d.trace_add("write", calc); var_h.trace_add("write", calc) + unit_d.trace_add("write", calc); unit_h.trace_add("write", calc) + make_title_label(content_frame, t("area_cyl"), "A = 2πr(r+h)", 0) + make_input_row(content_frame, t("diameter"), var_d, 1, unit_d) + make_input_row(content_frame, t("height"), var_h, 3, unit_h) + result = make_result_label(content_frame, 5) + +def area_sphere_radius(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_r = tk.StringVar() + unit_r = tk.StringVar(value=default_unit) + def calc(*a): + try: + s = 4*math.pi*get_m(var_r,unit_r)**2 + if DEBUG: print(f"Debug area_sphere_radius: r={get_m(var_r,unit_r)}, s={s}, unit={unit_r.get()}") + if round_en: s = round(s, round_num) + result.config(text=f"{t('result_area')} = {s} m²") + except: result.config(text="") + var_r.trace_add("write", calc); unit_r.trace_add("write", calc) + make_title_label(content_frame, t("area_sphere"), "A = 4πr²", 0) + make_input_row(content_frame, t("radius"), var_r, 1, unit_r) + result = make_result_label(content_frame, 3) + +def area_sphere_diameter(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_d = tk.StringVar() + unit_d = tk.StringVar(value=default_unit) + def calc(*a): + try: + s = 4*math.pi*(get_m(var_d,unit_d)/2)**2 + if DEBUG: print(f"Debug area_sphere_diameter: d={get_m(var_d,unit_d)}, r={get_m(var_d,unit_d)/2}, s={s}, unit={unit_d.get()}") + if round_en: s = round(s, round_num) + result.config(text=f"{t('result_area')} = {s} m²") + except: result.config(text="") + var_d.trace_add("write", calc); unit_d.trace_add("write", calc) + make_title_label(content_frame, t("area_sphere"), "A = 4π(d/2)²", 0) + make_input_row(content_frame, t("diameter"), var_d, 1, unit_d) + result = make_result_label(content_frame, 3) + +def area_cone_radius(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_r, var_l = tk.StringVar(), tk.StringVar() + unit_r, unit_l = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) + def calc(*a): + try: + r, l = get_m(var_r,unit_r), get_m(var_l,unit_l) + s = math.pi*r*(r+l) + if DEBUG: print(f"Debug area_cone_radius: r={r}, l={l}, s={s}, unit_r={unit_r.get()}, unit_l={unit_l.get()}") + if round_en: s = round(s, round_num) + result.config(text=f"{t('result_area')} = {s} m²") + except: result.config(text="") + var_r.trace_add("write", calc); var_l.trace_add("write", calc) + unit_r.trace_add("write", calc); unit_l.trace_add("write", calc) + make_title_label(content_frame, t("area_cone"), "A = πr(r+l)", 0) + make_input_row(content_frame, t("radius"), var_r, 1, unit_r) + make_input_row(content_frame, t("slant"), var_l, 3, unit_l) + result = make_result_label(content_frame, 5) + +def area_cone_diameter(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_d, var_l = tk.StringVar(), tk.StringVar() + unit_d, unit_l = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) + def calc(*a): + try: + r, l = get_m(var_d,unit_d)/2, get_m(var_l,unit_l) + s = math.pi*r*(r+l) + if DEBUG: print(f"Debug area_cone_diameter: d={get_m(var_d,unit_d)}, r={r}, l={l}, s={s}, unit_d={unit_d.get()}, unit_l={unit_l.get()}") + if round_en: s = round(s, round_num) + result.config(text=f"{t('result_area')} = {s} m²") + except: result.config(text="") + var_d.trace_add("write", calc); var_l.trace_add("write", calc) + unit_d.trace_add("write", calc); unit_l.trace_add("write", calc) + make_title_label(content_frame, t("area_cone"), "A = πr(r+l)", 0) + make_input_row(content_frame, t("diameter"), var_d, 1, unit_d) + make_input_row(content_frame, t("slant"), var_l, 3, unit_l) + result = make_result_label(content_frame, 5) + +def volume_cube(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_a = tk.StringVar() + unit_a = tk.StringVar(value=default_unit) + def calc(*a): + try: + a = get_m(var_a,unit_a); s = a**3 + if DEBUG: print(f"Debug volume_cube: a={a}, s={s}, unit={unit_a.get()}") + if round_en: s = round(s, round_num) + result.config(text=f"{t('result_vol')} = {s} m³") + except: result.config(text="") + var_a.trace_add("write", calc); unit_a.trace_add("write", calc) + make_title_label(content_frame, t("vol_cube"), "V = a³", 0) + make_input_row(content_frame, f"{t('side')} a:", var_a, 1, unit_a) + result = make_result_label(content_frame, 3) + +def volume_rectangular_prism(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_l, var_w, var_h = tk.StringVar(), tk.StringVar(), tk.StringVar() + unit_l, unit_w, unit_h = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) + def calc(*a): + try: + l = get_m(var_l,unit_l); w = get_m(var_w,unit_w); h = get_m(var_h,unit_h); s = l * w * h + if DEBUG: print(f"Debug volume_rectangular_prism: l={l}, w={w}, h={h}, s={s}, unit_l={unit_l.get()}, unit_w={unit_w.get()}, unit_h={unit_h.get()}") + if round_en: s = round(s, round_num) + result.config(text=f"{t('result_vol')} = {s} m³") + except: result.config(text="") + var_l.trace_add("write", calc); var_w.trace_add("write", calc); var_h.trace_add("write", calc) + unit_l.trace_add("write", calc); unit_w.trace_add("write", calc); unit_h.trace_add("write", calc) + make_title_label(content_frame, t("vol_rect"), "V = l · w · h", 0) + make_input_row(content_frame, t("length"), var_l, 1, unit_l) + make_input_row(content_frame, t("width"), var_w, 3, unit_w) + make_input_row(content_frame, t("height"), var_h, 5, unit_h) + result = make_result_label(content_frame, 7) + +def volume_cylinder_radius(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_r, var_h = tk.StringVar(), tk.StringVar() + unit_r, unit_h = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) + def calc(*a): + try: + r, h = get_m(var_r,unit_r), get_m(var_h,unit_h) + s = math.pi*r**2*h + if DEBUG: print(f"Debug volume_cylinder_radius: r={r}, h={h}, s={s}, unit_r={unit_r.get()}, unit_h={unit_h.get()}") + if round_en: s = round(s, round_num) + result.config(text=f"{t('result_vol')} = {s} m³") + except: result.config(text="") + var_r.trace_add("write", calc); var_h.trace_add("write", calc) + unit_r.trace_add("write", calc); unit_h.trace_add("write", calc) + make_title_label(content_frame, t("vol_cyl"), "V = π · r² · h", 0) + make_input_row(content_frame, t("radius"), var_r, 1, unit_r) + make_input_row(content_frame, t("height"), var_h, 3, unit_h) + result = make_result_label(content_frame, 5) + +def volume_cylinder_diameter(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_d, var_h = tk.StringVar(), tk.StringVar() + unit_d, unit_h = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) + def calc(*a): + try: + r, h = get_m(var_d,unit_d)/2, get_m(var_h,unit_h) + s = math.pi*r**2*h + if DEBUG: print(f"Debug volume_cylinder_diameter: d={get_m(var_d,unit_d)}, r={r}, h={h}, s={s}, unit_d={unit_d.get()}, unit_h={unit_h.get()}") + if round_en: s = round(s, round_num) + result.config(text=f"{t('result_vol')} = {s} m³") + except: result.config(text="") + var_d.trace_add("write", calc); var_h.trace_add("write", calc) + unit_d.trace_add("write", calc); unit_h.trace_add("write", calc) + make_title_label(content_frame, t("vol_cyl"), "V = π · (d/2)² · h", 0) + make_input_row(content_frame, t("diameter"), var_d, 1, unit_d) + make_input_row(content_frame, t("height"), var_h, 3, unit_h) + result = make_result_label(content_frame, 5) + +def volume_cone_radius(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_r, var_h = tk.StringVar(), tk.StringVar() + unit_r, unit_h = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) + def calc(*a): + try: + r, h = get_m(var_r,unit_r), get_m(var_h,unit_h) + s = (1/3)*math.pi*r**2*h + if DEBUG: print(f"Debug volume_cone_radius: r={r}, h={h}, s={s}, unit_r={unit_r.get()}, unit_h={unit_h.get()}") + if round_en: s = round(s, round_num) + result.config(text=f"{t('result_vol')} = {s} m³") + except: result.config(text="") + var_r.trace_add("write", calc); var_h.trace_add("write", calc) + unit_r.trace_add("write", calc); unit_h.trace_add("write", calc) + make_title_label(content_frame, t("vol_cone"), "V = π·r²·h / 3", 0) + make_input_row(content_frame, t("radius"), var_r, 1, unit_r) + make_input_row(content_frame, t("height"), var_h, 3, unit_h) + result = make_result_label(content_frame, 5) + +def volume_cone_diameter(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_d, var_h = tk.StringVar(), tk.StringVar() + unit_d, unit_h = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) + def calc(*a): + try: + r, h = get_m(var_d,unit_d)/2, get_m(var_h,unit_h) + s = (1/3)*math.pi*r**2*h + if DEBUG: print(f"Debug volume_cone_diameter: d={get_m(var_d,unit_d)}, r={r}, h={h}, s={s}, unit_d={unit_d.get()}, unit_h={unit_h.get()}") + if round_en: s = round(s, round_num) + result.config(text=f"{t('result_vol')} = {s} m³") + except: result.config(text="") + var_d.trace_add("write", calc); var_h.trace_add("write", calc) + unit_d.trace_add("write", calc); unit_h.trace_add("write", calc) + make_title_label(content_frame, t("vol_cone"), "V = π·(d/2)²·h / 3", 0) + make_input_row(content_frame, t("diameter"), var_d, 1, unit_d) + make_input_row(content_frame, t("height"), var_h, 3, unit_h) + result = make_result_label(content_frame, 5) + +def volume_sphere_radius(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_r = tk.StringVar() + unit_r = tk.StringVar(value=default_unit) + def calc(*a): + try: + s = (4/3)*math.pi*get_m(var_r,unit_r)**3 + if DEBUG: print(f"Debug volume_sphere_radius: r={get_m(var_r,unit_r)}, s={s}, unit={unit_r.get()}") + if round_en: s = round(s, round_num) + result.config(text=f"{t('result_vol')} = {s} m³") + except: result.config(text="") + var_r.trace_add("write", calc); unit_r.trace_add("write", calc) + make_title_label(content_frame, t("vol_sphere"), "V = 4/3 · π · r³", 0) + make_input_row(content_frame, t("radius"), var_r, 1, unit_r) + result = make_result_label(content_frame, 3) + +def volume_sphere_diameter(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_d = tk.StringVar() + unit_d = tk.StringVar(value=default_unit) + def calc(*a): + try: + s = (4/3)*math.pi*(get_m(var_d,unit_d)/2)**3 + if DEBUG: print(f"Debug volume_sphere_diameter: d={get_m(var_d,unit_d)}, r={get_m(var_d,unit_d)/2}, s={s}, unit={unit_d.get()}") + if round_en: s = round(s, round_num) + result.config(text=f"{t('result_vol')} = {s} m³") + except: result.config(text="") + var_d.trace_add("write", calc); unit_d.trace_add("write", calc) + make_title_label(content_frame, t("vol_sphere"), "V = 4/3 · π · (d/2)³", 0) + make_input_row(content_frame, t("diameter"), var_d, 1, unit_d) + result = make_result_label(content_frame, 3) + +def volume_tetrahedron(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_a = tk.StringVar() + unit_a = tk.StringVar(value=default_unit) + def calc(*a): + try: + s = get_m(var_a,unit_a)**3 / (6*2**0.5) + if DEBUG: print(f"Debug volume_tetrahedron: a={get_m(var_a,unit_a)}, s={s}, unit={unit_a.get()}") + if round_en: s = round(s, round_num) + result.config(text=f"{t('result_vol')} = {s} m³") + except: result.config(text="") + var_a.trace_add("write", calc); unit_a.trace_add("write", calc) + make_title_label(content_frame, t("vol_tetra"), "V = a³ / (6√2)", 0) + make_input_row(content_frame, f"{t('side')} a:", var_a, 1, unit_a) + result = make_result_label(content_frame, 3) + +def volume_trapezoidal_prism(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_b, var_B, var_h, var_i = tk.StringVar(), tk.StringVar(), tk.StringVar(), tk.StringVar() + unit_b, unit_B, unit_h, unit_i = tk.StringVar(value=default_unit), tk.StringVar(value=default_unit), tk.StringVar(value=default_unit), tk.StringVar(value=default_unit) + def calc(*a): + try: + b=get_m(var_b,unit_b); B=get_m(var_B,unit_B) + h=get_m(var_h,unit_h); i=get_m(var_i,unit_i) + s = ((b+B)/2)*h*i + if DEBUG: print(f"Debug volume_trapezoidal_prism: b={b}, B={B}, h={h}, i={i}, s={s}, unit_b={unit_b.get()}, unit_B={unit_B.get()}, unit_h={unit_h.get()}, unit_i={unit_i.get()}") + if round_en: s = round(s, round_num) + result.config(text=f"{t('result_vol')} = {s} m³") + except: result.config(text="") + for v in (var_b, var_B, var_h, var_i): v.trace_add("write", calc) + for u in (unit_b, unit_B, unit_h, unit_i): u.trace_add("write", calc) + make_title_label(content_frame, t("vol_trap"), "V = (b+B)/2 · h · i", 0) + make_input_row(content_frame, f"{t('side')} b:", var_b, 1, unit_b) + make_input_row(content_frame, f"{t('side')} B:", var_B, 3, unit_B) + make_input_row(content_frame, t("height"), var_h, 5, unit_h) + make_input_row(content_frame, t("depth"), var_i, 7, unit_i) + result = make_result_label(content_frame, 9) + +def voltage_i_r(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_i, var_r = tk.StringVar(), tk.StringVar() + unit_i, unit_r = tk.StringVar(value="A"), tk.StringVar(value="Ω") + + def calc(*a): + try: + i = get_electricity_value(var_i, unit_i) + r = get_electricity_value(var_r, unit_r) + if r == 0: + result.config(text="") + return + u = i * r + if DEBUG: print(f"Debug voltage_i_r: i={i} A, r={r} Ω, u={u} V") + if round_en: u = round(u, round_num) + result.config(text=f"{t('u')} = {u} V") + except: result.config(text="") + for v in (var_i, var_r, unit_i, unit_r): v.trace_add("write", calc) + make_title_label(content_frame, t("voltage"), "U = I · R", 0) + make_input_row(content_frame, t("i"), var_i, 1, unit_i, CURRENT_UNITS) + make_input_row(content_frame, t("r"), var_r, 3, unit_r, RESISTANCE_UNITS) + result = make_result_label(content_frame, 5) + +def voltage_p_i(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_i, var_p = tk.StringVar(), tk.StringVar() + unit_i, unit_p = tk.StringVar(value="A"), tk.StringVar(value="W") + + def calc(*a): + try: + i = get_electricity_value(var_i, unit_i) + p = get_electricity_value(var_p, unit_p) + if i == 0: + result.config(text="") + return + u = p / i + if DEBUG: print(f"Debug voltage_p_i: p={p} W, i={i} A, u={u} V") + if round_en: u = round(u, round_num) + result.config(text=f"{t('u')} = {u} V") + except: result.config(text="") + for v in (var_i, var_p, unit_i, unit_p): v.trace_add("write", calc) + make_title_label(content_frame, t("voltage"), "U = P / I", 0) + make_input_row(content_frame, t("p"), var_p, 1, unit_p, POWER_UNITS) + make_input_row(content_frame, t("i"), var_i, 3, unit_i, CURRENT_UNITS) + result = make_result_label(content_frame, 5) + +def voltage_r_p(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_r, var_p = tk.StringVar(), tk.StringVar() + unit_r, unit_p = tk.StringVar(value="Ω"), tk.StringVar(value="W") + + def calc(*a): + try: + r = get_electricity_value(var_r, unit_r) + p = get_electricity_value(var_p, unit_p) + if p == 0: + result.config(text="") + return + u = math.sqrt(p * r) + if DEBUG: print(f"Debug voltage_r_p: p={p} W, r={r} Ω, u={u} V") + if round_en: u = round(u, round_num) + result.config(text=f"{t('u')} = {u} V") + except: result.config(text="") + for v in (var_r, var_p, unit_r, unit_p): v.trace_add("write", calc) + make_title_label(content_frame, t("voltage"), "U = √(P · R)", 0) + make_input_row(content_frame, t("p"), var_p, 1, unit_p, POWER_UNITS) + make_input_row(content_frame, t("r"), var_r, 3, unit_r, RESISTANCE_UNITS) + result = make_result_label(content_frame, 5) + +def current_u_r(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_u, var_r = tk.StringVar(), tk.StringVar() + unit_u, unit_r = tk.StringVar(value="V"), tk.StringVar(value="Ω") + + def calc(*a): + try: + u = get_electricity_value(var_u, unit_u) + r = get_electricity_value(var_r, unit_r) + if r == 0: + result.config(text="") + return + i = u / r + if DEBUG: print(f"Debug current_u_r: u={u} V, r={r} Ω, i={i} A") + if round_en: i = round(i, round_num) + result.config(text=f"{t('i')} = {i} A") + except: result.config(text="") + for v in (var_u, var_r, unit_u, unit_r): v.trace_add("write", calc) + make_title_label(content_frame, t("current"), "I = U / R", 0) + make_input_row(content_frame, t("u"), var_u, 1, unit_u, VOLTAGE_UNITS) + make_input_row(content_frame, t("r"), var_r, 3, unit_r, RESISTANCE_UNITS) + result = make_result_label(content_frame, 5) + +def current_p_u(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_u, var_p = tk.StringVar(), tk.StringVar() + unit_u, unit_p = tk.StringVar(value="V"), tk.StringVar(value="W") + + def calc(*a): + try: + u = get_electricity_value(var_u, unit_u) + p = get_electricity_value(var_p, unit_p) + if u == 0: + result.config(text="") + return + i = p / u + if DEBUG: print(f"Debug current_p_u: p={p} W, u={u} V, i={i} A") + if round_en: i = round(i, round_num) + result.config(text=f"{t('i')} = {i} A") + except: result.config(text="") + for v in (var_u, var_p, unit_u, unit_p): v.trace_add("write", calc) + make_title_label(content_frame, t("current"), "I = P / U", 0) + make_input_row(content_frame, t("p"), var_p, 1, unit_p, POWER_UNITS) + make_input_row(content_frame, t("u"), var_u, 3, unit_u, VOLTAGE_UNITS) + result = make_result_label(content_frame, 5) + +def current_p_r(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_p, var_r = tk.StringVar(), tk.StringVar() + unit_p, unit_r = tk.StringVar(value="W"), tk.StringVar(value="Ω") + + def calc(*a): + try: + p = get_electricity_value(var_p, unit_p) + r = get_electricity_value(var_r, unit_r) + if r == 0: + result.config(text="") + return + i = math.sqrt(p / r) + if DEBUG: print(f"Debug current_p_r: p={p} W, r={r} Ω, i={i} A") + if round_en: i = round(i, round_num) + result.config(text=f"{t('i')} = {i} A") + except: result.config(text="") + for v in (var_p, var_r, unit_p, unit_r): v.trace_add("write", calc) + make_title_label(content_frame, t("current"), "I = √(P / R)", 0) + make_input_row(content_frame, t("p"), var_p, 1, unit_p, POWER_UNITS) + make_input_row(content_frame, t("r"), var_r, 3, unit_r, RESISTANCE_UNITS) + result = make_result_label(content_frame, 5) + + +def resistance_u_i(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_u, var_i = tk.StringVar(), tk.StringVar() + unit_u, unit_i = tk.StringVar(value="V"), tk.StringVar(value="A") + + def calc(*a): + try: + u = get_electricity_value(var_u, unit_u) + i = get_electricity_value(var_i, unit_i) + if i == 0: + result.config(text="") + return + r = u / i + if DEBUG: print(f"Debug resistance_u_i: u={u} V, i={i} A, r={r} Ω") + if round_en: r = round(r, round_num) + result.config(text=f"{t('r')} = {r} Ω") + except: result.config(text="") + for v in (var_u, var_i, unit_u, unit_i): v.trace_add("write", calc) + make_title_label(content_frame, t("resistance"), "R = U / I", 0) + make_input_row(content_frame, t("u"), var_u, 1, unit_u, VOLTAGE_UNITS) + make_input_row(content_frame, t("i"), var_i, 3, unit_i, CURRENT_UNITS) + result = make_result_label(content_frame, 5) + +def resistance_u_p(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_u, var_p = tk.StringVar(), tk.StringVar() + unit_u, unit_p = tk.StringVar(value="V"), tk.StringVar(value="W") + + def calc(*a): + try: + u = get_electricity_value(var_u, unit_u) + p = get_electricity_value(var_p, unit_p) + if u == 0: + result.config(text="") + return + r = u**2 / p + if DEBUG: print(f"Debug resistance_u_p: u={u} V, p={p} W, r={r} Ω") + if round_en: r = round(r, round_num) + result.config(text=f"{t('r')} = {r} Ω") + except: result.config(text="") + for v in (var_u, var_p, unit_u, unit_p): v.trace_add("write", calc) + make_title_label(content_frame, t("resistance"), "R = U² / P", 0) + make_input_row(content_frame, t("u"), var_u, 1, unit_u, VOLTAGE_UNITS) + make_input_row(content_frame, t("p"), var_p, 3, unit_p, POWER_UNITS) + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_p, var_i = tk.StringVar(), tk.StringVar() + +def resistance_p_i(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_p, var_i = tk.StringVar(), tk.StringVar() + unit_p, unit_i = tk.StringVar(value="W"), tk.StringVar(value="A") + + def calc(*a): + try: + p = get_electricity_value(var_p, unit_p) + i = get_electricity_value(var_i, unit_i) + if i == 0: + result.config(text="") + return + r = p / i**2 + if DEBUG: print(f"Debug resistance_p_i: p={p} W, i={i} A, r={r} Ω") + if round_en: r = round(r, round_num) + result.config(text=f"{t('r')} = {r} Ω") + except: result.config(text="") + for v in (var_p, var_i, unit_p, unit_i): v.trace_add("write", calc) + make_title_label(content_frame, t("resistance"), "R = P / I²", 0) + make_input_row(content_frame, t("p"), var_p, 1, unit_p, POWER_UNITS) + make_input_row(content_frame, t("i"), var_i, 3, unit_i, CURRENT_UNITS) + result = make_result_label(content_frame, 5) + +def resistance_color_bands(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + colors_digit = ["Black", "Brown", "Red", "Orange", "Yellow", "Green", "Blue", "Violet", "Grey", "White"] + colors_multiplier = ["Black", "Brown", "Red", "Orange", "Yellow", "Green", "Blue", "Violet", "Grey", "White", "Gold", "Silver"] + colors_tolerance = ["Brown", "Red", "Green", "Blue", "Violet", "Grey", "Gold", "Silver", "None"] + + b1 = tk.StringVar(value="Brown") + b2 = tk.StringVar(value="Black") + b3 = tk.StringVar(value="Black") + b4 = tk.StringVar(value="Brown") + b5 = tk.StringVar(value="Gold") + ring_mode = tk.IntVar(value=4) + + def format_value(r): + if r >= 1_000_000: + return f"{round(r/1_000_000, round_num)} MΩ" + if r >= 1_000: + return f"{round(r/1_000, round_num)} kΩ" + if r >= 1: + return f"{round(r, round_num)} Ω" + if r >= 0.001: + return f"{round(r*1000, round_num)} mΩ" + return f"{round(r*1_000_000, round_num)} μΩ" + + def update_bands(): + positions = bands_5 if ring_mode.get() == 5 else bands_4 + vars_active = [b1, b2, b3, b4, b5] if ring_mode.get() == 5 else [b1, b2, b3, b5] + for idx, item in enumerate(band_items): + if idx < len(positions): + x1, y1, x2, y2 = positions[idx] + canvas.coords(item, x1, y1, x2, y2) + color_key = vars_active[idx].get() + canvas.itemconfig(item, fill=COLOR_HEX.get(color_key, "#000000"), state="normal") + else: + canvas.itemconfig(item, state="hidden") + + def calc(*a): + try: + if ring_mode.get() == 4: + d1 = COLOR_DIGITS[b1.get()] + d2 = COLOR_DIGITS[b2.get()] + mul = COLOR_MULTIPLIER[b3.get()] + tol = COLOR_TOLERANCE[b5.get()] + r = (d1*10 + d2) * mul + else: + d1 = COLOR_DIGITS[b1.get()] + d2 = COLOR_DIGITS[b2.get()] + d3 = COLOR_DIGITS[b3.get()] + mul = COLOR_MULTIPLIER[b4.get()] + tol = COLOR_TOLERANCE[b5.get()] + r = (d1*100 + d2*10 + d3) * mul + update_bands() + result.config(text=f"R = {format_value(r)} {tol} ({r} Ω)") + except Exception: + result.config(text="") + + for v in (b1, b2, b3, b4, b5): v.trace_add("write", calc) + + def rebuild_dropdowns(): + for w in dropdown_widgets: + w.destroy() + dropdown_widgets.clear() + if ring_mode.get() == 4: + rows = [ + ("1. Band (Ziffer 1)", b1, colors_digit), + ("2. Band (Ziffer 2)", b2, colors_digit), + ("3. Band (Multiplikator)", b3, colors_multiplier), + ("4. Band (Toleranz)", b5, colors_tolerance), + ] + else: + rows = [ + ("1. Band (Ziffer 1)", b1, colors_digit), + ("2. Band (Ziffer 2)", b2, colors_digit), + ("3. Band (Ziffer 3)", b3, colors_digit), + ("4. Band (Multiplikator)", b4, colors_multiplier), + ("5. Band (Toleranz)", b5, colors_tolerance), + ] + for i, (lbl, var, opts) in enumerate(rows): + l, o = make_dropdown(dropdown_frame, lbl, var, i, opts) + dropdown_widgets.extend([l, o]) + + def on_mode_change(): + rebuild_dropdowns() + update_bands() + calc() + + make_title_label(content_frame, "Widerstand Farbcode", "", 0) + + mode_frame = tk.Frame(content_frame, bg=bg) + mode_frame.grid(row=1, column=0, sticky="w", padx=16, pady=(4, 0)) + tk.Label(mode_frame, text="Ringe:", bg=bg, fg=fg, font=("Arial", 11)).pack(side="left", padx=(0, 8)) + for val, label in [(4, "4-Ring"), (5, "5-Ring")]: + tk.Radiobutton( + mode_frame, text=label, variable=ring_mode, value=val, + bg=bg, fg=fg, + selectcolor="#2c2c2e" if bg_dark else "#dddddd", + activebackground=bg, activeforeground=fg, + font=("Arial", 11), + command=on_mode_change + ).pack(side="left", padx=4) + + canvas_width = 180 + body_left = 40 + body_right = 140 + body_top, body_bottom = 30, 50 + wire_y = 40 + + canvas = tk.Canvas(content_frame, height=70, width=canvas_width, + bg=bg, highlightthickness=0) + canvas.grid(row=2, column=0, sticky="w", padx=16, pady=(10, 4)) + + canvas.create_rectangle(body_left, body_top, body_right, body_bottom, + fill="#d2b48c", outline="#8b5a2b", width=2) + canvas.create_line(body_left, wire_y, 25, wire_y, fill="#8b5a2b", width=3) + canvas.create_line(body_right, wire_y, canvas_width-20, wire_y, fill="#8b5a2b", width=3) + + bands_4 = [ + (body_left+10, body_top, body_left+18, body_bottom), + (body_left+28, body_top, body_left+36, body_bottom), + (body_left+50, body_top, body_left+58, body_bottom), + (body_left+70, body_top, body_left+78, body_bottom), + ] + bands_5 = [ + (body_left+8, body_top, body_left+15, body_bottom), + (body_left+23, body_top, body_left+30, body_bottom), + (body_left+38, body_top, body_left+45, body_bottom), + (body_left+56, body_top, body_left+63, body_bottom), + (body_left+73, body_top, body_left+80, body_bottom), + ] + + band_items = [] + for coords in bands_4: + item = canvas.create_rectangle(*coords, fill="#000000", outline="black") + band_items.append(item) + item5 = canvas.create_rectangle(*bands_5[4], fill="#000000", outline="black", state="hidden") + band_items.append(item5) + + def make_dropdown(parent, label_text, var, row, options): + lbl = tk.Label(parent, text=label_text, bg=bg, fg=fg, + font=("Arial", 11), anchor="w") + lbl.grid(row=row*2, column=0, sticky="w", pady=(8, 0)) + om = tk.OptionMenu(parent, var, *options) + om.config(bg="#2c2c2e" if bg_dark else "#f0f0f0", fg=fg, + activebackground="#3a3a3c", activeforeground=fg, + relief="flat", highlightthickness=0, + font=("Arial", 11), width=12) + om["menu"].config(bg="#2c2c2e" if bg_dark else "#f0f0f0", fg=fg) + om.grid(row=row*2+1, column=0, sticky="ew", pady=(2, 2)) + return lbl, om + + dropdown_frame = tk.Frame(content_frame, bg=bg) + dropdown_frame.grid(row=3, column=0, sticky="ew", padx=16, pady=(8, 0)) + dropdown_frame.columnconfigure(0, weight=1) + dropdown_widgets = [] + + result = make_result_label(content_frame, 4) + + rebuild_dropdowns() + update_bands() + calc() + +def power_u_i(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_u, var_i = tk.StringVar(), tk.StringVar() + unit_u, unit_i = tk.StringVar(value="V"), tk.StringVar(value="A") + + def calc(*a): + try: + u = get_electricity_value(var_u, unit_u) + i = get_electricity_value(var_i, unit_i) + p = u * i + if DEBUG: print(f"Debug power_u_i: u={u} V, i={i} A, p={p} W") + if round_en: p = round(p, round_num) + result.config(text=f"{t('p')} = {p} W") + except: result.config(text="") + for v in (var_u, var_i, unit_u, unit_i): v.trace_add("write", calc) + make_title_label(content_frame, t("power"), "P = U * I", 0) + make_input_row(content_frame, t("u"), var_u, 1, unit_u, VOLTAGE_UNITS) + make_input_row(content_frame, t("i"), var_i, 3, unit_i, CURRENT_UNITS) + result = make_result_label(content_frame, 5) + +def power_i_r(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_i, var_r = tk.StringVar(), tk.StringVar() + + def calc(*a): + try: + i = get_electricity_value(var_i, unit_i) + r = get_electricity_value(var_r, unit_r) + if r == 0: + result.config(text="") + return + p = i**2 * r + if DEBUG: print(f"Debug power_i_r: i={i} A, r={r} Ω, p={p} W") + if round_en: p = round(p, round_num) + result.config(text=f"{t('p')} = {p} W") + except: result.config(text="") + for v in (var_i, var_r, unit_i, unit_r): v.trace_add("write", calc) + make_title_label(content_frame, t("power"), "P = I² * R", 0) + make_input_row(content_frame, t("i"), var_i, 1, unit_i, CURRENT_UNITS) + make_input_row(content_frame, t("r"), var_r, 3, unit_r, RESISTANCE_UNITS) + result = make_result_label(content_frame, 5) + +def power_u_r(): + clear_frame(); content_frame.columnconfigure(0, weight=1) + var_u, var_r = tk.StringVar(), tk.StringVar() + + def calc(*a): + try: + u = get_electricity_value(var_u, unit_u) + r = get_electricity_value(var_r, unit_r) + if r == 0: + result.config(text="") + return + p = u**2 / r + if DEBUG: print(f"Debug power_u_r: u={u} V, r={r} Ω, p={p} W") + if round_en: p = round(p, round_num) + result.config(text=f"{t('p')} = {p} W") + except: result.config(text="") + for v in (var_u, var_r, unit_u, unit_r): v.trace_add("write", calc) + make_title_label(content_frame, t("power"), "P = U² / R", 0) + make_input_row(content_frame, t("u"), var_u, 1, unit_u, VOLTAGE_UNITS) + make_input_row(content_frame, t("r"), var_r, 3, unit_r, RESISTANCE_UNITS) + result = make_result_label(content_frame, 5) + +def calculator(): + clear_frame() + display_var = tk.StringVar(value="0") + expr_var = tk.StringVar(value="") + + def button_click(z): + c = display_var.get() + display_var.set(str(z) if c in ("0", "Fehler", "Error") else c + str(z)) + + def clear(): + display_var.set("0"); expr_var.set("") + + def backspace(): + c = display_var.get() + display_var.set(c[:-1] if len(c) > 1 and c not in ("Fehler","Error") else "0") + + def toggle_sign(): + c = display_var.get() + try: + v = float(c) + display_var.set(("-"+c) if v > 0 else (c[1:] if v < 0 else c)) + except: pass + + def percent(): + try: + v = float(display_var.get()) / 100 + display_var.set(str(round(v, round_num) if round_en else v)) + except: pass + + def ausrechnen(event=None): + try: + ausdruck = display_var.get() + expr_var.set(ausdruck + " =") + ergebnis = eval(ausdruck) + if round_en: ergebnis = round(ergebnis, round_num) + display_var.set(str(ergebnis)) + db_add(ausdruck, ergebnis) + update_history() + except: + expr_var.set(""); display_var.set("Fehler" if language=="DE" else "Error") + + def tastatur_input(event): + if event.char in "0123456789+-*/.": button_click(event.char) + elif event.keysym == "Return": ausrechnen() + elif event.keysym in ("Escape","c","C","Delete","KP_Delete") or event.char in ("\x7f",): + clear() + elif event.keysym == "BackSpace": backspace() + + content_frame.bind_all("", tastatur_input) + + wrapper = tk.Frame(content_frame, bg="#1c1c1e") + wrapper.grid(row=0, column=0, sticky="nsew") + content_frame.rowconfigure(0, weight=1) + content_frame.columnconfigure(0, weight=1) + wrapper.columnconfigure(0, weight=1) + wrapper.rowconfigure(1, weight=1) + + display_frame = tk.Frame(wrapper, bg="#2c2c2e") + display_frame.grid(row=0, column=0, sticky="ew", padx=10, pady=(10, 6)) + tk.Label(display_frame, textvariable=expr_var, + font=("Arial", 12), bg="#2c2c2e", fg="#888888", + anchor="e", padx=12, pady=6).pack(fill="x", pady=(6, 0)) + tk.Label(display_frame, textvariable=display_var, + font=("Arial", 34, "bold"), bg="#2c2c2e", fg="white", + anchor="e", padx=12, pady=0).pack(fill="x", pady=(0, 10)) + + STYLE = { + "num": {"bg": "#2c2c2e", "fg": "white", "abg": "#3a3a3c"}, + "op": {"bg": "#3a3a3c", "fg": "#bf9fff", "abg": "#48484a"}, + "fn": {"bg": "#3a3a3c", "fg": "#aaaaaa", "abg": "#48484a"}, + "eq": {"bg": "#7c5cbf", "fg": "#ece8ff", "abg": "#5e42a0"}, + } + grid = tk.Frame(wrapper, bg="#1c1c1e") + grid.grid(row=1, column=0, sticky="nsew", padx=10, pady=(0, 6)) + for c in range(4): grid.columnconfigure(c, weight=1) + for r in range(5): grid.rowconfigure(r, weight=1) + + def make_btn(text, kind, cmd, row, col, colspan=1): + s = STYLE[kind] + tk.Button(grid, text=text, command=cmd, + bg=s["bg"], fg=s["fg"], + activebackground=s["abg"], activeforeground=s["fg"], + font=("Arial", 18), relief="flat", bd=0, + padx=0, pady=14, cursor="hand2").grid( + row=row, column=col, columnspan=colspan, + padx=4, pady=4, sticky="nsew") + + make_btn("AC", "fn", clear, 0, 0) + make_btn("+/-", "fn", toggle_sign, 0, 1) + make_btn("%", "fn", percent, 0, 2) + make_btn("÷", "op", lambda: button_click("/"), 0, 3) + make_btn("7", "num", lambda: button_click("7"), 1, 0) + make_btn("8", "num", lambda: button_click("8"), 1, 1) + make_btn("9", "num", lambda: button_click("9"), 1, 2) + make_btn("×", "op", lambda: button_click("*"), 1, 3) + make_btn("4", "num", lambda: button_click("4"), 2, 0) + make_btn("5", "num", lambda: button_click("5"), 2, 1) + make_btn("6", "num", lambda: button_click("6"), 2, 2) + make_btn("−", "op", lambda: button_click("-"), 2, 3) + make_btn("1", "num", lambda: button_click("1"), 3, 0) + make_btn("2", "num", lambda: button_click("2"), 3, 1) + make_btn("3", "num", lambda: button_click("3"), 3, 2) + make_btn("+", "op", lambda: button_click("+"), 3, 3) + make_btn("⌫", "fn", backspace, 4, 0) + make_btn("0", "num", lambda: button_click("0"), 4, 1) + make_btn(".", "num", lambda: button_click("."), 4, 2) + make_btn("=", "eq", ausrechnen, 4, 3) + + hist_frame = tk.Frame(wrapper, bg="#1c1c1e") + hist_frame.grid(row=2, column=0, sticky="ew", padx=10, pady=(0, 8)) + tk.Label(hist_frame, text=t("history"), bg="#1c1c1e", fg="#555555", + font=("Arial", 10), anchor="w").pack(fill="x", padx=6) + history_label = tk.Label(hist_frame, text="", bg="#1c1c1e", + fg="#666666", font=("Arial", 10), + anchor="e", justify="right") + history_label.pack(fill="x", padx=6) + + def update_history(): + rows = db_get_last(3) + lines = [f"{r[0]} = {r[1]}" for r in rows] + history_label.config(text="\n".join(lines)) + + update_history() + +root = tk.Tk() +root.title("Calculator") +root.geometry("500x640") +root.resizable(False, False) +root.iconbitmap(default=resource_path("bilder/icon.ico")) + +menubar = tk.Menu(root) +menu = tk.Menu(menubar, tearoff=0) +shape = tk.Menu(menu, tearoff=0) +shape_volume = tk.Menu(shape, tearoff=0) +shape_area = tk.Menu(shape, tearoff=0) +areacircle = tk.Menu(shape_area, tearoff=0) +areacylinder = tk.Menu(shape_area, tearoff=0) +areasphere = tk.Menu(shape_area, tearoff=0) +areacone = tk.Menu(shape_area, tearoff=0) +volumeclinder = tk.Menu(shape_volume, tearoff=0) +volumecone = tk.Menu(shape_volume, tearoff=0) +volumesphere = tk.Menu(shape_volume, tearoff=0) +electricity_menu = tk.Menu(menu, tearoff=0) +voltage = tk.Menu(electricity_menu, tearoff=0) +amper = tk.Menu(electricity_menu, tearoff=0) +resistance = tk.Menu(electricity_menu, tearoff=0) +power = tk.Menu(electricity_menu, tearoff=0) + +root.config(menu=menubar) + +content_frame = tk.Frame(root) +content_frame.grid(row=0, column=0, padx=10, pady=10, sticky="nsew") +root.columnconfigure(0, weight=1) +root.rowconfigure(0, weight=1) +content_frame.columnconfigure(0, weight=1) +root.config(bg=bg) +content_frame.config(bg=bg) + +creator = tk.Label(root, bg=bg, fg=fg) + +rebuild_menu() +calculator() + +threading.Thread(target=check_for_updates, daemon=True).start() + + +root.mainloop()