微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

阻止文本在Tkinter画布中重叠

如何解决阻止文本在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来查找文本的像素大小,然后再创建它。尽管如此,文本仍然像这样重叠:

Overlapping numbers


我不确定如何解决此问题,或者为什么它无法按原样工作。任何帮助表示赞赏。

解决方法

我认为问题在于:

  1. 您放弃得太早了,
  2. 达到尝试次数限制时,无论文字是否重叠,都添加文字

您应该大幅增加尝试次数(也许几百次),然后如果尝试次数超过最大次数,则不应该绘制文本。

我认为更好的策略可能是先绘制文本项目,然后使用方法的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 举报,一经查实,本站将立刻删除。