如何解决阻止文本在Tkinter画布中重叠
我正在tkinter画布上创建一个游戏,其中涉及生成文本(1或2位数字),并且可以正常工作,但是我无法弄清楚如何显示它们,因此它们不会重叠。目前,我有这个:
import tkinter as tk
from tkinter import font
import random
Box_SIZE = 300
class Game(tk.Tk):
def __init__(self,*args,**kwargs):
tk.Tk.__init__(self,**kwargs)
self.config(bg = "white")
self.numBox = tk.Canvas(self,height = Box_SIZE,width = Box_SIZE,bg = "white",highlightthickness = 0)
self.numBox.pack(expand = True)
self.score = 0
self.numberSpawn()
def placeNumber(self,value):
validSpawn = False
attempts = 0
maxAttempt = False
while not validSpawn and not maxAttempt:
attempts += 1
if attempts > 20:
maxAttempt = True
attempts = 0
size = random.choice([24,36,48,72])
coord = [random.randint(40,Box_SIZE - 40) for x in range(2)]
self.numBox.update()
pxSize = tk.font.Font(size = size,family = "Times New Roman").measure(value)
if len(str(value)) == 1:
secondCoords = [coord[0] + pxSize *2.5,coord[1] + pxSize]
else:
secondCoords = [x + pxSize for x in coord]
if not self.numBox.find_overlapping(*coord,*secondCoords):
validSpawn = True
if not maxAttempt:
newTxt = self.numBox.create_text(*coord,font = ("Times New Roman",size),text = value)
def numberSpawn(self):
self.maxnum = random.randint(3,19)
self.placeNumber(self.maxnum)
for i in range(random.randint(4,16)):
num = random.randint(0,self.maxnum-1)
self.placeNumber(num)
app = Game()
app.mainloop()
value
是要显示的数字,Box_SIZE
是画布的尺寸。我尝试使用this来停止文本重叠,并尝试使用this来查找文本的像素大小,然后再创建它。尽管如此,文本仍然像这样重叠:
我不确定如何解决此问题,或者为什么它无法按原样工作。任何帮助表示赞赏。
解决方法
我认为问题在于:
- 您放弃得太早了,
- 达到尝试次数限制时,无论文字是否重叠,都添加文字
您应该大幅增加尝试次数(也许几百次),然后如果尝试次数超过最大次数,则不应该绘制文本。
我认为更好的策略可能是先绘制文本项目,然后使用方法的bbox
计算该项目占用的实际空间量。然后,使用它来查找重叠的项目。刚创建的项目将始终重叠,但是如果重叠数大于1,则选择新的随机坐标。
例如,也许像这样:
def placeNumber(self,value):
size = random.choice([24,36,48,72])
coord = [random.randint(40,BOX_SIZE - 40) for x in range(2)]
newTxt = self.numBox.create_text(*coord,font = ("Times New Roman",size),text = value)
for i in range(1000): # 1000 is the maximum number of tries to make
bbox = self.numBox.bbox(newTxt)
overlapping = self.numBox.find_overlapping(*bbox)
if len(overlapping) == 1:
return
# compute new coordinate
coord = [random.randint(40,BOX_SIZE - 40) for x in range(2)]
self.numBox.coords(newTxt,*coord)
# delete the text since we couldn't find a space for it.
self.numBox.delete(newTxt)
当可用空间不足时,两种算法都会变慢。当我创建一个包含100个数字的1000x1000画布时,它在一秒钟之内以零重叠的方式进行布局。
,这是为您提供的解决方案:
import tkinter as tk
from tkinter import font
import random
def checkOverlap(R1,R2):
if (R1[0]>=R2[2]) or (R1[2]<=R2[0]) or (R1[3]<=R2[1]) or (R1[1]>=R2[3]):
return False
else:
return True
def go():
validSpawn = False
while not validSpawn:
value = random.randint(1,99)
size = random.choice([24,72])
coord = [random.randint(40,500 - 40) for x in range(2)]
new_number = canvas.create_text(*coord,text=value)
new_box = canvas.bbox(new_number)
canvas.itemconfigure(new_number,state='hidden')
validSpawn = True
for i in canvas.items:
this_box = canvas.bbox(i)
if checkOverlap(this_box,new_box):
validSpawn = False
break
canvas.itemconfigure(new_number,state='normal')
canvas.items.append(new_number)
root = tk.Tk()
canvas = tk.Canvas(root,width = 500,height = 500,bg='white')
canvas.items = []
canvas.pack()
btn = tk.Button(root,text="Go",command=go)
btn.pack()
root.mainloop()
我没有让它尝试找出项目的大小,而是让它绘制,进行测量,隐藏它,然后寻找重叠,然后删除它或根据结果显示它。您将需要在其中添加最大尝试次数,否则屏幕上显示的数字越多,开始尝试的速度就越慢。它不应在函数中间绘制框架,以免用户在进行测量时永远看不到它。
我还保留了所有保存在屏幕上的数字的数组,因此我可以遍历它们并运行自己的重叠函数。这就是我喜欢的方式,您可以返回到使用find_overlapping,它仍然可以正常工作。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。