【问题标题】:Reduce the lines of code (tkinter, Python, Multiple labels, entry)减少代码行数(tkinter、Python、多标签、条目)
【发布时间】:2021-02-03 13:59:55
【问题描述】:

说明:点击提交按钮后,条目应出现在树中。

我已限制条目字段,因此它们只能取两个值(使用跟踪方法)。

问题1:我一共有8个entry,也就是说代码有8个StringVar,8个entry,8个label,1个button,一共17个grid。请帮我减少代码。

问题 2:我需要一个可以全局使用的列表中的条目。

from tkinter import Tk, Frame, Button, Label, Entry, ttk, StringVar, Scrollbar
import datetime

# Main Window
class WINDOW(Tk):
    def __init__(self, master):
        Tk.__init__(self, master)
        self.master = master

        frame1 = Frame1(self)
        frame1.grid(row=0,column=0)
        list_of_entries=[]

class Frame1(Frame):
    def __init__(self, master):
        Frame.__init__(self, master,height=master.winfo_screenheight(),
                       width=master.winfo_screenwidth())
        self.master = master


        one_var = StringVar()
        two_var = StringVar()
        three_var = StringVar()
        four_var = StringVar()
        five_var = StringVar()

        # Restrict entry field for 2 values only (using trace)
        one_var.trace("w", lambda name, index, mode, one_var=one_var: callback())
        two_var.trace("w", lambda name, index, mode, two_var=one_var: callback())
        three_var.trace("w", lambda name, index, mode, three_var=one_var: callback())
        four_var.trace("w", lambda name, index, mode, four_var=one_var: callback())
        five_var.trace("w", lambda name, index, mode, five_var=one_var: callback())

        def callback(*args):
            one_var.set(one_var.get()[:2])
            two_var.set(two_var.get()[:2])
            three_var.set(three_var.get()[:2])
            four_var.set(four_var.get()[:2])
            five_var.set(five_var.get()[:2])


        # Request frame labels

        DATA0_lbl = Label(self, text='DATA0', font=('calibre', 10, 'bold'))
        DATA1_lbl = Label(self, text='DATA1', font=('calibre', 10, 'bold'))
        DATA2_lbl = Label(self, text='DATA2', font=('calibre', 10, 'bold'))
        DATA3_lbl = Label(self, text='DATA3', font=('calibre', 10, 'bold'))
        DATA4_lbl = Label(self, text='DATA4', font=('calibre', 10, 'bold'))

        # Request frame label grid
        DATA0_lbl.grid(row=0, column=0)
        DATA1_lbl.grid(row=0, column=1)
        DATA2_lbl.grid(row=0, column=2)
        DATA3_lbl.grid(row=0, column=3)
        DATA4_lbl.grid(row=0, column=4)

        # Request frame entry fields
        DATA0_entry = Entry(self,textvariable=one_var, width=10, font=('calibre', 10, 'normal'))
        DATA1_entry = Entry(self,textvariable=two_var,  width=10, font=('calibre', 10, 'normal'))
        DATA2_entry = Entry(self, textvariable=three_var, width=10, font=('calibre', 10, 'normal'))
        DATA3_entry = Entry(self,textvariable=four_var,  width=10, font=('calibre', 10, 'normal'))
        DATA4_entry = Entry(self, textvariable=five_var, width=10, font=('calibre', 10, 'normal'))

        # Request frame entry field grid
        DATA0_entry.grid(row=1, column=0)
        DATA1_entry.grid(row=1, column=1)
        DATA2_entry.grid(row=1, column=2)
        DATA3_entry.grid(row=1, column=3)
        DATA4_entry.grid(row=1, column=4)



        # Log data sheet
        NewTree = ttk.Treeview(self, height=23, columns=("DATA0","DATA1", "DATA2", "DATA3","DATA4"))

        NewTree.column("#0", width=180)
        NewTree.column("#1", width=150)
        NewTree.column("#2", width=150)
        NewTree.column("#3", width=150)
        NewTree.column("#4", width=150)
        NewTree.column("#5", width=150)

        NewTree.heading("#0",text='TIME')
        NewTree.heading("#1",text='DATA0')
        NewTree.heading("#2",text='DATA1')
        NewTree.heading("#3",text='DATA2')
        NewTree.heading("#4",text="DATA3")
        NewTree.heading("#5", text="DATA4")

        NewTree.grid(row=5, columnspan=4)

        def insert_data():
            NewTree.insert('', 'end', text=datetime.datetime.now(),
                                 values=(DATA0_entry.get(),
                                         DATA1_entry.get(),
                                         DATA2_entry.get(),
                                         DATA3_entry.get(),
                                         DATA4_entry.get()))
            one_var.set("")
            two_var.set("")
            three_var.set("")
            four_var.set("")
            five_var.set("")

        submit_button = Button(self, text="SUBMIT", command=insert_data)
        submit_button.grid(row=3, column=4)


root = WINDOW(None)
root.geometry(f'{root.winfo_screenwidth()}x{root.winfo_screenheight()}')
root.title("ADD DATA")


root.mainloop()

【问题讨论】:

  • 使用for 循环?

标签: python tkinter tkinter-entry tkinter-label


【解决方案1】:

您可以使用循环来创建条目和标签。通过使用入口小部件的验证功能而不是跟踪,您可以完全抛弃跟踪语句和StringVar 的实例。

全部加起来,这最终会减少大约 50 行左右的代码。

入口验证的详细解释见Interactively validating Entry widget content in tkinter

这是一个完整的例子:

from tkinter import Tk, Frame, Button, Label, Entry, ttk, StringVar, Scrollbar
import datetime

# Main Window
class WINDOW(Tk):
    def __init__(self, master):
        Tk.__init__(self, master)
        self.master = master

        frame1 = Frame1(self)
        frame1.grid(row=0,column=0)
        list_of_entries=[]

class Frame1(Frame):
    def __init__(self, master):
        Frame.__init__(self, master,height=master.winfo_screenheight(),
                       width=master.winfo_screenwidth())
        self.master = master

        vcmd = (self.register(self.validate), '%P')
        self.entries = []
        for i in range(5):
            label = Label(self, text=f"DATA{i}", font=('calibre', 10, 'bold'))
            entry = Entry(self, validatecommand=vcmd, validate='key', width=10, font=('calibre', 10, 'normal'))
            label.grid(row=0, column=i)
            entry.grid(row=1, column=i)
            self.entries.append(entry)

        # Log data sheet
        NewTree = ttk.Treeview(self, height=23, columns=("DATA0","DATA1", "DATA2", "DATA3","DATA4"))

        NewTree.column("#0", width=180)
        NewTree.column("#1", width=150)
        NewTree.column("#2", width=150)
        NewTree.column("#3", width=150)
        NewTree.column("#4", width=150)
        NewTree.column("#5", width=150)

        NewTree.heading("#0",text='TIME')
        NewTree.heading("#1",text='DATA0')
        NewTree.heading("#2",text='DATA1')
        NewTree.heading("#3",text='DATA2')
        NewTree.heading("#4",text="DATA3")
        NewTree.heading("#5", text="DATA4")

        NewTree.grid(row=5, columnspan=4)

        def insert_data():
            NewTree.insert('', 'end', text=datetime.datetime.now(),
                                 values=(self.entries[0].get(),
                                         self.entries[1].get(),
                                         self.entries[2].get(),
                                         self.entries[3].get(),
                                         self.entries[4].get()))
            for i in range(5):
                self.entries[i].delete(0, 'end')

        submit_button = Button(self, text="SUBMIT", command=insert_data)
        submit_button.grid(row=3, column=4)

    def validate(self, new_value):
        return len(new_value) <= 2


root = WINDOW(None)
root.geometry(f'{root.winfo_screenwidth()}x{root.winfo_screenheight()}')
root.title("ADD DATA")


root.mainloop()

【讨论】:

  • 非常感谢。有用。但我没有得到列表中条目字段的值。因为我需要在将数据插入树之前检查条目值是否为十六进制
  • 是否可以限制条目字段,它只能采用十六进制值,只能使用验证方法的二进制??
  • @namratapatted:是的,这是可能的。你可以在 validate 函数中添加任何你想要的检查。
  • 支票是什么意思。我没听懂。
  • validate 函数正在执行检查,并根据字符的长度返回 True 或 False。您可以根据要执行的任何其他检查返回 True 或 False。例如,您可以检查长度是否小于或等于 2,并且它是否仅包含字符 0-9 和 a-f。
【解决方案2】:

首先,您可以完全减少代码,只需使用 for 循环,也可以放弃使用 StringVar 而是使用 tkinter 进行验证,请看这里:

from tkinter import Tk, Frame, Button, Label, Entry, ttk, StringVar, Scrollbar
import datetime

# Main Window
class WINDOW(Tk):
    def __init__(self, master):
        Tk.__init__(self, master)
        self.master = master

        frame1 = Frame1(self)
        frame1.grid(row=0,column=0)
        list_of_entries=[]

class Frame1(Frame):
    def __init__(self, master):
        Frame.__init__(self, master,height=master.winfo_screenheight(),
                       width=master.winfo_screenwidth())
        self.master = master 
        vcmd = self.register(self.validate) # Register the validation function
        
        NewTree = ttk.Treeview(self, height=23, columns=("DATA0","DATA1", "DATA2", "DATA3","DATA4"))
        NewTree.grid(row=5, columnspan=4)
        
        NewTree.column("#0", width=180) # These column would stand out of the loop
        NewTree.heading("#0",text='TIME') # So manually inserting them

        MAX_WIDGETS = 5
        base_text = 'DATA' # Base text, so later you can add 1 to make it DATA1 and so on..
        lbls = [] # Empty list for label to append to later, not necessary if you dont need to change or reuse them later
        self.entries = []
        for i in range(MAX_WIDGETS):
            NewTree.column(f"#{str(i+1)}", width=150) # i+1 because you have an extra column already
            NewTree.heading(f"#{str(i+1)}",text=base_text+str(i))
            
            lbls.append(Label(self, text=base_text+str(i), font=('calibre', 10, 'bold')))
            lbls[i].grid(row=0, column=i)

            self.entries.append(Entry(self, width=10, font=('calibre', 10, 'normal'),validate='key',validatecommand=(vcmd,'%P')))
            self.entries[i].grid(row=1, column=i)

        submit_button = Button(self, text="SUBMIT", command=lambda: self.insert_data(NewTree))
        submit_button.grid(row=3, column=4)

    def insert_data(self,tree):
        data = [x.get() for x in self.entries]
        tree.insert('', 'end', text=datetime.datetime.now(),
                                values=data)
        [x.delete(0,'end') for x in self.entries] # Just to delete the items, list is otherwise of no use.

    def validate(self,inp): # The validation function
        return len(inp) <= 2

root = WINDOW(None)

root.geometry(f'{root.winfo_screenwidth()}x{root.winfo_screenheight()}')
root.title("ADD DATA")

root.mainloop()

我已尽可能缩短代码,使用for。有时不可能将内容保持在循环范围内,例如你额外的TIME 列,所以我把它放在循环之外。而且由于您使用的是类,因此可以最大限度地利用它,而不是定义函数,而是定义方法等。你之前的版本大概是 120 行左右,现在减少到 60 行左右。

您还可以进一步使用更多的 LC(List Comprehension),但我认为它可能会降低代码的可读性,因为这是编写代码时要牢记的重要因素。

您可以摆脱将标签附加到列表中,如果您不打算重复使用它们,它将节省 1 额外的行 ;)

要更好地理解验证,请查看:Interactively validating Entry widget content in tkinter

【讨论】:

  • 非常感谢您抽出宝贵的时间。但它没有插入数据。它有助于减少代码。特别是树部分
  • @namratapatted 你是什么意思它没有插入数据。请记住,必须填写所有框才能插入数据。如果您不想使用它,请删除 if 内部的 insert_data
猜你喜欢
  • 2013-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多