如何使tkinter窗口变为圆角?

3

我正在尝试使一个使用tkinter的overrideredirect窗口呈圆形。

目前为止,我已经完成了以下步骤:

from tkinter import Tk, Canvas, BOTH, PhotoImage
from tkinter.constants import NW, RAISED
import pyautogui as pg

root = Tk()
root.overrideredirect(1)
root.attributes("-topmost", 1)
root.geometry("500x500")

# Creating a canvas for placing the squircle shape.
canvas = Canvas(root, height=500, width=500, highlightthickness=0)
canvas.pack()

def place_center(): # Placing the window in the center of the screen
    global x, y
    reso = pg.size()
    rx = reso[0]
    ry = reso[1]
    x = int((rx/2) - (500/2))
    y = int((ry/2) - (500/2))
    root.geometry(f"500x500+{x}+{y}")

def round_rectangle(x1, y1, x2, y2, radius=25, **kwargs): # Creating a rounded rectangle
        
        points = [x1+radius, y1,
                x1+radius, y1,
                x2-radius, y1,
                x2-radius, y1,
                x2, y1,
                x2, y1+radius,
                x2, y1+radius,
                x2, y2-radius,
                x2, y2-radius,
                x2, y2,
                x2-radius, y2,
                x2-radius, y2,
                x1+radius, y2,
                x1+radius, y2,
                x1, y2,
                x1, y2-radius,
                x1, y2-radius,
                x1, y1+radius,
                x1, y1+radius,
                x1, y1]

        return canvas.create_polygon(points, **kwargs, smooth=True)

place_center()

# Taking a screenshot and adding it to the canvas to create a transparent effect
root.withdraw()
s = pg.screenshot(region=(x, y, 500, 500))
tp = "C:\\Users\\username\\AppData\\Local\\Temp\\bg.png"
s.save(tp)
bg = PhotoImage(file=tp)
canvas.create_image(0, 0, image=bg, anchor=NW)
root.deiconify()
os.remove(tp)

# Creating the squircle
round_rectangle(0, 0, 500, 500, radius=70, fill="#1fa5fe")

root.mainloop()

我使用这个函数来移动窗口:

def move(event):
    fx = root.winfo_pointerx() - 250
    fy = root.winfo_pointery() - 10
    root.geometry(f"500x500{fx}+{fy}")

我没有在代码中添加它,因为当我移动窗口时,截图仅针对特定区域,所以它会再次变成方形。
移动前:移动前的圆形窗口 移动后:移动后的方形窗口 我该如何使其即使在移动时也保持圆形?
我尝试在 while True: 循环中使用 root.withdraw()root.deiconify(),但这会导致闪烁。
谢谢帮助。

2
root = Tk() 之后,加入 root.config(bg='grey15')root.attributes('-transparentcolor', 'grey15'),同时将画布的背景颜色也设置为相同的颜色。 - Matiiss
1
你设置画布背景颜色了吗?因为我忘记你使用的是覆盖在根窗口之上的画布,所以根窗口的颜色仍然很重要,但你也需要将画布背景颜色设置为相同的颜色。 - Matiiss
1
@IshaanJog 我认为 @Matiss 的意思是要删除所有的截图代码,并添加:root.config(bg="grey15"); canvas.config(bg="grey15"); root.attributes("-transparentcolor", "grey15") 代替它。 - TheLizzard
@Matiiss 问题在于 OP 仍然有一个代码,它截取了背景的屏幕截图,并将其用于他们的画布中。如果 OP 删除它并按照您的说明操作,它将起作用。 - TheLizzard
@TheLizzard 我错过了截图部分,我从来没有想过使用截图来创建透明效果,这实际上是一个相当酷的想法,截图应该在移动函数中进行,然后它可能会起作用,但可能不会那么顺畅。 - Matiiss
显示剩余12条评论
2个回答

4
如何在tkinter中更改窗口的形状(尽管这应该在大多数Windows计算机上工作,但某些其他操作系统(macOS,Linux)可能会出现问题,这意味着这个确切的代码可能无法正常工作且不能产生所需的输出)。请参考以下代码注释:
from tkinter import Tk, Canvas
from PIL import Image, ImageTk
import requests


# load image from web but you can of course load it from file, this is
# just so you can run and immediately see the results
url = 'http://media-s3-us-east-1.ceros.com/g3-communications/images/2019/01/15/05eea4b9b9ce010d2dd6b0c063d2f5ca/p1-blob.png?imageOpt=1&fit=bounds&width=893'
data = requests.get(url, stream=True).raw
# just when loading your own image instead of `data` use the path, and resize
# if you need, can obvs change these numbers
image = Image.open(data).resize((600, 600), Image.ANTIALIAS)


root = Tk()
# set root bg color to some rare color because
# the `-transparentcolor` affects all colors on the window, all of them
root.config(bg='grey15')
# just simply set window to the middle, not necessary
root.geometry(f'+{root.winfo_screenwidth() // 2 - 300}+{root.winfo_screenheight() // 2 - 300}')
# the important part, set the transparentcolor to some rare color in this case `grey15`,
# can obvs be sth else depending on your theme
root.attributes('-transparentcolor', 'grey15')
# remove window from window manager
root.overrideredirect(True)

# create canvas and set the bg to the same "rare" color (width and height set
# to image width and height, can be sth different too)
canvas = Canvas(
    root, bg='grey15', width=image.width, height=image.height, highlightthickness=0
)
canvas.pack()
# convert image to PhotoImage for `tkinter` to understand
photo = ImageTk.PhotoImage(image)
# put the image on canvas because canvas supports transparent bg
canvas.create_image(0, 0, image=photo, anchor='nw')

root.mainloop()

关键部分是.attributes('-transparentcolor', ...)(在某些操作系统上可能无法正常工作),窗口的形状由该形状的图像形成(图像应具有透明背景(.png图像))。还可以使用Canvas方法(.create_)简单地绘制形状。另外需要记住,该属性会影响窗口上的所有颜色,这意味着例如,如果您将transparentcolor设置为白色,并且您的背景图像包含白色,则它很可能也是透明的(虽然可能看起来不太好),因此建议使用一些最不可能出现在GUI中的颜色。


嗨@Matiiss 非常感谢!即使移动后,现在也已经舍入了! - IJ_123
我更喜欢使用画布形状而不是图像,因此我在画布和根目录中使用了-transparentcolor,它很有效!我使用canvas.create_polygon(...)创建了这个形状。 - IJ_123

2
我相信这将解决您的问题。
from tkinter import *
from PIL import ImageTk, Image
import pyautogui as pg


root = Tk()
root.overrideredirect(1)
root.configure(bg="white")
root.attributes("-topmost", 1)
root.attributes("-transparentcolor", "white")
root.geometry("500x500")

label = Label(root, height=900, width=900, bg="white", border=0)
label.pack()


def place_center():  # Placing the window in the center of the screen
    global x, y
    reso = pg.size()
    rx = reso[0]
    ry = reso[1]
    x = int((rx / 2) - (500 / 2))
    y = int((ry / 2) - (500 / 2))
    root.geometry(f"500x500+{x}+{y}")


place_center()

img = Image.open("bg.png")
img = img.resize((300, 300), Image.ANTIALIAS)

imagem = ImageTk.PhotoImage(img)
label.configure(image=imagem)

root.mainloop()

你不应该从一个模块中导入所有内容,这可能会导致非常难以调试的问题。 - Matiiss
@Cristielson Silva 你好 谢谢你的回答,但我不只是想要一张图片。 我想要整个窗口都是圆形的,并且可以移动。无论如何,Matiiss和TheLizzard帮助我解决了这个问题。 谢谢! - IJ_123
我更喜欢创建一个独立的形状,而不是使用图像。 - IJ_123

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接