【问题标题】:Resizing Tkinter Frames with fixed aspect-ratio使用固定纵横比调整 Tkinter 帧的大小
【发布时间】:2013-05-07 13:12:41
【问题描述】:

我正在寻找一种方法来让 Tkinter 帧在调整大小时表现得有点像这样:

from Tkinter import *
w = Tk()
w.aspect(1,1,1,1)
w.mainloop()

所以我想要这段代码:

import Tkinter as tk
from Tkconstants import *
r=tk.Tk()
content_frame=tk.Frame(r,borderwidth=5,relief=GROOVE)
content_frame.grid(row=0,column=0,sticky=(N,S,E,W))
tk.Label(content_frame,text='content').pack()
pad_frame=tk.Frame(r,borderwidth=5,relief=GROOVE)
pad_frame.grid(row=1,column=0,sticky=(N,S,E,W))
tk.Label(pad_frame,text='-pad-').pack()
r.rowconfigure(0, weight=1)
r.rowconfigure(1, weight=1)
r.columnconfigure(0, weight=1)
r.mainloop()

它基本上创建了 2 个框架,一个应该包含一些内容(在我的应用程序中,这个框架包含一个可以调整大小的 mathplotlib 图形),一个只是用于填充。

按照以下规则调整大小:

  • 内容框架以固定的纵横比调整大小(假设它始终需要是方形的)
  • pad 框架占用剩余的(垂直)空间

有什么想法吗?我已经阅读手册有一段时间了,似乎找不到合适的东西。

-丹尼尔

【问题讨论】:

  • 你为什么不删除填充,只使用aspect
  • 这是我实际要做的简化案例。整个东西嵌入到更大的界面中,所以我不能使用windows/toplevel/...而且Frame没有.aspect()方法。

标签: python resize tkinter frame aspect-ratio


【解决方案1】:

至少有几种方法可以解决这个问题。最简单的 IMO 是让您的填充小部件成为内容小部件的容器,然后使用 place 显式设置内容小部件的宽度和高度。这是place 优于gridpack 的边缘情况之一。

在以下示例中,我创建了一个函数,可让您传入内容框架、填充框架和纵横比。然后它通过纵横比和容器的大小来限制内容框架的大小。它将使内容窗口在 X 维度上填充容器,然后适当地设置高度。如果生成的窗口太高而无法看到,它会将最大高度设置为容器的高度并改为调整宽度。

我试图保持问题中的大部分代码完整无缺,尽管这并不是我通常选择的编码方式。我为小部件指定了不同的颜色,以便更容易看到正在发生的事情。

import Tkinter as tk
from Tkconstants import *
r=tk.Tk()

def set_aspect(content_frame, pad_frame, aspect_ratio):
    # a function which places a frame within a containing frame, and
    # then forces the inner frame to keep a specific aspect ratio

    def enforce_aspect_ratio(event):
        # when the pad window resizes, fit the content into it,
        # either by fixing the width or the height and then
        # adjusting the height or width based on the aspect ratio.

        # start by using the width as the controlling dimension
        desired_width = event.width
        desired_height = int(event.width / aspect_ratio)

        # if the window is too tall to fit, use the height as
        # the controlling dimension
        if desired_height > event.height:
            desired_height = event.height
            desired_width = int(event.height * aspect_ratio)

        # place the window, giving it an explicit size
        content_frame.place(in_=pad_frame, x=0, y=0, 
            width=desired_width, height=desired_height)

    pad_frame.bind("<Configure>", enforce_aspect_ratio)

pad_frame = tk.Frame(borderwidth=0, background="bisque", width=200, height=200)
pad_frame.grid(row=0, column=0, sticky="nsew", padx=10, pady=20)
content_frame=tk.Frame(r,borderwidth=5,relief=GROOVE, background="blue")
tk.Label(content_frame,text='content').pack()
set_aspect(content_frame, pad_frame, aspect_ratio=2.0/1.0) 
r.rowconfigure(0, weight=1)
r.columnconfigure(0, weight=1)

r.mainloop()

如果包含小部件的内容可以轻松调整到容器的大小,这将最有效。如果其中有复杂的小部件布局,当窗口缩小到其自然大小以下时,如果某些小部件不适合,它们可能会被切掉。

【讨论】:

  • 像魅力一样工作。非常有用,谢谢。如果我在 Tkinter 的 GUI 编程方面有更多经验,我可能也会做不同的事情,但我对整个事情还很陌生。再次感谢您提供出色的代码。
【解决方案2】:

您可以将函数绑定到&lt;Configure&gt; 事件,以获取包含内容和填充帧的Frame&lt;Configure&gt; 事件将在您调整窗口大小时触发。通过使用rowconfigurecolumnconfigure 更新行和列的权重,使用事件的宽度和高度属性来固定内容框架的大小

您需要在容器框架中有两行两列才能拥有一个方形内容框架。对于高窗户,您需要在第二行进行填充。对于宽窗口,您需要在第二列中进行填充。

一个工作示例:

import Tkinter as tk
from Tkconstants import *


class Application(tk.Frame):
    def __init__(self, master, width, height):
        tk.Frame.__init__(self, master)
        self.grid(sticky=N + S + E + W)
        master.rowconfigure(0, weight=1)
        master.columnconfigure(0, weight=1)
        self._create_widgets()
        self.bind('<Configure>', self._resize)
        self.winfo_toplevel().minsize(150, 150)

    def _create_widgets(self):
        self.content = tk.Frame(self, bg='blue')
        self.content.grid(row=0, column=0, sticky=N + S + E + W)

        self.rowconfigure(0, weight=1)
        self.rowconfigure(1, weight=1)
        self.columnconfigure(0, weight=1)
        self.columnconfigure(1, weight=1)

    def _resize(self, event):
        '''Modify padding when window is resized.'''
        w, h = event.width, event.height
        w1, h1 = self.content.winfo_width(), self.content.winfo_height()
        print w1, h1  # should be equal
        if w > h:
            self.rowconfigure(0, weight=1)
            self.rowconfigure(1, weight=0)
            self.columnconfigure(0, weight=h)
            self.columnconfigure(1, weight=w - h)
        elif w < h:
            self.rowconfigure(0, weight=w)
            self.rowconfigure(1, weight=h - w)
            self.columnconfigure(0, weight=1)
            self.columnconfigure(1, weight=0)
        else:
            # width = height
            self.rowconfigure(0, weight=1)
            self.rowconfigure(1, weight=0)
            self.rowconfigure(0, weight=1)
            self.columnconfigure(1, weight=0)

root = tk.Tk()
app = Application(master=root, width=100, height=100)
app.mainloop()

【讨论】:

  • 也可以完美运行。也会接受你的回答,但我只能接受一个......对不起。不过,非常感谢。
  • 谢谢,Bryan 的回答好多了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-14
  • 2012-05-26
  • 1970-01-01
  • 2014-06-15
  • 2011-02-10
  • 2017-08-10
  • 2023-03-04
相关资源
最近更新 更多