You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Tkinter 3D图形仅在mainloop中更新一次的问题

Tkinter 3D图形程序屏幕不刷新问题

我正在使用Python Tkinter开发一款3D图形程序,核心逻辑是通过主函数重置并根据旋转值修改所有3D坐标,再将这些点转换后使用create_line函数绘制朝前的三角形,最终希望屏幕更新显示所有绘制的线条,并通过不断修改旋转值实现模型持续旋转。

实际运行中,数学计算和线条绘制逻辑均正常执行,且主函数确实在重复运行,但屏幕仅在第一次迭代时更新,后续不再刷新。我已排查确认问题与root.update或mainloop的使用方式相关。

尝试过的方案

  • 在while循环中仅使用root.update(),仍存在仅更新一次的问题;
  • 当前代码采用root.mainloop()结合after()的方式;
  • 仅使用root.mainloop(),无法实现预期效果。

当前代码

import tkinter as tk
import math
import time

root = tk.Tk()
root.geometry('475x375')

w = 400
h = 400

win = tk.Canvas(root, width=w, height=h,bd=0,highlightthickness=0)
win.configure(bg="black")
win.pack()

sortedPos = [0,0,0,0,0,0]

colors = ["#ffffff","#ff0000","#00ff00","#0000ff","#ff00ff","#ffff00","#ff0000","#ffffff","#ff00ff","#0000ff","#ffff00","#00ff00"]
c = ""

def centeredLine(x1,y1,x2,y2):
    win.create_line(x1 + w/2, (0-y1) + h/2, x2 + w/2, (0-y2) + h/2, fill=c)

def triangle(x1,y1,x2,y2,x3,y3):
    y = y1
    while (y<y2):
        centeredLine(x1+(((x2-x1)/(y2-y1))*(y-y1)), y, x1+(((x3-x1)/(y3-y1))*(y-y1)), y)
        y += 1
    while (y<y3):
        centeredLine(x2+(((x3-x2)/(y3-y2))*(y-y2)), y, x1+(((x3-x1)/(y3-y1))*(y-y1)), y)
        y += 1

def sort(x1,y1,x2,y2,x3,y3):
    if ((x1*y2-x2*y1)+(x2*y3-x3*y2)+(x3*y1-x1*y3)<0):
        if (y1 < y2):
            if y1 < y3:
                sortedPos[0] = x1
                sortedPos[1] = y1
                if (y2 < y3):
                    sortedPos[2] = x2
                    sortedPos[3] = y2
                    sortedPos[4] = x3
                    sortedPos[5] = y3
                else:
                    sortedPos[2] = x3
                    sortedPos[3] = y3
                    sortedPos[4] = x2
                    sortedPos[5] = y2
            else:
                sortedPos[0] = x3
                sortedPos[1] = y3
                sortedPos[2] = x1
                sortedPos[3] = y1
                sortedPos[4] = x2
                sortedPos[5] = y2
        elif (y2 < y3):
            sortedPos[0] = x2
            sortedPos[1] = y2
            if (y1 < y3):
                sortedPos[2] = x1
                sortedPos[3] = y1
                sortedPos[4] = x3
                sortedPos[5] = y3
            else:
                sortedPos[2] = x3
                sortedPos[3] = y3
                sortedPos[4] = x1
                sortedPos[5] = y1
        else:
            sortedPos[0] = x3
            sortedPos[1] = y3
            sortedPos[2] = x2
            sortedPos[3] = y2
            sortedPos[4] = x1
            sortedPos[5] = y1
        triangle(sortedPos[0],sortedPos[1],sortedPos[2],sortedPos[3],sortedPos[4],sortedPos[5])

xPos = [60,60,60,60,-60,-60,-60,-60,0,0,0,0,37.08,37.08,-37.08,-37.08,97.08,97.08,-97.08,-97.08]
yPos = [60,60,-60,-60,60,60,-60,-60,97.08,97.08,-97.08,-97.08,0,0,0,0,37.08,-37.08,37.08,-37.08]
zPos = [60,-60,60,-60,60,-60,60,-60,37.08,-37.08,37.08,-37.08,97.08,-97.08,97.08,-97.08,0,0,0,0]

sX = []
sY = []

triangles1 = [0,0,8,4,8,9,8,12,0,2,2,2,6,6,6,10,10,10,11,11,11,7,7,7,3,3,3,7,7,7,15,15,15,11,11,11]
triangles2 = [16,1,1,5,5,5,4,8,8,0,16,17,14,4,18,14,12,2,2,17,3,6,10,11,13,1,16,19,18,5,5,9,1,7,15,13]
triangles3 = [1,8,9,18,4,8,14,14,12,12,0,16,4,18,19,6,14,12,10,2,17,19,6,10,1,16,17,18,5,15,9,1,13,15,13,3]

fovl = 310

def reset():
    win.delete("all")
    
    xPos = [60,60,60,60,-60,-60,-60,-60,0,0,0,0,37.08,37.08,-37.08,-37.08,97.08,97.08,-97.08,-97.08]
    yPos = [60,60,-60,-60,60,60,-60,-60,97.08,97.08,-97.08,-97.08,0,0,0,0,37.08,-37.08,37.08,-37.08]
    zPos = [60,-60,60,-60,60,-60,60,-60,37.08,-37.08,37.08,-37.08,97.08,-97.08,97.08,-97.08,0,0,0,0]
    sX = []
    sY = []

xDif = 0
yDif = 0

def rotateX(d):
    #Around X-axis: X = x; Y = y*cos(theta) - z*sin(theta); Z = y*sin(theta) + z*cos(theta);
    for i, val in enumerate(yPos):
        yPos[i] = val*math.cos(abs(d)) - zPos[i]*math.sin(d)
        zPos[i] = val*math.sin(d) + zPos[i]*math.cos(abs(d))

def rotateY(d):
    #Around Y-axis: X = x*cos(theta) + z*sin(theta); Y = y; Z = z*cos(theta) - x*sin(theta);
    for i, val in enumerate(xPos):
        xPos[i] = val*math.cos(abs(d)) + zPos[i]*math.sin(d)
        zPos[i] = zPos[i]*math.cos(abs(d)) - val*math.sin(d)

def to2D():
    for i, val in enumerate(xPos):
        sX.append(round(fovl/(fovl+zPos[i])*val))
        sY.append(round(fovl/(fovl+zPos[i])*yPos[i]))

def main():
    global c
    global yDif
    reset()
    rotateX(xDif)
    rotateY(yDif)
    to2D()
    for i, val in enumerate(triangles1):
        c = (colors[int(i/3)])
        sort(sX[val],sY[val],sX[triangles2[i]],sY[triangles2[i]],sX[triangles3[i]],sY[triangles3[i]])
    yDif += 10
    print("done")
    root.after(0, root.update())
    root.after(1000, main)

main()
root.mainloop()

主函数具体流程

  • 将3D坐标重置为初始值并清空画布;
  • 根据X轴旋转值修改3D坐标;
  • 根据Y轴旋转值修改3D坐标;
  • 将3D坐标转换为2D屏幕坐标;
  • 开始绘制三角形:设置当前三角形颜色,按Y值排序屏幕坐标,使用create_line逐层绘制三角形;
  • 重复绘制所有三角形(共36个);
  • 将Y轴旋转值增加10;
  • 打印"done"用于调试,确认主函数重复执行;
  • 调用root.after(0, root.update()),未解决问题;
  • 调用root.after(1000, main)实现每秒重复一次主函数。

若需更多信息,请告知。

内容的提问来源于stack exchange,提问作者GingrBread

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 06:55:55