提问人:Paolo Sestini 提问时间:11/14/2023 更新时间:11/14/2023 访问量:42
仅当在主窗口中创建一个按钮时,具有图像功能的按钮大小调整才有效
Button resize with image function works only when one button is created in the main window
问:
我创建了一个函数,用于在调整按钮大小时调整按钮上的图像大小(我想在按钮的左上角保留徽标图像,并将文本放在按钮的中间),当在根窗口中创建单个按钮时,它似乎可以正常工作,但是当创建第二个按钮时,第一个按钮会填充整个根窗口并隐藏第二个按钮。
下面是我的代码。
请问,任何人都可以告诉我我做错了什么或如何解决我的问题吗?
谢谢。
#!/usr/bin/env python
# coding: utf-8
import tkinter as tk
from PIL import Image, ImageTk, ImageColor, ImageFont
root = tk.Tk()
root.wm_state("zoomed")
screenWidth = root.winfo_screenwidth()
screenHeight = root.winfo_screenheight()
screenText = f'Screen Width: {screenWidth}\nScreen Height: {screenHeight}'
def OnEnter(event, color: str):
event.widget['background'] = color
def OnLeave(event, color):
event.widget['background'] = color
def OnButtonResize(event, logo: str, extraText: str = "") -> None:
eventWidth = event.width
eventHeight = event.height
#print(f"Button resized to {eventWidth}x{eventHeight}")
# create a larger transparent image (around the size of the button)
img = Image.new("RGBA", (eventWidth, eventHeight), (0, 0, 0, 0))
# paste the small image at the top-left corner of this large image
img.paste(logo, (int(eventWidth/50), int(eventHeight/30)))
#imgWidth, imgHeight = img.size
buttonText = f"Button Width: {eventWidth}\nButton Height: {eventHeight}\n{extraText}"
#print(buttonText)
tkimg = ImageTk.PhotoImage(img)
event.widget['text'] = buttonText
event.widget['image'] = tkimg
event.widget.image = tkimg # This line is to make the image persistent and avoid errors due to garbage collector
def Rgb2Hex(rgbTuple: tuple) -> str:
return (f"#{rgbTuple[0]:02x}{rgbTuple[1]:02x}{rgbTuple[2]:02x}")
def Hex2Rgb(hexcode: str) -> tuple:
return(ImageColor.getcolor(hexcode, "RGB"))
def MinMax(x: int) -> int:
return(max(0, min(x, 255)))
def LightenHexColor(hexColorCode: str , percent: int = 10) -> str:
inputColorTuple = Hex2Rgb(hexColorCode)
ligtherColorTuple = ()
for i in inputColorTuple:
ligtherColorTuple = ligtherColorTuple + (MinMax(int(i*(100+percent)/100)),)
return(Rgb2Hex(ligtherColorTuple))
def GetZoneNameImage(zoneName: str = "Z1", fontColor: str = "#000000") -> str:
imageFilename = f"{zoneName}.png"
font_size = 128
font_filepath = "C:/Windows/Fonts/calibrii.ttf"
color = Hex2Rgb(LightenHexColor(fontColor, -25))
font = ImageFont.truetype(font_filepath, size=font_size)
mask_image = font.getmask(zoneName, "L")
img = Image.new("RGBA", mask_image.size)
img.im.paste(color, (0, 0) + mask_image.size, mask_image) # need to use the inner `img.im.paste` due to `getmask` returning a core
img.save(imageFilename, quality=100)
return(imageFilename)
helv32 = ("Helvetica", 32, "bold")
logoWidth = 150
logoHeight = 110
bgColorCursorOut1 = "#38bab6"
bgColorCursorIn1 = LightenHexColor(bgColorCursorOut1)
logoFilename1 = GetZoneNameImage(zoneName="Z1", fontColor=bgColorCursorOut1)
# load the required image and resize it to the desired size
logo1 = Image.open(logoFilename1).resize((logoWidth, logoHeight))
tkimg1 = ImageTk.PhotoImage(logo1)
bgColorCursorOut1 = "#38bab6"
bgColorCursorIn1 = LightenHexColor(bgColorCursorOut1)
button1 = tk.Button(root, text=screenText, image=tkimg1, compound="c", bg=bgColorCursorOut1, font=helv32)
button1.pack(fill=tk.BOTH, expand=tk.TRUE)
button1.bind("<Configure>", lambda event: OnButtonResize(event, logo1, screenText))
button1.bind("<Enter>", lambda event: OnEnter(event, bgColorCursorIn1))
button1.bind("<Leave>", lambda event: OnLeave(event, bgColorCursorOut1))
bgColorCursorOut2 = "#FCBA03"
bgColorCursorIn2 = LightenHexColor(bgColorCursorOut2)
logoFilename2 = GetZoneNameImage(zoneName="Z2", fontColor=bgColorCursorOut2)
# load the required image and resize it to the desired size
logo2 = Image.open(logoFilename2).resize((logoWidth, logoHeight))
tkimg2 = ImageTk.PhotoImage(logo2)
button2 = tk.Button(root, text=screenText, image=tkimg2, compound="c", bg=bgColorCursorOut2, font=helv32)
button2.pack(fill=tk.BOTH, expand=tk.TRUE)
button2.bind("<Configure>", lambda event: OnButtonResize(event, logo2))
button2.bind("<Enter>", lambda event: OnEnter(event, bgColorCursorIn2))
button2.bind("<Leave>", lambda event: OnLeave(event, bgColorCursorOut2))
root.mainloop()
答:
2赞
acw1668
11/14/2023
#1
由于您在两个按钮上使用,因此它们将尝试占用可用空间。并且将图像的大小设置为与按钮大小相同的大小,并且按钮内的可用空间不足以容纳图像(由于 和 options 占用了一些空间)。所以会发光,因为它是打包到窗口中的第一个按钮,它会再次触发事件。pack(fill=tk.BOTH, expand=tk.TRUE)
padx
borderwidth
highlightthickness
button1
<Configure>
对于您的情况,您可以使用而不是将按钮的大小限制在窗口的一半:place()
pack()
...
# button1 occupies the upper half of the window
button1.place(x=0, y=0, relwidth=1, relheight=0.5)
...
# button2 occupies the low half of the window
button2.place(x=0, rely=0.5, relwidth=1, relheight=0.5)
您可以正确使用并获得相同的结果。grid()
.rowconfigure()
.columnconfigure()
评论
0赞
Paolo Sestini
11/14/2023
您建议使用 place 的解决方案会引发错误:_tkinter。TclError:图像“pyimage727”不存在,但使用 grid() 似乎解决了所有问题。谢谢。
0赞
acw1668
11/14/2023
@PaoloSestini我不知道你是如何实现我的解决方案的,但它对我有用。
0赞
Paolo Sestini
11/14/2023
我只是替换了两行:......button1.pack(fill=tk.两者,expand=tk。没错)......button2.pack(fill=tk.两者,expand=tk。TRUE) 替换为您建议的解决方案。
0赞
acw1668
11/14/2023
@PaoloSestini 尝试在创建两个按钮时设置初始和选项。width
height
0赞
Paolo Sestini
11/14/2023
是的,设置按钮的初始宽度和高度解决了_tkinter。TclError:图像“pyimage727”错误。谢谢。
评论
padx
borderwidth
highlightthickness
eventWidth-8
eventHeight-8