将 Tkinter GUI 类 分离成更有意义的方式
Separate Tkinter GUI classes into more meaningful ways
我正在尝试使用继承使以下代码尽可能有意义。目的是为了学习。 Appclass最超级class。而 Tabs class 继承了它。我可以让下面的代码更有意义并打破它以获得更好的 classes 吗?我不能为所有 Tabs class 方法创建 notebook = self.notebook,而是在 Tab class 的 init 方法中初始化它。完成后笔记本无法识别。我需要所有选项卡的背景颜色都相同。因此,如果我可以在 Tabs class 的 init 方法中提及它并将其其他方法(关于,...,可视化)转换为 Tabs class 的子 classes,将这是个好建议吗?请帮忙
import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk
from tkinter.filedialog import askopenfile
from tkinter.font import Font
class App(tk.Tk):
def __init__(self):
super().__init__()
# intializing the window
self.title("Data Visualization")
# configuring size of the window
self.geometry('800x650')
# this removes the maximize button
self.resizable(0,0)
# Styling the tabs
s = ttk.Style()
s.theme_create('pastel', settings={
".": {
"configure": {
"background": '#ffffff', # All except tabs
"font": 'red'
}
},
"TNotebook": {
"configure": {
"background":'#848a98', # Your margin color
"tabmargins": [5, 5, 4, 4], # margins: left, top, right, separator
}
},
"TNotebook.Tab": {
"configure": {
"background": '#d9ffcc', # tab color when not selected
"padding": [10, 2], # [space between text and horizontal tab-button border, space between text and vertical tab_button border]
"font":"white"
},
"map": {
"background": [("selected", '#ccffff')], # Tab color when selected
"expand": [("selected", [1, 1, 1, 0])] # text margins
}
}
})
s.theme_use('pastel')
#s.theme_use('default')
s.configure('TNotebook.Tab', font=('URW Gothic L','13','bold'))
#s.map("TNotebook", background= [("selected", "#ffffff")])
#Create Tab Control
self.notebook = ttk.Notebook(self)
class Tabs(App):
def __init__(self):
super().__init__()
def about(self):
my_font = Font(
family = 'Arial',
size = 15,
weight = 'bold',
slant = 'roman',
underline = 0,
overstrike = 0
)
my_font2 = Font(
family = 'Arial',
size = 11,
#weight = 'bold',
slant = 'roman',
underline = 0,
overstrike = 0
)
notebook = self.notebook
f1 = tk.Frame(notebook)#,background="#FFFAF0")
#logo
logo = Image.open('airport.jpg')
#Resize the Image using resize method
resized_image= logo.resize((600,300), Image.ANTIALIAS)
logo = ImageTk.PhotoImage(resized_image)
logo_label = ttk.Label(f1,image=logo,relief="raised")
logo_label.image = logo
#logo_label.grid(column=3, row=0)
logo_label.place(relx=0.12,rely=0.1) # using place
notebook.add(f1, text="About" )
# Tab1
ttk.Label(f1, text="Airports, Airport-frequencies and Runways analysis", font=my_font).place(relx=0.2,rely=0.03)
#text box
text_box = tk.Text(f1, height =10,font=my_font2)
text_box.insert(1.0,"""This application allows you to analyze Airports, Airport-frequencies and Runways of Europe.
• Tab "Load and Save Actions" is to load the initial data set (which consists of three CSV files) and translate it into a suitable format. \n\n• Tab "Preprocess" is to clean and prepare the initial data set, managing inconsistences, \nerrors, missing values and any specific changes required. \n\n• Tab "Visualize" is to use the prepared data set to generate output and visualisations.""" )
text_box.tag_configure("center", justify="center")
text_box.tag_add("center", 1.0, "end")
text_box.place(relx=0.1, rely=0.65)
text_box.config(highlightthickness = 2, borderwidth=0,background='#FFFAFA')
notebook.pack(expand=1, fill="both")
def load_save(self):
notebook = self.notebook
f2 = tk.Frame(notebook,background="#ffffff")
notebook.add(f2, text="Load and Save Actions" )
def preprocess(self):
notebook = self.notebook
f3 = tk.Frame(notebook,background="#ffffff")
notebook.add(f3, text="Preprocess" )
def visualize(self):
notebook = self.notebook
f4 = tk.Frame(notebook,background="#ffffff")
notebook.add(f4, text="Visualize" )
if __name__ == "__main__":
tabs=Tabs()
tabs.about()
tabs.load_save()
tabs.preprocess()
tabs.visualize()
tabs.mainloop()
在您的示例中,Tabs
应该而不是 继承自 App
。继承是一种是一种关系。如果Tabs
继承自App
,那就意味着Tabs
是App
。意思是,你现在有两个 Apps
:原始版本加上一个特殊版本。
这对于 tkinter 来说尤其成问题。 Tkinter 被设计为只有一个 Tk
实例,但你有一个 App
实例(因为 App
是一个 Tk
) Tab
的每个实例加一。这将导致不直观且通常不可取的行为。
继承不是为了在对象之间共享数据。如果 Tabs
需要访问 App
中的数据或函数,它应该通过调用函数或从 App
实例本身访问数据来实现。
更好的结构是为选项卡创建自定义 class,然后创建该选项卡的实例 class,而不是使用创建选项卡的函数。
这是一个示例,其中 app
的实例被传递到每个选项卡。然后选项卡可以使用 self.app
调用函数或访问 App
中的变量。 Tab
class 将使用一些常用选项在 app.notebook
中创建一个框架。
通过使每个选项卡成为一个 class,它为您提供了一种方便的方法来封装每个选项卡特定的功能和数据。
import tkinter as tk
from tkinter import ttk
class App(tk.Tk):
def __init__(self):
super().__init__()
...
self.notebook = ttk.Notebook(self)
self.notebook.pack(fill="both", expand=True)
self.about_tab = AboutTab(app=self)
self.load_save = LoadSaveTab(app=self)
class Tab(tk.Frame):
def __init__(self, app, label):
# given an app, make this a child of app.notebook
self.app = app
super().__init__(app.notebook, background="#FFFAF0")
self.app.notebook.add(self, text=label)
class AboutTab(Tab):
def __init__(self, app):
super().__init__(app, "About")
label = tk.Label(self, text="This is the 'About' tab")
label.pack(fill="both")
...
class LoadSaveTab(Tab):
def __init__(self, app):
super().__init__(app, "Load and Save")
label = tk.Label(self, text="This is the 'Load and Save' tab")
label.pack(fill="both")
...
if __name__ == "__main__":
app = App()
app.mainloop()
我正在尝试使用继承使以下代码尽可能有意义。目的是为了学习。 Appclass最超级class。而 Tabs class 继承了它。我可以让下面的代码更有意义并打破它以获得更好的 classes 吗?我不能为所有 Tabs class 方法创建 notebook = self.notebook,而是在 Tab class 的 init 方法中初始化它。完成后笔记本无法识别。我需要所有选项卡的背景颜色都相同。因此,如果我可以在 Tabs class 的 init 方法中提及它并将其其他方法(关于,...,可视化)转换为 Tabs class 的子 classes,将这是个好建议吗?请帮忙
import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk
from tkinter.filedialog import askopenfile
from tkinter.font import Font
class App(tk.Tk):
def __init__(self):
super().__init__()
# intializing the window
self.title("Data Visualization")
# configuring size of the window
self.geometry('800x650')
# this removes the maximize button
self.resizable(0,0)
# Styling the tabs
s = ttk.Style()
s.theme_create('pastel', settings={
".": {
"configure": {
"background": '#ffffff', # All except tabs
"font": 'red'
}
},
"TNotebook": {
"configure": {
"background":'#848a98', # Your margin color
"tabmargins": [5, 5, 4, 4], # margins: left, top, right, separator
}
},
"TNotebook.Tab": {
"configure": {
"background": '#d9ffcc', # tab color when not selected
"padding": [10, 2], # [space between text and horizontal tab-button border, space between text and vertical tab_button border]
"font":"white"
},
"map": {
"background": [("selected", '#ccffff')], # Tab color when selected
"expand": [("selected", [1, 1, 1, 0])] # text margins
}
}
})
s.theme_use('pastel')
#s.theme_use('default')
s.configure('TNotebook.Tab', font=('URW Gothic L','13','bold'))
#s.map("TNotebook", background= [("selected", "#ffffff")])
#Create Tab Control
self.notebook = ttk.Notebook(self)
class Tabs(App):
def __init__(self):
super().__init__()
def about(self):
my_font = Font(
family = 'Arial',
size = 15,
weight = 'bold',
slant = 'roman',
underline = 0,
overstrike = 0
)
my_font2 = Font(
family = 'Arial',
size = 11,
#weight = 'bold',
slant = 'roman',
underline = 0,
overstrike = 0
)
notebook = self.notebook
f1 = tk.Frame(notebook)#,background="#FFFAF0")
#logo
logo = Image.open('airport.jpg')
#Resize the Image using resize method
resized_image= logo.resize((600,300), Image.ANTIALIAS)
logo = ImageTk.PhotoImage(resized_image)
logo_label = ttk.Label(f1,image=logo,relief="raised")
logo_label.image = logo
#logo_label.grid(column=3, row=0)
logo_label.place(relx=0.12,rely=0.1) # using place
notebook.add(f1, text="About" )
# Tab1
ttk.Label(f1, text="Airports, Airport-frequencies and Runways analysis", font=my_font).place(relx=0.2,rely=0.03)
#text box
text_box = tk.Text(f1, height =10,font=my_font2)
text_box.insert(1.0,"""This application allows you to analyze Airports, Airport-frequencies and Runways of Europe.
• Tab "Load and Save Actions" is to load the initial data set (which consists of three CSV files) and translate it into a suitable format. \n\n• Tab "Preprocess" is to clean and prepare the initial data set, managing inconsistences, \nerrors, missing values and any specific changes required. \n\n• Tab "Visualize" is to use the prepared data set to generate output and visualisations.""" )
text_box.tag_configure("center", justify="center")
text_box.tag_add("center", 1.0, "end")
text_box.place(relx=0.1, rely=0.65)
text_box.config(highlightthickness = 2, borderwidth=0,background='#FFFAFA')
notebook.pack(expand=1, fill="both")
def load_save(self):
notebook = self.notebook
f2 = tk.Frame(notebook,background="#ffffff")
notebook.add(f2, text="Load and Save Actions" )
def preprocess(self):
notebook = self.notebook
f3 = tk.Frame(notebook,background="#ffffff")
notebook.add(f3, text="Preprocess" )
def visualize(self):
notebook = self.notebook
f4 = tk.Frame(notebook,background="#ffffff")
notebook.add(f4, text="Visualize" )
if __name__ == "__main__":
tabs=Tabs()
tabs.about()
tabs.load_save()
tabs.preprocess()
tabs.visualize()
tabs.mainloop()
在您的示例中,Tabs
应该而不是 继承自 App
。继承是一种是一种关系。如果Tabs
继承自App
,那就意味着Tabs
是App
。意思是,你现在有两个 Apps
:原始版本加上一个特殊版本。
这对于 tkinter 来说尤其成问题。 Tkinter 被设计为只有一个 Tk
实例,但你有一个 App
实例(因为 App
是一个 Tk
) Tab
的每个实例加一。这将导致不直观且通常不可取的行为。
继承不是为了在对象之间共享数据。如果 Tabs
需要访问 App
中的数据或函数,它应该通过调用函数或从 App
实例本身访问数据来实现。
更好的结构是为选项卡创建自定义 class,然后创建该选项卡的实例 class,而不是使用创建选项卡的函数。
这是一个示例,其中 app
的实例被传递到每个选项卡。然后选项卡可以使用 self.app
调用函数或访问 App
中的变量。 Tab
class 将使用一些常用选项在 app.notebook
中创建一个框架。
通过使每个选项卡成为一个 class,它为您提供了一种方便的方法来封装每个选项卡特定的功能和数据。
import tkinter as tk
from tkinter import ttk
class App(tk.Tk):
def __init__(self):
super().__init__()
...
self.notebook = ttk.Notebook(self)
self.notebook.pack(fill="both", expand=True)
self.about_tab = AboutTab(app=self)
self.load_save = LoadSaveTab(app=self)
class Tab(tk.Frame):
def __init__(self, app, label):
# given an app, make this a child of app.notebook
self.app = app
super().__init__(app.notebook, background="#FFFAF0")
self.app.notebook.add(self, text=label)
class AboutTab(Tab):
def __init__(self, app):
super().__init__(app, "About")
label = tk.Label(self, text="This is the 'About' tab")
label.pack(fill="both")
...
class LoadSaveTab(Tab):
def __init__(self, app):
super().__init__(app, "Load and Save")
label = tk.Label(self, text="This is the 'Load and Save' tab")
label.pack(fill="both")
...
if __name__ == "__main__":
app = App()
app.mainloop()