如何让 Tkinter windows 中的元素填充框架?

How can I get elements in Tkinter windows to fill the frame?

我是 Python 使用 Tkinter 进行 GUI 开发的新手。 我正在尝试使应用程序 window 具有一定的大小,并且我希望 window 中的网络摄像头视图能够填充主 window.

的大小

当我设置 window 大小时,网络摄像头没有填满整个 window。

自定义window大小时如何让元素填满整个window?

这是我的代码:

import tkinter as tk
from PIL import Image, ImageTk
import cv2

class MainWindow():
    def __init__(self, window, cap):
        self.window = window
        self.cap = cap
        self.width = self.cap.get(cv2.CAP_PROP_FRAME_WIDTH)
        self.height = self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
        self.interval = 20 # Interval in ms to get the latest frame

        # Create canvas for image
        self.canvas = tk.Canvas(self.window, width=self.width, height=self.height)
        self.canvas.grid(row=0, column=0)
        self.canvas.pack(fill="both", expand=True)

        # Update image on canvas
        self.update_image()

    def update_image(self):
        # Get the latest frame and convert image format
        self.image = cv2.cvtColor(self.cap.read()[1], cv2.COLOR_BGR2RGB) # to RGB
        self.image = Image.fromarray(self.image) # to PIL format
        self.image = ImageTk.PhotoImage(self.image) # to ImageTk format

        # Update image
        self.canvas.create_image(0, 0, anchor=tk.NW, image=self.image)

        # Repeat every 'interval' ms
        self.window.after(self.interval, self.update_image)

if __name__ == "__main__":
    root = tk.Tk()
    root.geometry('600x800')
    # root.resizable(width=0, height=0)
    MainWindow(root, cv2.VideoCapture(0))

    root.mainloop()

谢谢。

您所要做的就是调整图像大小以适合 canvas 尺寸。您可以使用 cv2.resize()Image.resize() 来调整图像大小。

要获得当前 canvas 大小,请使用 canvas.winfo_height()canvas.wifo_width()。除此之外,您还应该考虑使用 canvas.itemconfig(tag_id) 更新现有图像,而不是每次都创建一个新图像。

示例代码(我将使用标签而不是 canvas 来显示图像):

import tkinter as tk
from PIL import Image, ImageTk
import cv2

class MainWindow():
    def __init__(self, window, cap):
        self.window = window
        self.cap = cap

        self.interval = 20 # Interval in ms to get the latest frame
        # Create canvas for image
        self.vid_lbl = tk.Label(self.window)
        self.vid_lbl.pack(fill="both", expand=True)

        # Update image on canvas
        self.update_image()

    def update_image(self):
        # Get the latest frame and convert image format

        width, height = self.vid_lbl.winfo_width(), self.vid_lbl.winfo_height()

        self.image = cv2.cvtColor(self.cap.read()[1], cv2.COLOR_BGR2RGB) # to RGB
        self.image = cv2.resize(self.image, (width, height), cv2.INTER_AREA)
        self.image = Image.fromarray(self.image) # to PIL format
        #self.image = self.image.resize((width, height))

        self.image = ImageTk.PhotoImage(self.image) # to ImageTk format
        self.vid_lbl.config(image=self.image)

        # Repeat every 'interval' ms
        self.window.after(self.interval, self.update_image)

if __name__ == "__main__":
    root = tk.Tk()
    root.geometry('600x800')
    # root.resizable(width=0, height=0)
    MainWindow(root, cv2.VideoCapture(0))

    root.mainloop()