10 Commits
1.0.0 ... 1.0.2

Author SHA1 Message Date
3280827aac Update README.md 2026-04-06 18:33:13 +00:00
e4a1681ede Update README.md 2026-04-06 18:28:54 +00:00
b4ff04112a Update README.md 2026-04-06 18:24:35 +00:00
0b7eff5f41 Upload files to "/" 2026-04-06 18:22:17 +00:00
e32ae07bd0 Update LICENSE 2026-03-28 18:42:03 +00:00
a6bece502e Update LICENSE 2026-03-28 18:40:27 +00:00
6eb653e595 Upload files to "/" 2026-03-28 18:40:12 +00:00
354929ef21 Delete LICENSE/LICENSE (1) 2026-03-28 18:40:03 +00:00
095d130ccc Upload files to "LICENSE" 2026-03-28 18:39:44 +00:00
55ac8a128f Delete LICENSE 2026-03-28 18:39:24 +00:00
3 changed files with 328 additions and 55 deletions

64
LICENSE
View File

@@ -1,29 +1,47 @@
MIT License GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (c) 2026 Survivalful (https://Survivalful.de/) Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Permission is hereby granted, free of charge, to any person obtaining a copy Preamble
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The GNU General Public License is a free, copyleft license for
copies or substantial portions of the Software. software and other kinds of works.
Any use of this Software, in whole or in part, must visibly credit the original For the developers' and authors' protection, the GPL clearly explains
author: Survivalful (https://Survivalful.de/) that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
This credit must appear in at least one of the following: Some devices are designed to deny users access to install or run
- The application's user interface (e.g. About screen or footer) modified versions of the software inside them, although the manufacturer
- The project's README or documentation can do so. This is fundamentally incompatible with the aim of
- The source code as a comment protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. Finally, any free program is threatened constantly by
software patents. We wish to ensure that a free program has all the
rights that its distributors can provide, so we will not allow patents to
restrict the program.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR The precise terms and conditions for copying, distribution and
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, modification follow.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER TERMS AND CONDITIONS
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 0. Definitions.
SOFTWARE.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to

View File

@@ -1,6 +1,9 @@
---
# 🧮 Survivalcalc # 🧮 Survivalcalc
A modern desktop calculator with advanced features for area and volume calculations, built with Python and Tkinter. A modern desktop calculator with advanced features for area, volume, and electricity calculations, built with Python and Tkinter.
--- ---
@@ -9,13 +12,15 @@ A modern desktop calculator with advanced features for area and volume calculati
* 🔢 **Standard Calculator** Basic arithmetic with real-time computation * 🔢 **Standard Calculator** Basic arithmetic with real-time computation
* 📐 **Area Calculations** Square, rectangle, circle, triangle, trapezoid, cylinder, sphere, cone * 📐 **Area Calculations** Square, rectangle, circle, triangle, trapezoid, cylinder, sphere, cone
* 📦 **Volume Calculations** Cube, rectangular prism, cylinder, cone, sphere, tetrahedron, trapezoidal prism * 📦 **Volume Calculations** Cube, rectangular prism, cylinder, cone, sphere, tetrahedron, trapezoidal prism
***Electricity Calculations** Voltage, current, resistance, and power with various formulas, plus a color band resistance calculator.
* 🌙 **Dark Mode** Toggle between light and dark themes * 🌙 **Dark Mode** Toggle between light and dark themes
* 🌍 **Multi-Language Support** German (DE) and English (EN) * 🌍 **Multi-Language Support** German (DE) and English (EN)
* 📏 **Unit System** Support for mm, cm, m, km with automatic conversion * 📏 **Unit System** Support for pm, nm, μm, mm, cm, dm, m, km, Mm, Gm with automatic conversion
* 🔄 **Adjustable Rounding** Configure decimal places (020) * 🔄 **Adjustable Rounding** Configure decimal places (020)
* 🕓 **Calculation History** Track last 3 calculations with SQLite storage * 🕓 **Calculation History** Track last 3 calculations with SQLite storage
* ⚙️ **Persistent Settings** All preferences saved automatically * ⚙️ **Persistent Settings** All preferences saved automatically
* ⌨️ **Keyboard Support** Full keyboard shortcuts for calculator operations * ⌨️ **Keyboard Support** Full keyboard shortcuts for calculator operations
* 🔄 **Automatic Updates** Notifies you when a new version is available.
--- ---
@@ -48,6 +53,14 @@ A modern desktop calculator with advanced features for area and volume calculati
5. Select your units 5. Select your units
6. Results update automatically 6. Results update automatically
### Electricity Calculations
1. Open **Shapes** menu
2. Select **Electricity**
3. Choose the quantity to calculate (e.g., Voltage, Current)
4. Select the formula you want to use (e.g., U = I · R)
5. Enter your values
6. Results update automatically
### Settings ### Settings
- Toggle dark mode - Toggle dark mode
- Enable/disable rounding - Enable/disable rounding
@@ -71,7 +84,7 @@ A modern desktop calculator with advanced features for area and volume calculati
* **OS**: Windows 7 or later * **OS**: Windows 7 or later
* **RAM**: 50 MB minimum * **RAM**: 50 MB minimum
* **Disk Space**: 10 MB * **Disk Space**: 10 MB
* **Internet**: Required for initial download only * **Internet**: Required for initial download and update checks
--- ---
@@ -95,26 +108,24 @@ A modern desktop calculator with advanced features for area and volume calculati
2. Find **Survivalcalc** 2. Find **Survivalcalc**
3. Click **Uninstall** 3. Click **Uninstall**
Or run **Survivalcalc_Uninstaller.exe** directly.
--- ---
## 📬 Support ## 📬 Support
* 🌐 **Website**: [Github](https://survivalful.de/survivalcalc/) * 🌐 **Website**: [https://Survivalful.de](https://survivalful.de)
* 📧 **Email**: [team@survivalful.de](mailto:team@survivalful.de) * 📧 **Email**: [team@survivalful.de](mailto:team@survivalful.de)
--- ---
## 📜 License ## 📜 License
MIT License © 2026 Survivalful GPL License © 2026 Survivalful
--- ---
## 📊 Version Info ## 📊 Version Info
* **Version**: 1.0.0 * **Version**: 1.0.2
* **Release**: 24.03.2026 * **Release**: 24.03.2026
* **Status**: Stable * **Status**: Stable

292
main.py
View File

@@ -14,7 +14,6 @@ import webbrowser
VERSION_URL = "https://cloud.survivalful.de/s/ydLwqwXdJEj8XwR/download" VERSION_URL = "https://cloud.survivalful.de/s/ydLwqwXdJEj8XwR/download"
def fetch_version_info(): def fetch_version_info():
"""Holt die version.json vom Server. Gibt None bei Fehler zurück."""
try: try:
with urllib.request.urlopen(VERSION_URL, timeout=5) as response: with urllib.request.urlopen(VERSION_URL, timeout=5) as response:
return json.loads(response.read().decode()) return json.loads(response.read().decode())
@@ -22,7 +21,6 @@ def fetch_version_info():
return None return None
def version_is_newer(latest, current): def version_is_newer(latest, current):
"""Vergleicht zwei Versionsstrings wie '1.2.0' > '1.0.0'."""
try: try:
l_parts = list(map(int, latest.split('.'))) l_parts = list(map(int, latest.split('.')))
c_parts = list(map(int, current.split('.'))) c_parts = list(map(int, current.split('.')))
@@ -129,7 +127,7 @@ LANG = {
"result_current": "Strom I", "result_current": "Strom I",
"result_resistance": "Wiederstand R", "result_resistance": "Wiederstand R",
"voltage": "Spannung", "voltage": "Spannung",
"ampere": "Strom", "current": "Strom",
"resistance": "Widerstand", "resistance": "Widerstand",
"power": "Leistung", "power": "Leistung",
"u": "Spannung U", "u": "Spannung U",
@@ -267,17 +265,39 @@ def t(key, **kwargs):
pass pass
return text return text
app_version = "1.0.0" 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_release = "24.3.2026"
app_status = "Stable" app_status = "Stable"
dev_e_mail = "team@survivalful.de" dev_e_mail = "team@survivalful.de"
dev_website = "https://Survivalful.de/" dev_website = "https://Survivalful.de/"
app_license = "MIT License © 2026 Survivalful" app_license = "GPL License © 2026 Survivalful"
sys_system = platform.system() sys_system = platform.system()
sys_version = platform.release() sys_version = platform.release()
sys_machine = platform.machine() sys_machine = platform.machine()
sys_python = platform.python_version() sys_python = platform.python_version()
install_date = datetime.datetime.now().strftime("%d.%m.%Y %H:%M") install_date = get_install_date()
DEFAULT_SETTINGS = { DEFAULT_SETTINGS = {
"bg_dark": True, "bg_dark": True,
@@ -350,37 +370,78 @@ load_settings()
init_db() init_db()
def check_for_updates(): def check_for_updates():
"""
Überprüft im Hintergrund auf Updates und zeigt bei Erfolg eine Nachricht an.
Diese Funktion wird in einem separaten Thread ausgeführt.
"""
try: try:
info = fetch_version_info() info = fetch_version_info()
if not info: if not info:
return return
latest_version = info.get("version") latest_version = info.get("version")
changelog = info.get("changelog", "Keine Informationen verfügbar.") changelog = info.get("changelog", "Keine Informationen verfügbar.")
download_url = info.get("download_url") download_url = info.get("installer_url")
update_info_url = info.get("update_info_url")
if latest_version and version_is_newer(latest_version, app_version): 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 messagebox.askyesno(title, message):
if update_info_url:
webbrowser.open(update_info_url)
root.after(0, show_update_dialog) 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: except Exception as e:
print(f"Update-Check fehlgeschlagen: {e}") print(f"Update-Check fehlgeschlagen: {e}")
UNIT_FACTORS = { UNIT_FACTORS = {
"pm": 1e-12, "nm": 1e-9, "μm": 1e-6, "mm": 0.001, "cm": 0.01, "dm": 0.1, "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 "m": 1.0, "km": 1000, "Mm": 1e6, "Gm": 1e9
@@ -396,6 +457,27 @@ CURRENT_UNITS = ["pA", "nA", "μA", "mA", "A", "kA", "MA", "GA"]
RESISTANCE_UNITS = ["", "", "μΩ", "", "Ω", "", "", ""] RESISTANCE_UNITS = ["", "", "μΩ", "", "Ω", "", "", ""]
POWER_UNITS = ["pW", "nW", "μW", "mW", "W", "kW", "MW", "GW"] 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): def half(first, last):
return first / last return first / last
@@ -553,6 +635,7 @@ def rebuild_menu():
resistance.add_command(label=t("r_u_p"), command=resistance_u_p) resistance.add_command(label=t("r_u_p"), command=resistance_u_p)
resistance.add_command(label=t("r_p_i"), command=resistance_p_i) resistance.add_command(label=t("r_p_i"), command=resistance_p_i)
electricity_menu.add_cascade(label=t("power"),menu=power) 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_i_r"), command=power_u_i)
power.add_command(label=t("u_r_p"), command=power_i_r) power.add_command(label=t("u_r_p"), command=power_i_r)
power.add_command(label=t("r_p_i"), command=power_u_r) power.add_command(label=t("r_p_i"), command=power_u_r)
@@ -1360,6 +1443,167 @@ def resistance_p_i():
make_input_row(content_frame, t("i"), var_i, 3, unit_i, CURRENT_UNITS) make_input_row(content_frame, t("i"), var_i, 3, unit_i, CURRENT_UNITS)
result = make_result_label(content_frame, 5) 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(): def power_u_i():
clear_frame(); content_frame.columnconfigure(0, weight=1) clear_frame(); content_frame.columnconfigure(0, weight=1)
var_u, var_i = tk.StringVar(), tk.StringVar() var_u, var_i = tk.StringVar(), tk.StringVar()