【问题标题】:Python Tkinter with classes带有类的 Python Tkinter
【发布时间】:2019-01-22 20:31:01
【问题描述】:

尝试开发一个工作应用程序,我想将 UI 和主控制器类代码分开。我应该如何处理这个?

我创建了我的 MainUi 类。

class MainUi:
store_number = ''
tld_date = ''

def __init__(self, root):
    self.root = root
    root.title("TacoBell TLD Tool")
    self.store_number = IntVar()
    self.tld_date = IntVar()

    self.lblstore_number = Label(root, text="Store Number (XXXXXX): ")
    self.lbltld_date = Label(root, text="TLD Date(MM/DD/YYYY): ")

    self.lblstore_number.grid(row=0, sticky=E)  # Sticky align text North(N), East(E), South(S), West(W0
    self.lbltld_date.grid(row=1, sticky=E)

    self.entStore = Entry(self.root, textvariable=self.store_number)
    self.entDate = Entry(self.root, textvariable=self.tld_date)

    self.entStore.grid(row=0, column=1)
    self.entDate.grid(row=1, column=1)

我需要定义 getter 和 setter 吗?我希望将这些条目存储在我的主类中的两个变量中,这样我就可以将主类中的变量传递给其他函数。

import paramiko
import os
import csv
import tools
from ui import MainUi
from tkinter import *


root = Tk()
ui = MainUi(root)
# get store number and date data from UI.py and store them as variables here 
root.mainloop()

【问题讨论】:

    标签: python python-3.x oop tkinter


    【解决方案1】:

    是的,您可以通过更改类变量store_numbertld_date 将它们分开。为此,您需要获取输入框中的数字并将它们保存为变量。我们可以通过调用self.store_number = self.entStore.get()self.tld_date = self.entDate.get() 方便地做到这一点

    MainUI.py

    ​​>
    from tkinter import *
    
    class LaunchMainUi:
        store_number = ''
        tld_date = ''
    
        def __init__(self, root):
            self.root = root
            root.title("TacoBell TLD Tool")
            self.store_number = IntVar()
            self.tld_date = IntVar()
    
            Label(root, text="Store Number (XXXXXX): ").grid(row=0, sticky=E)  # Sticky align text North(N), East(E), South(S), West(W)
            Label(root, text="TLD Date(MM/DD/YYYY): ").grid(row=1, sticky=E)
    
            self.entStore = Entry(self.root)
            self.entDate = Entry(self.root)
    
            self.entStore.grid(row=0, column=1)
            self.entDate.grid(row=1, column=1)
    
            self.confirm = Button(root, text="Confirm", command=self.save)
            self.confirm.grid(row=2, column=1)
    
        def save(self, event=None):
            storeNumber = self.entStore.get()
            tldDate = self.entDate.get()
    
            #Saved as method variables ^ in order to perform necessary validation checks easier
    
            #If entered items are valid:
            self.store_number = storeNumber
            self.tld_date = tldDate
            self.root.destroy()
    

    我首先更改了类名,以便文件名和类名不会冲突。然后我创建了一个名为self.confirm 的按钮并将其命令设置为self.save。此函数将两个变量存储为storeNumbertldDate,然后将类变量设置为输入的内容并销毁根窗口。

    控制器.py

    ​​>
    import MainUI
    from tkinter import *
    
    root = Tk()
    
    ui = MainUI.LaunchMainUi(root)
    root.mainloop() #Keeps the ui instance running until closed, then the rest of the code is run
    
    storeNum = ui.store_number
    tldDate = ui.tld_date
    
    print('Store Number: {}\nTLD Date: {}'.format(storeNum, tldDate)) #This line is to show that the variables can be accessed
    

    因为我们销毁了根实例,所以返回了 mainloop() 函数,这意味着它下面的任何代码都将运行。只要 UI 是打开的,它下面的代码就不会运行。因此,当根窗口关闭时,它下面的代码会运行并保存两个变量以供以后使用。您应该在注释掉的地方添加一些错误检查代码。


    使用 .pack()

    我个人远离使用.grid(),因为它可能有点令人困惑。相反,我喜欢使用 .pack() 和 encapsulation. 如果您想改用 .pack(),这里还有另一个 __init__,它的工作原理是一样的。我还让__init__ 上的 GUI 看起来不那么标准,并带有一些 TacoBell 颜色:)

    def __init__(self, root):
        self.root = root
        self.root.title("TacoBell TLD Tool")
        self.root.geometry('600x300')
    
        font20 = 'Calibri 20'
        bfont20 = font20 + ' bold'
    
        Label(self.root, text='TacoBell TLD Tool', font=bfont20, fg='purple').pack()
    
        topItems = Frame(self.root)
        Label(topItems, text="Store Number (XXXXXX): ", font=font20).pack(side=LEFT)  # Sticky align text North(N), East(E), South(S), West(W)
        self.entStore = Entry(topItems, font=font20)
        self.entStore.pack(side=RIGHT)
        topItems.pack(pady=20)
    
        lowItems = Frame(self.root)
        Label(lowItems, text="TLD Date(MM/DD/YYYY): ", font=font20).pack(side=LEFT)
        self.entDate = Entry(lowItems, font=font20)
        self.entDate.pack(side=RIGHT)
        lowItems.pack(pady=20)
    
        self.confirm = Button(root, text="Confirm", bg='purple', fg='white', font=bfont20, width=30, command=self.save)
        self.confirm.pack()
    

    【讨论】:

      【解决方案2】:

      最好的方法是使用组件。使用 tkinter,您应该通过扩展 Frame 类来定义您的组件。所以你的代码应该是这样的:

      class StoreForm(tkinter.Frame):
          store_number = ''
          tld_date = ''
      
          def __init__(self, root, **kw):
              super().__init__(**kw)
              root.title("TacoBell TLD Tool")
              self.store_number = tkinter.IntVar()
              self.tld_date = tkinter.IntVar()
      
              self.lblstore_number = tkinter.Label(self, text="Store Number (XXXXXX): ")
              self.lbltld_date = tkinter.Label(self, text="TLD Date(MM/DD/YYYY): ")
      
              self.lblstore_number.grid(row=0, sticky=E)  # Sticky align text North(N), East(E), South(S), West(W0
              self.lbltld_date.grid(row=1, sticky=E)
      
              self.entStore = tkinter.Entry(self, textvariable=self.store_number)
              self.entDate = tkinter.Entry(self, textvariable=self.tld_date)
      
              self.entStore.grid(row=0, column=1)
              self.entDate.grid(row=1, column=1)
      

      请注意,root 参数不是您的根,而是此框架的预期容器。

      这样,您就有了一个独立的可重复使用的图形组件。这个组件管理视图逻辑(显示小部件,如果需要,它们之间的交互),但不是你的应用程序逻辑,这是你的控制器的工作。但是要使用该控制器,您应该能够从该组件获取数据和/或提供一些数据。为此,您应该添加方法。即使我使用相似的名称,我也不会称它们为 getter 和 setter……

          def get_data(self):
              return self.store_number.get(), self.tld_date.get()
      
          def set_data(self, store_number_value, tld_date_value):
              self.store_number.set(store_number_value)
              self.tld_date.set(tld_date_value)
      

      现在,在您的主模块中,您可以添加类似

      MAIN_UI = tkinter.Tk()
      form = StoreForm(MAIN_UI).pack()
      

      我让你选择这应该发生在模块的根目录还是类内部。这就是控制器应该在的地方。控制器是您的业务逻辑在图形组件之外的组件。

      使用框架让您:

      • 将 UI 逻辑与业务逻辑分开
      • 混合布局(表格框架中的网格,外部组件流)

      【讨论】:

        猜你喜欢
        • 2021-10-05
        • 2012-03-28
        • 2020-11-13
        • 2013-05-04
        • 2017-08-05
        • 1970-01-01
        • 2013-11-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多