简体   繁体   English

Frame中的tkinter背景图像

[英]tkinter background image in Frame

I want to put a background image in a Frame, this is the code that I'm trying to run without success.我想将背景图像放在框架中,这是我试图运行但没有成功的代码。

import tkinter as tk
from tkinter import *

root = tk.Tk()

F1 = Frame(root)
F1.grid(row=0)

photo = PhotoImage(file="sfondo.png")
label = Label(F1, image=photo)
label.image = photo
label.place(x=0, y=0)

b = tk.Button(label, text="Start")
b.grid(row=8, column=8)

root.mainloop()

If I run the code as this, only a little point in the top left corner is displayed (the frame without nothing in, even if I placed the label inside of it).如果我这样运行代码,则只显示左上角的一点(即使我在其中放置了标签,框架也没有任何内容)。 If I replace the label parent with root , it displays the button with a little part of the image as backgound (only the perimeter of the button is colored for a few pixels).如果我将标签 parent 替换为root ,它会显示带有图像的一小部分的按钮作为背景(只有按钮的周边被着色为几个像素)。 However what I want is a full displayed background image in the frame where I can put the widgets that I want.但是我想要的是在框架中完整显示的背景图像,我可以在其中放置我想要的小部件。

I tried to with the place method as this and PIL module我尝试使用 place 方法作为 this 和 PIL 模块

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

root = tk.Tk()

F1 = Frame(root)
F1.grid(row=0)
image = Image.open("sfondo.png")

render = ImageTk.PhotoImage(image)
img = tk.Label(F1, image=render)
img.image = render
img.place(x=0, y=40)

b = tk.Button(img, text="Start")
b.grid(row=8, column=8)

root.mainloop()

Here more or less I'm having the same problems, if I set the parent of the label to root , the button is displayed with the perimeter coloured.在这里或多或少我遇到了同样的问题,如果我将标签的父级设置为root ,则按钮显示为带有彩色的周边。 If I set the parent to F1 nothing happens and in both cases if I set the parent as root and remove the button, the image is fully displayed.如果我将父级设置为F1没有任何反应,并且在这两种情况下,如果我将父级设置为root并删除按钮,则图像将完全显示。 But what I want is that the image is fully displayed in the frame and after diplay on the background image the widgets.但我想要的是图像完全显示在框架中,然后在背景图像上显示小部件。

You could put an image on a Canvas , and then place a Button on that by putting it inside a Canvas window object which can hold any Tkinter widget.您可以将图像放在Canvas上,然后通过将其放在可以容纳任何 Tkinter 小部件的Canvas 窗口对象中来放置一个Button

Additional widgets can be added in a similar fashion, each inside its own Canvas window object (since they can hold only a single widget each).可以以类似的方式添加其他小部件,每个小部件都在其自己的Canvas窗口对象中(因为它们每个只能容纳一个小部件)。 You can workaround that limitation by placing a Frame widget in the Canvas window, and then putting other widgets inside it .您可以通过在Canvas窗口中放置一个Frame小部件,然后将其他小部件放入其中来解决该限制。

Here's an example showing how to display a single Button :这是一个显示如何显示单个Button的示例:

from PIL import Image, ImageTk
import tkinter as tk

IMAGE_PATH = 'sfondo.png'
WIDTH, HEIGTH = 200, 200

root = tk.Tk()
root.geometry('{}x{}'.format(WIDTH, HEIGHT))

canvas = tk.Canvas(root, width=WIDTH, height=HEIGTH)
canvas.pack()

img = ImageTk.PhotoImage(Image.open(IMAGE_PATH).resize((WIDTH, HEIGTH), Image.ANTIALIAS))
canvas.background = img  # Keep a reference in case this code is put in a function.
bg = canvas.create_image(0, 0, anchor=tk.NW, image=img)

# Put a tkinter widget on the canvas.
button = tk.Button(root, text="Start")
button_window = canvas.create_window(10, 10, anchor=tk.NW, window=button)

root.mainloop()

Screenshot:截屏:

示例代码运行截图

Edit编辑

While I don't know of a way to do it in Frame instead of a Canvas , you could derive your own Frame subclass to make adding multiple widgets easier.虽然我不知道在Frame而不是Canvas中执行此操作的方法,但您可以派生自己的Frame子类以更轻松地添加多个小部件。 Here's what I mean:这就是我的意思:

from PIL import Image, ImageTk
import tkinter as tk


class BkgrFrame(tk.Frame):
    def __init__(self, parent, file_path, width, height):
        super(BkgrFrame, self).__init__(parent, borderwidth=0, highlightthickness=0)

        self.canvas = tk.Canvas(self, width=width, height=height)
        self.canvas.pack()

        pil_img = Image.open(file_path)
        self.img = ImageTk.PhotoImage(pil_img.resize((width, height), Image.ANTIALIAS))
        self.bg = self.canvas.create_image(0, 0, anchor=tk.NW, image=self.img)

    def add(self, widget, x, y):
        canvas_window = self.canvas.create_window(x, y, anchor=tk.NW, window=widget)
        return widget


if __name__ == '__main__':

    IMAGE_PATH = 'sfondo.png'
    WIDTH, HEIGTH = 350, 200

    root = tk.Tk()
    root.geometry('{}x{}'.format(WIDTH, HEIGTH))

    bkrgframe = BkgrFrame(root, IMAGE_PATH, WIDTH, HEIGTH)
    bkrgframe.pack()

    # Put some tkinter widgets in the BkgrFrame.
    button1 = bkrgframe.add(tk.Button(root, text="Start"), 10, 10)
    button2 = bkrgframe.add(tk.Button(root, text="Continue"), 50, 10)

    root.mainloop()

Result:结果:

屏幕截图显示两个小部件显示在带背景的框架上

Update更新

It recently dawned on me that there actually is a simpler way to do this than creating a custom Frame subclass as shown in my previous edit above.我最近突然意识到,实际上一种比创建自定义Frame子类更简单的方法,如上面我之前的编辑所示。 The trick is to place() a Label with image on it in the center of the parent Frame — you are then free to use other geometry managers like pack() and grid() as you normally would — as illustrated in the sample code below.诀窍是在父Frame的中心place()一个带有图像的Label - 然后您可以像往常一样自由使用其他几何管理器,如pack()grid() - 如下面的示例代码所示. Not only is it less complicated, it's also a more "natural" way of adding widgets than needing to call a non-standard method such as add() .它不仅不那么复杂,而且它也是一种添加小部件的更“自然”的方式,而不是需要调用诸如add()之类的非标准方法。

from PIL import Image, ImageTk
import tkinter as tk


IMAGE_PATH = 'sfondo.png'
WIDTH, HEIGHT = 250, 150

root = tk.Tk()
root.geometry('{}x{}'.format(WIDTH, HEIGHT))

# Display image on a Label widget.
img = ImageTk.PhotoImage(Image.open(IMAGE_PATH).resize((WIDTH, HEIGHT), Image.ANTIALIAS))
lbl = tk.Label(root, image=img)
lbl.img = img  # Keep a reference in case this code put is in a function.
lbl.place(relx=0.5, rely=0.5, anchor='center')  # Place label in center of parent.

# Add other tkinter widgets.
button = tk.Button(root, text="Start")
button.grid(row=0, column=0)
button = tk.Button(root, text="Continue")
button.grid(row=0, column=1, padx=10)

root.mainloop()

Result#2结果#2

屏幕截图显示使用替代方法显示在具有背景的框架上的两个小部件

PS You can download a copy of the sfondo.png background image from here . PS你可以从这里下载sfondo.png背景图片的副本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM