在小部件创建中继承子框架自动调整大小(tkinter,python 3)

Inherit subframes in widget creation auto sizing (tkinter, python 3)

我想做的是:

  1. 分别创建一个主框架(pc_gui)和两个子框架(video_frame)和(side_frame)
  2. 允许用户能够调整应用程序的大小 window 以适应所有框架、小部件、图像等相应地调整大小。
  3. GUI 中其他地方的参考框架。

为了保持整洁,可能会出错,我有一个应用程序 class,以及函数:init、app_size、create_frames、create_widgets , 和一个更新函数。还有很多,但如果我能让这个核心部分正常工作,我应该能够继续取得进步。

这从相对标准的 tkinter UI 初始化开始,其中包括应用程序的起始大小 window。

# Initialize Application Window
pc_gui = tk.Tk()
pc_gui.geometry("1280x720")

# Initialize Updater Variables
UPDATE_RATE = 1000

# Run application
app = Application(pc_gui)
pc_gui.mainloop()

然后创建 class 主框架 (pc_gui),然后调用各种子框架、应用程序大小和图像函数。

class Application(tk.Frame):
        """ GUI """
        def __init__(self, pc_gui):
                """ Initialize the frame """
                tk.Frame.__init__(self, pc_gui)
                self.app_size()
                self.grid()
                self.create_frames()
                self.create_images()
                self.updater()

这是app_size函数。它的目的是解析应用程序的当前大小 window 和显示监视器假设用户将更改这些以适应程序 运行.

    def app_size(self):
            pc_gui.update_idletasks() # Get Current Application Values
            app_width  = pc_gui.winfo_width() # Current Application Width
            app_height = pc_gui.winfo_height() # Current Application Height
            disp_width  = pc_gui.winfo_screenwidth() # Monitor (Screen) Width
            disp_height = pc_gui.winfo_screenheight() # Monitor (Screen) Height
            return app_width, app_height, disp_width, disp_height

然后我使用 app_size 值创建子帧。这些颜色只是为了帮助我在开发过程中跟踪事物。

   def create_frames(self):
            """ Create Frames """
            app_size = self.app_size() # Get size wxh of application window and display
            app_width = app_size[0]
            app_height = app_size[1]
            disp_width = app_size[2]
            disp_height = app_size[3]
            geometry = "%dx%d" % (app_width, app_height) # Create text value for geometry
            pc_gui.geometry(geometry) # Set Application Window Size

            # Section of Application window dedicated to source video
            video_frame = tk.Frame(
                    master = pc_gui,
                    width = app_width*.75,
                    height = app_height,
                    bg = "blue"
            )
            video_frame.place(
                    x = 0,
                    y = 0
            )

            # Section of Application window dedicated to calculations
            side_frame = tk.Frame(
                    master = pc_gui,
                    width = app_width*.25,
                    height = app_height,
                    bg = "red"
            )
            side_frame.place(
                    x = app_width*.75,
                    y = 0
            )

            pc_gui.update_idletasks()
            sf_x = side_frame.winfo_x()
            sf_y = side_frame.winfo_y()
            sf_w = side_frame.winfo_width()
            sf_h = side_frame.winfo_height()

            return sf_x, sf_y, sf_w, sf_h

    def updater(self):
            #self.create_frames() # Update Application Window
            self.create_images() # Update Images Widget
            self.after(UPDATE_RATE, self.updater) # Call "updater" function after 1 second

然后我开始创建小部件。对于图像(标签)小部件,我想使用网格,但我很难弄清楚如何在 create_images 函数中引用子框架 (side_frame)。我截断了重要的部分以使这个问题更切题。

   def create_images(self):

            sf_dims = self.create_frames()
            sf_x = sf_dims[0]
            sf_y = sf_dims[1]
            sf_w = sf_dims[2]
            sf_h = sf_dims[3]

...

            fp1_lbl = tk.Label(
                    master = pc_gui,
                    image = fp1
            )
            fp1_lbl.image = fp1
            fp1_lbl.place(
                    x=sf_x + img_padding,
                    y=sf_y + 20,
                    anchor='nw'
            )

诚然,到目前为止,一切都“有效”,但效率很低。我想做的是不让那些 sf_x、_y、_w 和 _h 挂在风中,因此我也不必从小部件函数调用 frame 函数来获取它们.

原因是我觉得它不符合 python 框架的正确精神,因为我只想在侧框架上使用网格,而是从小部件功能创建(或使用)网格(重点首先创建 side_frame),我宁愿只刷新应用程序 window 需要刷新的子部分,而不是每 1 秒刷新一次。

最终发生的是图像每 1 秒闪烁一次,即使没有任何内容需要更新并且图像会根据应用程序调整大小 window 我正在使用 Place 功能执行此操作并有效地忽略side_frame.

的存在

我目前的尝试围绕以下

        fp1_lbl = tk.Label(
                master = self.side_frame,
                image = fp1
        )
        fp1_lbl.image = fp1
        fp1_lbl.place(
                x=sf_x + img_padding,
                y=sf_y + 20,
                anchor='nw'
        )

我得到以下错误的版本:

AttributeError: 'Application' object has no attribute 'side_frame'

您需要使用“self”前缀来命名事物,以便在其他方法中使用它们。因此,当您创建子帧时:

        # Section of Application window dedicated to calculations
        self.side_frame = tk.Frame(
                master = pc_gui,
                width = app_width*.25,
                height = app_height,
                bg = "red"
        )
        self.side_frame.place(
                x = app_width*.75,
                y = 0
        )

现在您可以在 class 中的任何地方使用它们,正如您已经尝试过的那样:

    fp1_lbl = tk.Label(
            master = self.side_frame,
            image = fp1
    )

请记住,名为 fooself.foo 的变量之间没有隐含关系。他们是两个完全不相关的名字。


至于调整大小,tkinter 会为您完成。您可以使用 relwidth 和 relheight 参数将宽度和高度设置为 0 和 1 之间的分数。这是一个演示:

import tkinter as tk

class Application(tk.Frame):
    """ GUI """
    def __init__(self, pc_gui):
        """ Initialize the frame """
        tk.Frame.__init__(self, pc_gui)
        self.create_frames()

    def create_frames(self):
        # insert the subframes in *this* Frame (self), not in the master Frame
        self.video_frame = tk.Frame(self, bg = "blue")
        self.video_frame.place(relheight=1.0, relwidth=.25)

        self.side_frame = tk.Frame(self, bg = "red")
        self.side_frame.place(relheight=1.0, relwidth=.75, relx=1.0, anchor='ne')

pc_gui = tk.Tk()
pc_gui.geometry("1280x720")
win = Application(pc_gui)
win.pack(fill=tk.BOTH, expand=True)
tk.Button(pc_gui, text = "Don't click me!").pack()
pc_gui.mainloop()