带类的Python Tkinter

时间:2018-08-15 23:03:50

标签: python python-3.x oop tkinter

尝试开发用于工作的应用程序,我想将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()

2 个答案:

答案 0 :(得分: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

Controller.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()函数,这意味着它下面的任何代码都将运行。只要用户界面处于打开状态,它下面的代码就不会运行。因此,当关闭根窗口时,将运行其下面的代码,并保存两个变量供以后使用。您应该在注释掉的地方添加一些错误检查代码。


使用.pack()

我个人不使用.grid(),因为这样做可能会造成一些混乱。相反,我喜欢使用.pack()和封装。enter image description here如果您想使用.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()

答案 1 :(得分:0)

最好的方法是使用组件。使用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逻辑与业务逻辑分开
  • 混合布局(表格框架中的网格,外部包装以进行组件流动)