Tkinter -trace_add() 不执行验证方法

问题描述 投票:0回答:1

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.")
python-3.x tkinter
1个回答
0
投票

感谢 Bryan Oakley 和 jasonharper 的回答。 tk.Toplevel 成功了。

© www.soinside.com 2019 - 2024. All rights reserved.