如何在Python的customtkinter中对CTkFrame内的图像应用自定义圆角半径?

1 投票
1 回答
60 浏览
提问于 2025-04-14 15:29

我现在在做一个Python项目,使用的是customtkinter库,但遇到了一个问题:我想给一个放在CTkFrame里的图片加上圆角,但没成功。下面是我代码的一个简单示例:

import customtkinter
from PIL import Image

image_path = #image path

class App(customtkinter.CTk):
    def __init__(self):
        super().__init__()

        frame = customtkinter.CTkFrame(self, width=200, height=111, corner_radius=5)
        frame.pack()

        image = customtkinter.CTkImage(Image.open(image_path), size=(200, 111))

        image_label = customtkinter.CTkLabel(frame, image=image, text="")
        image_label.pack()

if __name__ == "__main__":
    app = App()
    app.mainloop() 

在这段代码中,我试图在CTkFrame里显示一张图片,并给它设置圆角。但是,图片并没有跟随父框架的圆角,反而是尖尖的角。

我尝试用画布来给图片加上圆角遮罩,但这样做出来的圆角分辨率很低,而且有时候圆角和背景不太匹配。

请问我该如何正确地给CTkFrame里的图片加上自定义的圆角呢?

如果有任何建议或其他方法,我会非常感激。谢谢!

1 个回答

0

我在StackOverflow上浏览时发现了这个帖子:如何使用PIL让logo的角变圆,而不在它上面留下白色背景(透明的?)

这让我想起了我四天前评论过的你的问题,我当时说在customtkinter中不可能让角变圆,所以我来这里纠正一下自己。

其实,使用PIL.ImageDraw.Draw.ellipse()是可以做到的,下面是代码:

from PIL import Image, ImageDraw

def add_corners(im, rad):
    circle = Image.new('L', (rad * 2, rad * 2), 0)
    draw = ImageDraw.Draw(circle)
    draw.ellipse((0, 0, rad * 2 - 1, rad * 2 - 1), fill=255)
    alpha = Image.new('L', im.size, 255)
    w, h = im.size
    alpha.paste(circle.crop((0, 0, rad, rad)), (0, 0))
    alpha.paste(circle.crop((0, rad, rad, rad * 2)), (0, h - rad))
    alpha.paste(circle.crop((rad, 0, rad * 2, rad)), (w - rad, 0))
    alpha.paste(circle.crop((rad, rad, rad * 2, rad * 2)), (w - rad, h - rad))
    im.putalpha(alpha)
    return im

在你的情况下,完整的代码是:

import customtkinter
from PIL import Image, ImageDraw

image_path = #image path


def add_corners(im, rad):
    circle = Image.new('L', (rad * 2, rad * 2), 0)
    draw = ImageDraw.Draw(circle)
    draw.ellipse((0, 0, rad * 2 - 1, rad * 2 - 1), fill=255)
    alpha = Image.new('L', im.size, 255)
    w, h = im.size
    alpha.paste(circle.crop((0, 0, rad, rad)), (0, 0))
    alpha.paste(circle.crop((0, rad, rad, rad * 2)), (0, h - rad))
    alpha.paste(circle.crop((rad, 0, rad * 2, rad)), (w - rad, 0))
    alpha.paste(circle.crop((rad, rad, rad * 2, rad * 2)), (w - rad, h - rad))
    im.putalpha(alpha)
    return im


class App(customtkinter.CTk):
    def __init__(self):
        super().__init__()

        frame = customtkinter.CTkFrame(self, width=200, height=111, corner_radius=5)
        frame.pack()

        image = customtkinter.CTkImage(add_corners(Image.open(image_path), 100), size=(200, 111))

        image_label = customtkinter.CTkLabel(frame, image=image, text="")
        image_label.pack()


if __name__ == "__main__":
    app = App()
    app.mainloop()

不过,如果你想要透明背景,这个方法只适用于.png格式的图片(就像上面链接的帖子中提到的那样)。

如果你还有其他问题,可以参考上面的帖子:那里已经有解决方案了。

希望我能帮到你,祝你有个愉快的一天。

补充:因为我觉得让角变圆很有用,我创建了一个模块,里面有一个类来自动化这个功能,这个模块叫做MoreCustomTkinterWidgets,可以在Pypi上找到。

撰写回答