如何使tkinter框架循环并更新对象值?

Khl*_*loe 5 python dictionary tkinter python-3.x

我的词典中有一个叫Bones5 的班级。但是,在我的实际实现中,有300多个骨骼,这就是为什么我今天在stackoverflow上问这个问题。Bonesskeleton

每个Bone都有:

  • ID:识别骨骼的整数
  • w:w位置(在-1和之间浮动1)
  • x:x位置(在-1和之间浮动1)
  • y:y位置(在-1和之间浮动1)
  • z:z位置(在-1和之间浮动1)

Bone.py

INCREMENT = 0.01

class Bone:
    def __init__(self, boneId, w, x, y, z):
        self.id = boneId
        self.w = w
        self.x = x
        self.y = y
        self.z = z

    def shouldChangePos(self, num):
        if (num >= 1 or num <= -1):
            return False
        return True

    def incrW(self):
        if(self.shouldChangePos(self.w)):
            self.w = self.w + INCREMENT

    def decrW(self):
        if(self.shouldChangePos(self.w)):
            self.w = self.w - INCREMENT

    def incrX(self):
        if(self.shouldChangePos(self.x)):
            self.x = self.x + INCREMENT

    def decrX(self):
        if(self.shouldChangePos(self.x)):
            self.x = self.x - INCREMENT

    def incrY(self):
        if(self.shouldChangePos(self.y)):
            self.y = self.y + INCREMENT

    def decrY(self):
        if(self.shouldChangePos(self.y)):
            self.y = self.y - INCREMENT

    def incrZ(self):
        if(self.shouldChangePos(self.z)):
            self.z = self.z + INCREMENT

    def decrZ(self):
        if(self.shouldChangePos(self.z)):
            self.z = self.z - INCREMENT
Run Code Online (Sandbox Code Playgroud)

问题说明

我正在尝试制作一个tkinter看起来像这样的GUI:

gui的模型图

传说:

  • 绿色-代表一个Frame(仅我的注释可以解释)
  • 红色-是对象的属性(仅用于解释我的注释)
  • 黑色-是对象的方法(仅我的注释即可解释)
  • 蓝色-向我显示的文字和按钮

正如你所看到的,它显示ID,w,x,y,z。在它的下面,有一个+按钮和一个-按钮。每次单击这些按钮时,我想减少对象中的相应值并更新tkinter显示的数字。我知道如何手动执行此操作,但是根据我的要求,我有300+ Bones。我无法手动制作这些镜框。

当单击+或-按钮时,如何循环创建这些框架并更新GUI和对象上显示的值?


main.py

from tkinter import *
from tkinter import ttk
from Bone import *

skeleton = {
    1: Bone(-0.42, 0.1, 0.02, 0.002, 0.234),
    4: Bone(4, 0.042, 0.32, 0.23, -0.32),
    11: Bone(11, 1, -0.23, -0.42, 0.42),
    95: Bone(95, -0.93, 0.32, 0.346, 0.31),
}


root = Tk()
root.geometry('400x600')

boneID = Label(root, text="ID: 1")
boneID.grid(row=1, column=1, sticky=W, padx=(0, 15))

w = Label(root, text="-0.42")
w.grid(row=1, column=2, sticky=W)

x = Label(root, text="0.02")
x.grid(row=1, column=4, sticky=W)

y = Label(root, text="0.002")
y.grid(row=1, column=6, sticky=W)

z = Label(root, text="0.234")
z.grid(row=1, column=8, sticky=W)

wPlusBtn = Button(root, text="+")
wPlusBtn.grid(row=2, column=2)
wMinusBtn = Button(root, text="-")
wMinusBtn.grid(row=2, column=3, padx=(0, 15))

xPlusBtn = Button(root, text="+")
xPlusBtn.grid(row=2, column=4)
xMinusBtn = Button(root, text="-")
xMinusBtn.grid(row=2, column=5, padx=(0, 15))

yPlusBtn = Button(root, text="+")
yPlusBtn.grid(row=2, column=6)
yMinusBtn = Button(root, text="-")
yMinusBtn.grid(row=2, column=7, padx=(0, 15))

zPlusBtn = Button(root, text="+")
zPlusBtn.grid(row=2, column=8)
zMinusBtn = Button(root, text="-")
zMinusBtn.grid(row=2, column=9, padx=(0, 15))

root.mainloop()
Run Code Online (Sandbox Code Playgroud)

Rig*_*leg 1

这里有两个问题:在循环中创建帧,并在按下 +/- 按钮时更新值。

为了处理框架问题,我建议您创建一个BoneFrame类来保存与一个实例相关的所有小部件(按钮和标签)Bone。在那里,您还可以将按钮绑定到Bone方法以便对值进行操作。类似的东西 - 我相信你会知道如何使用其他变量和你想要的网格坐标来完成这个

class BoneFrame(tk.Frame):
    def __init__(self, parent, bone):
        super().__init__(parent)

        # Create your widgets
        self.x_label = tk.Label(self, text=bone.x)
        self.x_decr_button = tk.Button(self, text="-", action=bone.decr_x)
        self.x_incr_button = tk.Button(self, text="+", action=bone.incr_x)
        ...

        # Then grid all the widgets as you want
        self.x_label.grid()
        ...
Run Code Online (Sandbox Code Playgroud)

然后,您可以轻松地迭代 s 的字典Bone,BoneFrame每次实例化,或者pack将该grid实例实例化到父容器。也许您需要将 a 添加bone_id到 的参数中BoneFrame.__init__并将其传递到循环中。

# In your main script
for bone_id, bone in skeleton.items():
    frame = BoneFrame(root, bone)
    frame.pack()
Run Code Online (Sandbox Code Playgroud)

目前,标签中的值永远不会更新。那是因为我们只设置一次文本,然后就不再更新它们。Bone我们可以定义更复杂的方法来BoneFrame实现更多逻辑,包括更新值以及刷新小部件,而不是将按钮直接绑定到 的方法。这是一种方法:

class BoneFrame(tk.Frame):
    def __init__(self, parent, bone):
        super().__init__(parent)

        # Store the bone to update it later on
        self.bone = bone

        # Instantiate a StringVar in order to be able to update the label's text
        self.x_var = tk.StringVar()
        self.x_var.set(self.bone.x)

        self.x_label = tk.Label(self, textvariable=self.x_var)
        self.x_incr_button = tk.Button(self, text="+", action=self.incr_x)

        ...

    def incr_x(self):
        self.bone.incr_x()
        self.x_var.set(self.bone.x)
Run Code Online (Sandbox Code Playgroud)

所以我们需要一个StringVar来更新标签的内容。总而言之,我们不是将按钮绑定到bone.incr_x,而是将其绑定到self.incr_x,这允许我们在按下按钮时做任何我们想做的事情,即 1. 更改实例中的值Bone,2. 更新实例中显示的值标签。