Tkinter 菜单在另一个模块中执行 New_Debtor_Acc。 New_Debtor_Acc 也使用 tkinter。该标签有一个trace_add()来验证交互输入的数据。但它不会执行,使用正常的“def New_Debtor_Acc”。
但是我确实发现,当我插入一个重复的调用时,如果没有“def”,就会执行验证。显然,现在在主菜单启动之前的初始化过程中调用该方法。 以下是2个模块>
# start.py
# ========
# Import functions
from tkinter import *
from tkinter.ttk import *
from accdeb import New_Debtor_Acc
# Create main menu
class MenuApp(Tk):
def __init__(self):
super().__init__()
self.geometry('1048x640+100+100')
self.title('A2B')
self.resizable(False, False)
# Create menubar
menubar = Menu(self)
dashboardmenu = Menu(menubar, tearoff=0)
accountsmenu = Menu(menubar, tearoff=0)
exitmenu = Menu(menubar, tearoff=0)
# Add Dashboard Menu and commands
menubar.add_cascade(label='Dashboard', menu=dashboardmenu)
dashboardmenu.add_command(label="Main Dashboard", command=self.DoNothing)
dashboardmenu.add_command(label="Unallocated Freight", command=self.DoNothing)
# Add Accounts Menu and commands
menubar.add_cascade(label='Accounts', menu=accountsmenu)
accountsmenu.add_command(label="General Ledger", command=self.DoNothing)
accountsmenu.add_cascade(label='Debtors', command=New_Debtor_Acc) # New Debtor
accountsmenu.add_command(label="Creditors", command=self.DoNothing)
accountsmenu.add_command(label="Stock", command=self.DoNothing)
# Add Exit Menu and commands
menubar.add_cascade(label='Exit', menu=exitmenu)
exitmenu.add_command(label="Quit", command=self.destroy)
# Display Menu
(self.config(menu=menubar))
# Do nothing button used while program is still in development
def DoNothing(self):
win = NothingApp(self)
# While program is still in development, use this nothing window
class NothingApp(Toplevel):
def __init__(self, parent):
super().__init__(parent)
self.geometry('300x100+200+200')
self.title('Do Nothing')
# To allow the nothing window to receive events and prevent
# users from interacting with the main window
self.grab_set()
Button(self, text='Close',
command=self.destroy).pack(expand=True)
# Main menu
def main_menu():
mnu = MenuApp()
# Run main loop
mnu.mainloop()
if __name__ == "__main__":
# Main menu
main_menu()
# accdeb.py
# =========
# Import functions
import tkinter as tk
# Debtor App
class DebtorApp(tk.Tk):
def __init__(self, hdr_desc: str):
super().__init__()
self.grab_set() # Disable main menu
self.geometry('600x640+150+150')
self.title(hdr_desc + ' Debtor Account')
self.resizable(False, False)
self.ent1_deb_mst_nrVar = tk.StringVar()
self.ent1_deb_mst_nrVar.trace_add("write", self.validate_deb_mst_nr)
self.lblZ_deb_msgVar = tk.StringVar()
# Status frame
status_frame = tk.Frame(self)
status_frame.pack()
padding = {'padx': 5, 'pady': 5}
# Status message
status_frame.lblY_deb_msg = tk.Label(status_frame, text="Status : ", **padding)
status_frame.lblY_deb_msg.pack(side='left')
status_frame.lblZ_deb_msg = tk.Label(status_frame, textvariable=self.lblZ_deb_msgVar,
text="None", foreground='red', **padding)
status_frame.lblZ_deb_msg.pack(side='left')
# Body frame
body_frame = tk.Frame(self)
body_frame.pack()
# Configure the grid
body_frame.columnconfigure(0, weight=2)
body_frame.columnconfigure(1, weight=2)
# Debtor master account nr
body_frame.lbl1_deb_mst_nr = tk.Label(body_frame,
text="Debtor master account number [AAAA0000]")
body_frame.lbl1_deb_mst_nr.grid(column=0, row=0, sticky=tk.W, **padding)
self.cmd_deb_mst_nr = (body_frame.register(self.validate_deb_mst_nr), '%P')
body_frame.ent1_deb_mst_nr = tk.Entry(body_frame, width=12,
textvariable=self.ent1_deb_mst_nrVar)
body_frame.ent1_deb_mst_nr.grid(column=1, row=0, sticky=tk.E, **padding)
body_frame.ent1_deb_mst_nr.focus_set()
# Button frame
button_frame = tk.Frame(self)
button_frame.pack()
# Close button
button_frame.btn1_close = tk.Button(button_frame, text='Close', command=self.destroy)
button_frame.btn1_close.grid(column=1, row=3, sticky=tk.E, **padding)
def validate_deb_mst_nr(self, *args):
input_deb_mst_nr = self.ent1_deb_mst_nrVar.get().upper()
error_msg = valid_deb_mst(input_deb_mst_nr)
self.ent1_deb_mst_nrVar.set(input_deb_mst_nr)
self.lblZ_deb_msgVar.set(error_msg)
# Validate Deb Master Number
def valid_deb_mst(input_chrs):
# Allowed input format: [AAAA0000]
allowed_chrs = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
allowed_nums = '1234567890'
format_mess = 'Format is [AAAA0000]'
length_chrs = len(input_chrs)
# Check position 1 to 4 for alphabetic characters
if (length_chrs > 0) and (length_chrs <= 4):
copy_chrs = input_chrs[0:4-1]
valid_chars = all(c in allowed_chrs for c in copy_chrs)
if not valid_chars:
error_mess = "".join([format_mess, '\n', "Input should be Alphabetic [AAAA..."])
else:
error_mess = ""
# Check position 5 to 8 for numeric characters
elif (length_chrs >= 5) and (length_chrs <= 8):
copy_chrs = input_chrs[5-1:8] # [5-1:8-1] Somehow miss to pick up char on position 8
valid_chars = all(c in allowed_nums for c in copy_chrs)
if not valid_chars:
error_mess = "".join([format_mess, '\n', "Input should be Numeric ...0000]"])
else:
error_mess = ""
# Check length max 8 characters
elif length_chrs > 8:
error_mess = "".join([format_mess, '\n', "Too many characters entered"])
# All OK
else:
error_mess = ""
return error_mess
# New Debtor
def New_Debtor_Acc():
deb = DebtorApp('New')
# 1. When New_Debtor_Acc below is NOT run:
# The validation via trace_add("write", self.validate_deb_mst_nr) is NOT run
# 2. When New_Debtor_Acc below IS run:
# The validation via trace_add("write", self.validate_deb_mst_nr) IS run
# It obviously also run on program initialisation...
# What am I doing wrong?
#
# New_Debtor_Acc()
if __name__ == "__main__":
raise RuntimeError("accdeb.py: This module may NOT run as main.")
感谢 Bryan Oakley 和 jasonharper 的回答。 tk.Toplevel 成功了。