Files
SurvivalCalc/main.py
2026-04-06 20:48:30 +00:00

1838 lines
81 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 = ["", "", "μΩ", "", "Ω", "", "", ""]
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("<Configure>",
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("<MouseWheel>", 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}")
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}")
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}")
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}")
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}")
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}")
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}")
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}")
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}")
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}")
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}")
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}")
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}")
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}")
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}")
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}")
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}")
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}")
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}")
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}")
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}")
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}")
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)}"
if r >= 1_000:
return f"{round(r/1_000, round_num)}"
if r >= 1:
return f"{round(r, round_num)} Ω"
if r >= 0.001:
return f"{round(r*1000, round_num)}"
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("<Key>", 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()