Provisions-Manager 95: Import, Händler-DB, Auszahlungsregeln, Excel-Export, Win95-Oberfläche, Wine-Build
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
322d2ed1c3
25 files changed
+3366
No files matched your search
@@ -0,0 +1,582 @@
|
||||
"""Windows-95-Optik für Tkinter: Farben, Schriften, Pixel-Icons und ein paar Bausteine."""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
|
||||
FACE = "#c0c0c0"
|
||||
HILITE = "#ffffff"
|
||||
LIGHT = "#dfdfdf"
|
||||
SHADOW = "#808080"
|
||||
DARK = "#000000"
|
||||
NAVY = "#000080"
|
||||
TEAL = "#008080"
|
||||
WHITE = "#ffffff"
|
||||
INFO_BG = "#ffffe1"
|
||||
|
||||
IS_WIN = sys.platform.startswith("win")
|
||||
FONT_FAMILY = "MS Sans Serif" if IS_WIN else "DejaVu Sans"
|
||||
FONT_SIZE = 8 if IS_WIN else 9
|
||||
FONT = (FONT_FAMILY, FONT_SIZE)
|
||||
FONT_BOLD = (FONT_FAMILY, FONT_SIZE, "bold")
|
||||
FONT_BIG = (FONT_FAMILY, FONT_SIZE + 4, "bold")
|
||||
FONT_MONO = ("Courier New" if IS_WIN else "DejaVu Sans Mono", FONT_SIZE + 1)
|
||||
|
||||
# --------------------------------------------------------------------------- Pixel-Icons (16x16)
|
||||
PALETTE = {
|
||||
"k": "#000000", "w": "#ffffff", "g": "#c0c0c0", "d": "#808080", "y": "#ffff00", "Y": "#808000",
|
||||
"b": "#000080", "B": "#0000ff", "r": "#ff0000", "R": "#800000", "G": "#008000", "L": "#00ff00",
|
||||
"t": "#008080", "c": "#00ffff", "s": "#ffcc99", "o": "#ff8000",
|
||||
}
|
||||
|
||||
ICONS = {
|
||||
"neu": """
|
||||
..kkkkkkkkk.....
|
||||
..kwwwwwwwkk....
|
||||
..kwwwwwwwkwk...
|
||||
..kwwwwwwwkkkk..
|
||||
..kwwwwwwwwwwk..
|
||||
..kwkkkkkkkwwk..
|
||||
..kwwwwwwwwwwk..
|
||||
..kwkkkkkkkkwk..
|
||||
..kwwwwwwwwwwk..
|
||||
..kwkkkkkkkkwk..
|
||||
..kwwwwwwwwwwk..
|
||||
..kwkkkkkwwwwk..
|
||||
..kwwwwwwwwwwk..
|
||||
..kwwwwwwwwwwk..
|
||||
..kkkkkkkkkkkk..
|
||||
................""",
|
||||
"oeffnen": """
|
||||
................
|
||||
.........kkk....
|
||||
........k...k.k.
|
||||
.............kk.
|
||||
.kkk........kkk.
|
||||
kyYyk...........
|
||||
kYyYykkkkkkk....
|
||||
kyYyYyYyYyYk....
|
||||
kYyYykkkkkkkkkk.
|
||||
kyYykyyyyyyyyyk.
|
||||
kYykyyyyyyyyyk..
|
||||
kykyyyyyyyyyk...
|
||||
kkyyyyyyyyyk....
|
||||
kkkkkkkkkkk.....
|
||||
................
|
||||
................""",
|
||||
"import": """
|
||||
......kkkk......
|
||||
......kGGk......
|
||||
......kGGk......
|
||||
......kGGk......
|
||||
...kkkkGGkkkk...
|
||||
....kGGGGGGk....
|
||||
.....kGGGGk.....
|
||||
......kGGk......
|
||||
.......kk.......
|
||||
.kkkkkkkkkkkkkk.
|
||||
.kwwwwwwwwwwwdk.
|
||||
.kwkkwkkwkkwwdk.
|
||||
.kwwwwwwwwwwwdk.
|
||||
.kddddddddddddk.
|
||||
.kkkkkkkkkkkkkk.
|
||||
................""",
|
||||
"export": """
|
||||
kkkkkkkkkkkkkkk.
|
||||
kbbkwwwwwwwkbbk.
|
||||
kbbkwwwwwwwkbbk.
|
||||
kbbkwwwwwwwkbbk.
|
||||
kbbkwwwwwwwkbbk.
|
||||
kbbkkkkkkkkkbbk.
|
||||
kbbbbbbbbbbbbbk.
|
||||
kbbbbbbbbbbbbbk.
|
||||
kbbkkkkkkkkkkbk.
|
||||
kbbkgggkkgggkbk.
|
||||
kbbkgggkkgggkbk.
|
||||
kbbkgggkkgggkbk.
|
||||
kbbkgggggggggbk.
|
||||
.kbkkkkkkkkkkbk.
|
||||
..kkkkkkkkkkkkk.
|
||||
................""",
|
||||
"haendler": """
|
||||
................
|
||||
....kkk.........
|
||||
...kssskk.kkk...
|
||||
...ksksk.kssk...
|
||||
...kssskksksk...
|
||||
....kskkkssk....
|
||||
...kbbbkkksk....
|
||||
..kbbbbbkRRRk...
|
||||
..kbbbbbkRRRRk..
|
||||
..kbkbkbRRRRRk..
|
||||
..kbkbkbkRkRRk..
|
||||
..kbkbkbkRkRRk..
|
||||
..kbbbbbkRRRRk..
|
||||
...kbkbkkRkRk...
|
||||
...kkkkk.kkkk...
|
||||
................""",
|
||||
"prozent": """
|
||||
................
|
||||
..kkk......kk...
|
||||
.kwwwk....kk....
|
||||
.kwkwk...kk.....
|
||||
.kwwwk..kk......
|
||||
..kkk..kk.......
|
||||
......kk........
|
||||
.....kk.........
|
||||
....kk..........
|
||||
...kk...kkk.....
|
||||
..kk...kwwwk....
|
||||
.kk....kwkwk....
|
||||
kk.....kwwwk....
|
||||
........kkk.....
|
||||
................
|
||||
................""",
|
||||
"rechner": """
|
||||
.kkkkkkkkkkkkk..
|
||||
.kddddddddddddk.
|
||||
.kdkkkkkkkkkkdk.
|
||||
.kdkLLLLLLLLkdk.
|
||||
.kdkkkkkkkkkkdk.
|
||||
.kddddddddddddk.
|
||||
.kdwwdwwdwwdrrk.
|
||||
.kdkkdkkdkkdkkk.
|
||||
.kddddddddddddk.
|
||||
.kdwwdwwdwwdwwk.
|
||||
.kdkkdkkdkkdkkk.
|
||||
.kddddddddddddk.
|
||||
.kdwwdwwdwwdwwk.
|
||||
.kdkkdkkdkkdkkk.
|
||||
.kkkkkkkkkkkkkk.
|
||||
................""",
|
||||
"info": """
|
||||
.....kkkkkk.....
|
||||
...kkBBBBBBkk...
|
||||
..kBBBBBBBBBBk..
|
||||
.kBBBBBwwBBBBBk.
|
||||
.kBBBBBwwBBBBBk.
|
||||
kBBBBBBBBBBBBBBk
|
||||
kBBBBBwwwBBBBBBk
|
||||
kBBBBBBwwBBBBBBk
|
||||
kBBBBBBwwBBBBBBk
|
||||
kBBBBBBwwBBBBBBk
|
||||
.kBBBBBwwBBBBBk.
|
||||
.kBBBBwwwwBBBBk.
|
||||
..kBBBBBBBBBBk..
|
||||
...kkBBBBBBkk...
|
||||
.....kkkkkk.....
|
||||
................""",
|
||||
"warnung": """
|
||||
.......kk.......
|
||||
......kyyk......
|
||||
......kyyk......
|
||||
.....kyyyyk.....
|
||||
.....kykkyk.....
|
||||
....kyykkyyk....
|
||||
....kyykkyyk....
|
||||
...kyyykkyyyk...
|
||||
...kyyykkyyyk...
|
||||
..kyyyyyyyyyyk..
|
||||
..kyyyykkyyyyk..
|
||||
.kyyyyykkyyyyyk.
|
||||
.kyyyyyyyyyyyyk.
|
||||
kkkkkkkkkkkkkkkk
|
||||
................
|
||||
................""",
|
||||
"fehler": """
|
||||
.....kkkkkk.....
|
||||
...kkrrrrrrkk...
|
||||
..krrrrrrrrrrk..
|
||||
.krrwrrrrrrwrrk.
|
||||
.krwwwrrrrwwwrk.
|
||||
krrrwwwrrwwwrrrk
|
||||
krrrrwwwwwwrrrrk
|
||||
krrrrrwwwwrrrrrk
|
||||
krrrrrwwwwrrrrrk
|
||||
krrrrwwwwwwrrrrk
|
||||
.krrwwwrrwwwrrk.
|
||||
.krwwwrrrrwwwrk.
|
||||
..krrrrrrrrrrk..
|
||||
...kkrrrrrrkk...
|
||||
.....kkkkkk.....
|
||||
................""",
|
||||
"frage": """
|
||||
.....kkkkkk.....
|
||||
...kkwwwwwwkk...
|
||||
..kwwwwwwwwwwk..
|
||||
.kwwwwBBBBwwwwk.
|
||||
.kwwwBBwwBBwwwk.
|
||||
kwwwwwwwwBBwwwwk
|
||||
kwwwwwwwBBwwwwwk
|
||||
kwwwwwwBBwwwwwwk
|
||||
kwwwwwwBBwwwwwwk
|
||||
kwwwwwwwwwwwwwwk
|
||||
.kwwwwwBBwwwwwk.
|
||||
.kwwwwwBBwwwwwk.
|
||||
..kwwwwwwwwwwk..
|
||||
...kkwwwwwwkk...
|
||||
.....kkkkkkk....
|
||||
................""",
|
||||
"app": """
|
||||
................
|
||||
.....kkkkkkk....
|
||||
....kdddddddk...
|
||||
....kdkkkkkdk...
|
||||
....kdkLLLkdk...
|
||||
....kdkLLLkdk...
|
||||
....kdkkkkkdk...
|
||||
....kdwdwdwdk...
|
||||
....kdddddddk...
|
||||
....kdwdwdwdk...
|
||||
....kdddddddk...
|
||||
..ttkdwdwdwdktt.
|
||||
.tcccckkkkkkccct
|
||||
tcccccyyyyyyccct
|
||||
.ttttttttttttttt
|
||||
................""",
|
||||
}
|
||||
|
||||
|
||||
def _icon_rows(name: str) -> list[str]:
|
||||
rows = [r.strip() for r in ICONS[name].strip("\n").splitlines() if r.strip()]
|
||||
return [r.ljust(16, ".")[:16] for r in rows[:16]] + ["." * 16] * (16 - len(rows))
|
||||
|
||||
|
||||
def make_icon(master, name: str, scale: int = 1) -> tk.PhotoImage:
|
||||
img = tk.PhotoImage(master=master, width=16 * scale, height=16 * scale)
|
||||
for y, row in enumerate(_icon_rows(name)):
|
||||
for x, ch in enumerate(row):
|
||||
if ch == ".":
|
||||
continue
|
||||
color = PALETTE[ch]
|
||||
img.put(color, to=(x * scale, y * scale, (x + 1) * scale, (y + 1) * scale))
|
||||
return img
|
||||
|
||||
|
||||
class Icons:
|
||||
"""Lazy-Cache, damit PhotoImages nicht vom Garbage Collector entsorgt werden."""
|
||||
|
||||
def __init__(self, master):
|
||||
self.master = master
|
||||
self._cache: dict[tuple[str, int], tk.PhotoImage] = {}
|
||||
|
||||
def __call__(self, name: str, scale: int = 1) -> tk.PhotoImage:
|
||||
key = (name, scale)
|
||||
if key not in self._cache:
|
||||
self._cache[key] = make_icon(self.master, name, scale)
|
||||
return self._cache[key]
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- Theme
|
||||
|
||||
def apply(root: tk.Tk) -> None:
|
||||
root.configure(bg=FACE)
|
||||
o = root.option_add
|
||||
o("*Font", FONT)
|
||||
o("*Background", FACE)
|
||||
o("*Foreground", DARK)
|
||||
o("*activeBackground", FACE)
|
||||
o("*highlightThickness", 0)
|
||||
o("*selectBackground", NAVY)
|
||||
o("*selectForeground", WHITE)
|
||||
o("*Button.relief", "raised")
|
||||
o("*Button.borderWidth", 2)
|
||||
o("*Button.padX", 8)
|
||||
o("*Button.padY", 1)
|
||||
o("*Entry.background", WHITE)
|
||||
o("*Entry.relief", "sunken")
|
||||
o("*Entry.borderWidth", 2)
|
||||
o("*Entry.disabledBackground", FACE)
|
||||
o("*Text.background", WHITE)
|
||||
o("*Text.relief", "sunken")
|
||||
o("*Text.borderWidth", 2)
|
||||
o("*Listbox.background", WHITE)
|
||||
o("*Listbox.relief", "sunken")
|
||||
o("*Listbox.borderWidth", 2)
|
||||
o("*Checkbutton.selectColor", WHITE)
|
||||
o("*Radiobutton.selectColor", WHITE)
|
||||
o("*Menu.relief", "raised")
|
||||
o("*Menu.activeBackground", NAVY)
|
||||
o("*Menu.activeForeground", WHITE)
|
||||
o("*Menu.activeBorderWidth", 0)
|
||||
o("*TCombobox*Listbox.background", WHITE)
|
||||
o("*TCombobox*Listbox.selectBackground", NAVY)
|
||||
|
||||
from tkinter import font as tkfont
|
||||
zeile = max(18, tkfont.Font(root=root, font=FONT).metrics("linespace") + 5)
|
||||
st = ttk.Style(root)
|
||||
st.theme_use("classic" if "classic" in st.theme_names() else "default")
|
||||
st.configure(".", background=FACE, foreground=DARK, font=FONT, troughcolor=LIGHT,
|
||||
selectbackground=NAVY, selectforeground=WHITE, fieldbackground=WHITE,
|
||||
bordercolor=FACE, lightcolor=HILITE, darkcolor=SHADOW, highlightthickness=0)
|
||||
st.configure("Treeview", background=WHITE, fieldbackground=WHITE, rowheight=zeile, borderwidth=0, font=FONT)
|
||||
st.map("Treeview", background=[("selected", NAVY)], foreground=[("selected", WHITE)])
|
||||
st.configure("Treeview.Heading", background=FACE, relief="raised", borderwidth=2, font=FONT, padding=(3, 1))
|
||||
st.map("Treeview.Heading", relief=[("pressed", "sunken")], background=[("active", FACE)])
|
||||
st.configure("TScrollbar", background=FACE, troughcolor=LIGHT, arrowcolor=DARK, relief="raised", borderwidth=2,
|
||||
arrowsize=16, width=16)
|
||||
st.map("TScrollbar", background=[("active", FACE)])
|
||||
st.configure("TCombobox", fieldbackground=WHITE, background=FACE, arrowsize=14, padding=1)
|
||||
st.map("TCombobox", fieldbackground=[("readonly", WHITE)], selectbackground=[("readonly", WHITE)],
|
||||
selectforeground=[("readonly", DARK)])
|
||||
st.configure("TPanedwindow", background=FACE)
|
||||
st.configure("Sash", sashthickness=6, background=FACE)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- Bausteine
|
||||
|
||||
class Sunken(tk.Frame):
|
||||
"""Eingelassener Rahmen (Doppellinie wie bei Win95-Listen)."""
|
||||
|
||||
def __init__(self, master, **kw):
|
||||
kw.setdefault("bd", 2)
|
||||
kw.setdefault("relief", "sunken")
|
||||
super().__init__(master, **kw)
|
||||
|
||||
|
||||
class Fenster(tk.Frame):
|
||||
"""Ein „Fenster im Fenster“ mit blauer Titelleiste – reine Optik, gliedert die Oberfläche."""
|
||||
|
||||
def __init__(self, master, titel: str, icon: tk.PhotoImage | None = None, **kw):
|
||||
super().__init__(master, bd=2, relief="raised", bg=FACE, **kw)
|
||||
self.titelleiste = tk.Frame(self, bg=NAVY, height=18)
|
||||
self.titelleiste.pack(fill="x", padx=1, pady=1)
|
||||
if icon is not None:
|
||||
tk.Label(self.titelleiste, image=icon, bg=NAVY).pack(side="left", padx=(2, 0))
|
||||
self.titel_var = tk.StringVar(value=titel)
|
||||
tk.Label(self.titelleiste, textvariable=self.titel_var, bg=NAVY, fg=WHITE, font=FONT_BOLD,
|
||||
anchor="w").pack(side="left", fill="x", padx=3)
|
||||
self.inhalt = tk.Frame(self, bg=FACE)
|
||||
self.inhalt.pack(fill="both", expand=True, padx=2, pady=2)
|
||||
|
||||
def set_titel(self, t: str):
|
||||
self.titel_var.set(t)
|
||||
|
||||
|
||||
class Statusleiste(tk.Frame):
|
||||
def __init__(self, master, felder: list[tuple[str, int]]):
|
||||
super().__init__(master, bg=FACE)
|
||||
self.vars: dict[str, tk.StringVar] = {}
|
||||
for i, (key, breite) in enumerate(felder):
|
||||
v = tk.StringVar()
|
||||
lbl = tk.Label(self, textvariable=v, bd=1, relief="sunken", anchor="w", padx=4)
|
||||
if breite:
|
||||
lbl.configure(width=breite)
|
||||
lbl.pack(side="left", padx=(0, 2), pady=2)
|
||||
else:
|
||||
lbl.pack(side="left", fill="x", expand=True, padx=(0, 2), pady=2)
|
||||
self.vars[key] = v
|
||||
|
||||
def set(self, key: str, text: str):
|
||||
self.vars[key].set(text)
|
||||
|
||||
|
||||
def knopf(master, text: str, command=None, icon: tk.PhotoImage | None = None, breite: int | None = None, **kw):
|
||||
b = tk.Button(master, text=text, command=command, bd=2, relief="raised", bg=FACE,
|
||||
activebackground=FACE, **kw)
|
||||
if icon is not None:
|
||||
b.configure(image=icon, compound="left", padx=6)
|
||||
if breite:
|
||||
b.configure(width=breite)
|
||||
return b
|
||||
|
||||
|
||||
class ToolbarButton(tk.Label):
|
||||
"""Flacher Werkzeugleisten-Knopf (Office-95-Stil): hebt sich beim Überfahren, senkt sich beim Klick."""
|
||||
|
||||
def __init__(self, master, text: str, icon: tk.PhotoImage, command, tooltip: str = ""):
|
||||
super().__init__(master, text=text, image=icon, compound="top", bd=1, relief="flat", bg=FACE,
|
||||
padx=6, pady=2, font=FONT)
|
||||
self.command = command
|
||||
self.bind("<Enter>", lambda e: self.configure(relief="raised"))
|
||||
self.bind("<Leave>", lambda e: self.configure(relief="flat"))
|
||||
self.bind("<ButtonPress-1>", lambda e: self.configure(relief="sunken"))
|
||||
self.bind("<ButtonRelease-1>", self._release)
|
||||
if tooltip:
|
||||
Tooltip(self, tooltip)
|
||||
|
||||
def _release(self, e):
|
||||
self.configure(relief="raised")
|
||||
if 0 <= e.x < self.winfo_width() and 0 <= e.y < self.winfo_height() and self.command:
|
||||
self.command()
|
||||
|
||||
|
||||
class Tooltip:
|
||||
def __init__(self, widget, text: str):
|
||||
self.widget, self.text, self.tip, self._after = widget, text, None, None
|
||||
widget.bind("<Enter>", self._plan, add="+")
|
||||
widget.bind("<Leave>", self._weg, add="+")
|
||||
widget.bind("<ButtonPress>", self._weg, add="+")
|
||||
|
||||
def _plan(self, _e):
|
||||
self._after = self.widget.after(600, self._zeigen)
|
||||
|
||||
def _zeigen(self):
|
||||
x = self.widget.winfo_rootx() + 10
|
||||
y = self.widget.winfo_rooty() + self.widget.winfo_height() + 4
|
||||
self.tip = tw = tk.Toplevel(self.widget)
|
||||
tw.wm_overrideredirect(True)
|
||||
tw.wm_geometry(f"+{x}+{y}")
|
||||
tk.Label(tw, text=self.text, bg=INFO_BG, bd=1, relief="solid", padx=4, pady=1).pack()
|
||||
|
||||
def _weg(self, _e=None):
|
||||
if self._after:
|
||||
self.widget.after_cancel(self._after)
|
||||
self._after = None
|
||||
if self.tip:
|
||||
self.tip.destroy()
|
||||
self.tip = None
|
||||
|
||||
|
||||
def trenner(master, vertikal: bool = True):
|
||||
f = tk.Frame(master, bg=FACE)
|
||||
if vertikal:
|
||||
tk.Frame(f, width=1, bg=SHADOW).pack(side="left", fill="y")
|
||||
tk.Frame(f, width=1, bg=HILITE).pack(side="left", fill="y")
|
||||
else:
|
||||
tk.Frame(f, height=1, bg=SHADOW).pack(fill="x")
|
||||
tk.Frame(f, height=1, bg=HILITE).pack(fill="x")
|
||||
return f
|
||||
|
||||
|
||||
def gruppe(master, titel: str, **kw) -> tk.LabelFrame:
|
||||
return tk.LabelFrame(master, text=titel, bd=2, relief="groove", bg=FACE, padx=6, pady=4, **kw)
|
||||
|
||||
|
||||
def scroll_tree(master, **kw) -> tuple[tk.Frame, ttk.Treeview]:
|
||||
rahmen = Sunken(master, bg=WHITE)
|
||||
tree = ttk.Treeview(rahmen, **kw)
|
||||
vs = ttk.Scrollbar(rahmen, orient="vertical", command=tree.yview)
|
||||
hs = ttk.Scrollbar(rahmen, orient="horizontal", command=tree.xview)
|
||||
tree.configure(yscrollcommand=vs.set, xscrollcommand=hs.set)
|
||||
tree.grid(row=0, column=0, sticky="nsew")
|
||||
vs.grid(row=0, column=1, sticky="ns")
|
||||
hs.grid(row=1, column=0, sticky="ew")
|
||||
rahmen.rowconfigure(0, weight=1)
|
||||
rahmen.columnconfigure(0, weight=1)
|
||||
return rahmen, tree
|
||||
|
||||
|
||||
def auto_breite(tree: ttk.Treeview, flex: dict[str, float], reserve: int = 4):
|
||||
"""Feste Spalten behalten ihre Breite, die „flex“-Spalten teilen sich den Rest anteilig.
|
||||
So bleiben z. B. die Betragsspalten immer sichtbar, egal wie breit das Fenster ist."""
|
||||
|
||||
def anpassen(_e=None):
|
||||
verfuegbar = tree.winfo_width() - reserve
|
||||
if verfuegbar < 50:
|
||||
return
|
||||
alle = ["#0"] + list(tree["columns"]) if "tree" in str(tree["show"]) else list(tree["columns"])
|
||||
fest = sum(int(tree.column(c, "width")) for c in alle if c not in flex)
|
||||
rest = max(0, verfuegbar - fest)
|
||||
summe = sum(flex.values())
|
||||
for c, anteil in flex.items():
|
||||
minimum = int(tree.column(c, "minwidth"))
|
||||
tree.column(c, width=max(minimum, int(rest * anteil / summe)))
|
||||
|
||||
tree.bind("<Configure>", anpassen, add="+")
|
||||
return anpassen
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- Dialoge
|
||||
|
||||
class Dialog(tk.Toplevel):
|
||||
"""Modaler Dialog im Win95-Stil."""
|
||||
|
||||
def __init__(self, master, titel: str, resizable: bool = False):
|
||||
super().__init__(master, bg=FACE)
|
||||
self.withdraw()
|
||||
self.title(titel)
|
||||
self.transient(master.winfo_toplevel())
|
||||
self.resizable(resizable, resizable)
|
||||
self.result = None
|
||||
self.protocol("WM_DELETE_WINDOW", self.abbrechen)
|
||||
self.bind("<Escape>", lambda e: self.abbrechen())
|
||||
try:
|
||||
self.iconphoto(False, master.winfo_toplevel()._app_icon) # type: ignore[attr-defined]
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def zeigen(self, fokus=None):
|
||||
self.update_idletasks()
|
||||
m = self.master.winfo_toplevel()
|
||||
w, h = self.winfo_reqwidth(), self.winfo_reqheight()
|
||||
x = m.winfo_rootx() + max(0, (m.winfo_width() - w) // 2)
|
||||
y = m.winfo_rooty() + max(0, (m.winfo_height() - h) // 3)
|
||||
self.geometry(f"+{x}+{y}")
|
||||
self.deiconify()
|
||||
self.lift()
|
||||
try:
|
||||
self.grab_set()
|
||||
except tk.TclError:
|
||||
pass
|
||||
(fokus or self).focus_set()
|
||||
self.wait_window()
|
||||
return self.result
|
||||
|
||||
def abbrechen(self):
|
||||
self.result = None
|
||||
self.destroy()
|
||||
|
||||
def knopfleiste(self, knoepfe: list[tuple[str, object]], default: int = 0) -> tk.Frame:
|
||||
f = tk.Frame(self, bg=FACE)
|
||||
for i, (text, cmd) in enumerate(knoepfe):
|
||||
b = knopf(f, text, cmd, breite=10)
|
||||
if i == default:
|
||||
b.configure(default="active")
|
||||
b.pack(side="left", padx=4)
|
||||
return f
|
||||
|
||||
|
||||
def _meldung(master, titel: str, text: str, icon: str, knoepfe: list[tuple[str, object]], default=0):
|
||||
d = Dialog(master, titel)
|
||||
body = tk.Frame(d, bg=FACE)
|
||||
body.pack(fill="both", expand=True, padx=12, pady=(14, 8))
|
||||
ic = make_icon(d, icon, 2)
|
||||
d._ic = ic
|
||||
tk.Label(body, image=ic, bg=FACE).pack(side="left", anchor="n", padx=(0, 14))
|
||||
tk.Label(body, text=text, bg=FACE, justify="left", wraplength=420, anchor="w").pack(side="left", fill="x")
|
||||
|
||||
def mk(val):
|
||||
def f():
|
||||
d.result = val
|
||||
d.destroy()
|
||||
return f
|
||||
|
||||
leiste = d.knopfleiste([(t, mk(v)) for t, v in knoepfe], default)
|
||||
leiste.pack(pady=(4, 12))
|
||||
d.bind("<Return>", lambda e: mk(knoepfe[default][1])())
|
||||
return d.zeigen()
|
||||
|
||||
|
||||
def info(master, titel: str, text: str):
|
||||
_meldung(master, titel, text, "info", [("OK", True)])
|
||||
|
||||
|
||||
def warnung(master, titel: str, text: str):
|
||||
_meldung(master, titel, text, "warnung", [("OK", True)])
|
||||
|
||||
|
||||
def fehler(master, titel: str, text: str):
|
||||
_meldung(master, titel, text, "fehler", [("OK", True)])
|
||||
|
||||
|
||||
def frage(master, titel: str, text: str, ja: str = "Ja", nein: str = "Nein", default_ja: bool = True) -> bool:
|
||||
return bool(_meldung(master, titel, text, "frage", [(ja, True), (nein, False)], 0 if default_ja else 1))
|
||||
|
||||
|
||||
def eingabe(master, titel: str, text: str, wert: str = "") -> str | None:
|
||||
d = Dialog(master, titel)
|
||||
tk.Label(d, text=text, bg=FACE, justify="left", anchor="w").pack(fill="x", padx=12, pady=(12, 4))
|
||||
var = tk.StringVar(value=wert)
|
||||
e = tk.Entry(d, textvariable=var, width=46)
|
||||
e.pack(padx=12, pady=4)
|
||||
e.select_range(0, "end")
|
||||
|
||||
def ok():
|
||||
d.result = var.get()
|
||||
d.destroy()
|
||||
|
||||
d.bind("<Return>", lambda _e: ok())
|
||||
d.knopfleiste([("OK", ok), ("Abbrechen", d.abbrechen)]).pack(pady=(6, 12))
|
||||
return d.zeigen(e)
|
||||
Reference in new issue
Block a user