在Python3 / Tkinter中创建一个随机大小正方形的对称网格

时间:2018-07-27 21:19:14

标签: python-3.x math tkinter

我有一个问题围绕着什么是可行的方法来在tkinter画布上的对称,不可见网格上放置随机大小的正方形。我将对此进行彻底的解释,因为这是一个专有问题。

到目前为止,我主要尝试用数学方法解决它。但是我发现这是一个非常复杂的问题,并且采用比我尝试过的方法更好的方法似乎是合理的。

最基本的代码如下:

while x_len > canvas_width:
                xpos = x_len + margin
                squares[i].place(x=xpos, y=ypos)
                x_len += square_size + space
                i += 1

x_len是给定行上所有正方形的总宽度,并且在退出while循环时(例如,当x_len>窗口宽度时),在xpos(在X上的位置)以及重置Y时重置。轴以创建新行。

放置相同大小的正方形时,它看起来像这样: same-size squares

到目前为止很好。

但是,当正方形是随机大小时,它看起来像这样(最多): random-size squares

除了布局可能无法预测之外,核心问题是正方形没有居中于“不可见网格”上-因为没有网格。

因此,为了解决这个问题,我尝试了一种方法,即根据每个给定的平方使用固定距离和相对距离。这样一来,对于第一行的Y轴,而不是X轴,Y的后续行,也不会有令人满意的结果。

请参阅示例(其中第一行以Y为中心,但随后的行而不是X):

random-size squares with new function

因此,通过这种方法,我基于从包含所有生成的正方形的宽度的列表中获取的变量,在Y轴和X轴上都使用了每平方改变。

从整体上看,它是这样的(尽管它仍在进行中,所以优化程度不是很好):

square_widths = [60, 75, 75, 45...]

space = square_size*0.5
margin = (square_size+space)/2
xmax = frame_width - margin - square_size
xmin = -1 + margin

def iterate(ypos, xpos, x_len):
    y = ypos
    x = xpos
    z = x_len
    i=0
    m_ypos = 0
    extra_x = 0

    while len(squares) <= 100:
        n=-1
        # row_ypos alters y for every new row
        row_ypos += 200-square_widths[n]/2

        # this if-statement is not relevant to the question
        if x < 0:
            n=0
            xpos = x
            extra_x = x
            x_len = z
            while x_len < xmax:
                ypos = row_ypos
                extra_x += 100
                ypos = row_ypos + (200-square_widths[n])/2
                xpos = extra_x + (200-square_widths[n])/2
                squares[i].place(x=xpos, y=ypos)
                x_len = extra_x + 200
                i += 1
                n += 1

这里最相关的是row_ypos,它改变每一行的Y,以及ypos,改变每一平方的Y(我还没有X的有效计算)。我想要获得的结果与第一行的Y轴类似。在所有行和列上(例如在X和Y中)。创建一个具有不同大小正方形的对称网格。

所以我的问题是: 这真的是解决此问题的最佳做法吗? 如果是这样-您是否有任何技巧可以达到目的? 如果不是-您将如何处理?

一个旁注是,它必须“手动”完成,我不能使用tkinter的内置函数来解决它。

2 个答案:

答案 0 :(得分:1)

为什么不只使用grid几何管理器?

COLUMNS = 5
ROWS = 5

for i in range(COLUMNS*ROWS):
    row, col = divmod(i, COLUMNS)
    l = tk.Label(self, text=i, font=('', randint(10,50)))
    l.grid(row=row, column=col)

这将使所有内容对齐,但是随机性可能会使行和列的大小不同。您可以使用行和列配置功能进行调整:

import tkinter as tk
from random import randint

COLUMNS = 10
ROWS = 5
class GUI(tk.Frame):
    def __init__(self, master=None, **kwargs):
        tk.Frame.__init__(self, master, **kwargs)

        labels = []
        for i in range(COLUMNS*ROWS):
            row, col = divmod(i, COLUMNS)
            l = tk.Label(self, text=i, font=('', randint(10,50)))
            l.grid(row=row, column=col)
            labels.append(l)

        self.update() # draw everything
        max_width = max(w.winfo_width() for w in labels)
        max_height = max(w.winfo_height() for w in labels)
        for column in range(self.grid_size()[0]):
            self.columnconfigure(col, minsize=max_width) # set all columns to the max width
        for row in range(self.grid_size()[1]):
            self.rowconfigure(row, minsize=max_height) # set all rows to the max height

def main():
    root = tk.Tk()
    win = GUI(root)
    win.pack()
    root.mainloop()

if __name__ == "__main__":
    main()

答案 1 :(得分:0)

我发现导致结果没有达到预期效果的罪魁祸首,这不是由于计算所致。相反,事实证明,我创建的列表未按正确的顺序放置正方形(此后我应该知道)。

所以我从原始数据本身获取了宽度,这比创建列表要有意义得多。

该函数现在看起来像这样(再次,它仍在完善中,但是我只想发布它,这样人们就不会浪费时间为已经解决的问题提出解决方案了:)):< / p>

def iterate(ypos, xpos, x_len):
    y = ypos
    x = xpos
    z = x_len
    i=0

    while len(squares) <= 100:
        n=0
        if y > 1:
            ypos -= max1 + 10
        if y < 0:
            if ypos < 0:
                ypos=10
            else:
                ypos += max1 + 10 #+ (max1-min1)/2

        if x < 0:
            n=0
            xc=0
            xpos = x
            x_len = z

            while x_len < xmax:
                yc = ypos + (max1-squares[i].winfo_width())/2
                if xpos <= 0:
                    xpos = 10
                else:
                    xpos += max1 + 10
                xc = xpos + (max1-squares[i].winfo_width())/2
                squares[i].place(x=xc, y=yc)
                x_len += max1 + 10
                print (x_len)
                i += 1
                n += 1