fix: окно расчёта показателей 8/9 — не уходит на задний план, ввод работает, кнопка на месте

Проблемы:
1. Окно уходило на задний план при сдвиге — не было grab_set/lift,
   родитель указывал на главное окно вместо диалога ПП 127
2. В показателе 8 не вводились данные — из-за потери фокуса
3. В показателе 9 кнопка «Рассчитать» не была видна — окно 720x560
   не вмещало все поля (прибыль/налог/ΔДоходов/бюджет/НДПИ/ДИВ/ВСО/НС +
   результат), кнопки уезжали за край

Исправлено:
- родитель окна — dialog (ПП 127), а не root
- w.transient(dialog) + w.lift() + w.grab_set() + w.focus_force()
- тело окна в Canvas + вертикальный Scrollbar (все поля доступны)
- кнопки «🧮 Рассчитать / ✔️ Применить / Отмена» вне скролла — всегда видны
- при закрытии — grab_release()
This commit is contained in:
2026-08-04 23:50:25 +04:00
parent e4e7bb444a
commit 220b923e76
+38 -16
View File
@@ -2172,23 +2172,38 @@ class DokoGenApp:
profit = getattr(self.model, 'profit', '') or ''
profit_tax = getattr(self.model, 'profit_tax', '') or ''
w = tk.Toplevel(self.root)
# Родитель — окно ПП 127 (dialog), а не главное окно;
# grab_set + lift — чтобы окно не уходило на задний план
w = tk.Toplevel(dialog)
w.title(f"🧮 Авторасчёт показателя {num}{name[:60]}")
w.geometry("720x560")
w.transient(self.root)
frm = ttk.Frame(w, padding=10)
frm.pack(fill=tk.BOTH, expand=True)
w.geometry("820x700")
w.transient(dialog)
w.lift()
w.focus_force()
# Внешняя рамка: тело со скроллом + кнопки снизу (всегда видны)
outer = ttk.Frame(w, padding=10)
outer.pack(fill=tk.BOTH, expand=True)
canvas = tk.Canvas(outer, highlightthickness=0)
scrollbar = ttk.Scrollbar(outer, orient=tk.VERTICAL, command=canvas.yview)
frm = ttk.Frame(canvas)
frm.bind("<Configure>", lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
canvas.create_window((0, 0), window=frm, anchor="nw")
canvas.configure(yscrollcommand=scrollbar.set)
canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
if num == '9':
ttk.Label(frm, text="Показатель 9 — ущерб бюджетам РФ (применим ко всем субъектам КИИ)",
font=('Arial', 10, 'bold')).pack(anchor=tk.W)
ttk.Label(frm, text="Формула: №9 = ΔБ / Бусредн × 100%, где ΔБ = ΔНП + ΔНДПИ + ΔДИВ + ΔВСО + ΔНС\n"
"ΔНП = ΔДоходов × (налог на прибыль / прибыль); если ΔДоходов > прибыли — весь налог.",
foreground='gray', wraplength=660, justify=tk.LEFT).pack(anchor=tk.W, pady=(2, 6))
foreground='gray', wraplength=760, justify=tk.LEFT).pack(anchor=tk.W, pady=(2, 6))
def _row(label, key, default=''):
ttk.Label(frm, text=label).pack(anchor=tk.W, pady=(4, 0))
e = ttk.Entry(frm, width=60)
e = ttk.Entry(frm, width=70)
e.insert(0, str(default or ''))
e.pack(fill=tk.X)
return e
@@ -2204,18 +2219,18 @@ class DokoGenApp:
e_div = _row("Снижение выплат от дивидендов ΔДИВ (руб.):", 'div', '0')
e_vso = _row("Снижение выплат сторонних организаций ΔВСО (руб.):", 'vso', '0')
e_ns = _row("Снижение сборов ΔНС (руб.):", 'ns', '0')
result = tk.Text(frm, height=10, wrap=tk.WORD, state=tk.NORMAL)
result = tk.Text(frm, height=8, wrap=tk.WORD, state=tk.NORMAL)
result.pack(fill=tk.BOTH, expand=True, pady=(8, 0))
else:
ttk.Label(frm, text="Показатель 8 — ущерб субъекту КИИ",
font=('Arial', 10, 'bold')).pack(anchor=tk.W)
ttk.Label(frm, text="Применим только для: госкорпорации, ГУП, госкомпании, стратегического АО/предприятия "
"(Указ Президента № 1009).\nФормула: №8 = ΔДоходов / Дусредн × 100%.",
foreground='gray', wraplength=660, justify=tk.LEFT).pack(anchor=tk.W, pady=(2, 6))
foreground='gray', wraplength=760, justify=tk.LEFT).pack(anchor=tk.W, pady=(2, 6))
def _row(label, key, default=''):
ttk.Label(frm, text=label).pack(anchor=tk.W, pady=(4, 0))
e = ttk.Entry(frm, width=60)
e = ttk.Entry(frm, width=70)
e.insert(0, str(default or ''))
e.pack(fill=tk.X)
return e
@@ -2230,7 +2245,7 @@ class DokoGenApp:
'dincome', f"{_d_loss:,.0f}" if _d_loss else '')
e_budget = _row("Доходы субъекта КИИ, усреднённые за 5 лет (руб.):",
'budget', f"{_d_avg:,.0f}" if _d_avg else '')
result = tk.Text(frm, height=10, wrap=tk.WORD, state=tk.NORMAL)
result = tk.Text(frm, height=8, wrap=tk.WORD, state=tk.NORMAL)
result.pack(fill=tk.BOTH, expand=True, pady=(8, 0))
def _calc():
@@ -2240,7 +2255,7 @@ class DokoGenApp:
b = _num(e_budget.get())
if d is None or b is None or b <= 0:
result.delete('1.0', tk.END)
result.insert('1.0', "Заполните оба поля (ΔДоходов и Дусредн).")
result.insert('1.0', "Заполните оба поля (ущерб и доходы за 5 лет).")
return
val = d / b * 100
lines.append(f"Суммарный экономический ущерб от нарушения критических процессов: {d:,.0f} руб.")
@@ -2316,12 +2331,10 @@ class DokoGenApp:
elif 'Категория значимости: III' in cat_line:
cat = 'III'
if cat:
# Выбрать в комбобоксе соответствующую категорию
opts = list(combo['values'])
target = next((o for o in opts if o.startswith(f"{cat} категория")), None)
if target:
var.set(target)
# Обоснование с расчётом
prefix = f"Показатель {num}. {name}{cat} категория."
full = prefix + "\n" + txt
cur = justify_txt.get('1.0', 'end-1c').strip()
@@ -2340,14 +2353,23 @@ class DokoGenApp:
justify_txt.insert('end', '\n' + full)
else:
justify_txt.insert('1.0', full)
w.grab_release()
w.destroy()
btns = ttk.Frame(frm)
# Кнопки — вне скролла, всегда видны
btns = ttk.Frame(outer)
btns.pack(fill=tk.X, pady=(8, 0))
ttk.Button(btns, text="🧮 Рассчитать", command=_calc).pack(side=tk.LEFT, padx=2)
ttk.Button(btns, text="✔️ Применить категорию", command=_apply).pack(side=tk.LEFT, padx=2)
ttk.Button(btns, text="Отмена", command=w.destroy).pack(side=tk.LEFT, padx=2)
ttk.Button(btns, text="Отмена",
command=lambda: (w.grab_release(), w.destroy())).pack(side=tk.LEFT, padx=2)
# Захват фокуса — окно не уходит на задний план
try:
w.grab_set()
except Exception:
pass
w.lift()
rows = [] # (num, name, values{III:..,II:..,I:..}, var, applicable)
_combos = {} # num -> комбобокс (для автозаполнения)