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
相关产品推荐
相关产品推荐

