使用新制作的图像更新tkinter窗口中的图像

时间:2018-04-12 03:05:10

标签: python-3.x tkinter graphics

我编写了一个程序来模拟恒星周围行星的轨道,我想要一个可视化器来显示恒星周围的当前行星位置。由于所有行星都存储了x和y的合成,因此将它们绘制在图像上是很简单的,但我不知道在每个模拟步骤之后更新图像并重新显示的好方法。

目前我像这样绘制图像(使用行星位置将像素变为红色)

def createwindow():
    img = Image.new( 'RGB', (750,730), "black")
    pixels = img.load()

    for thing in celestials:
        pixels[thing.xpos+375+sun.xpos,thing.ypos+375+sun.xpos]=250,20,20

所以我有一个很好地显示行星的图像,每次行星移动后都可以重建。但是如何在tkinter窗口中显示它?

有没有办法在不使用必须保存和加载的Photoimage的情况下执行此操作?或者更好的方式一起完成这一切?也许为每个行星分配一个标签并直接在tkinter黑色窗口上绘制它们,在每个模拟步骤中更新标签的位置?

所有帮助表示赞赏

2 个答案:

答案 0 :(得分:0)

您应该在画布上绘制动画,而不是在静态图像上绘制动画;然后,您可以移动在模拟的每个步骤中修改的动画元素。

沿着这些方向:(按下底部开始)

import tkinter as tk


def animate():
    canvas.move(1, 5, 0)     # 1 refers to the object to be moved ID, dx=5, dy=0
    root.update()
    root.after(50, animate)


if __name__ == '__main__':

    root = tk.Tk()

    frame = tk.Frame(root)
    canvas = tk.Canvas(root, width=800, height=400)
    canvas.pack()
    canvas.create_polygon(10, 10, 50, 10, 50, 50, 10, 50)  # canvas object ID created here by tkinter 

    btn = tk.Button(root, text='start', command=animate)
    btn.pack()

    root.mainloop()

答案 1 :(得分:0)

有很多方法可以显示动态内容,例如移动行星。这取决于您是否更喜欢使用小部件,像素,图像或图形基元。

窗口小部件

如果你喜欢移动小部件,正如你所说,你可以将每个星球分配给Label。然后,您可以使用Place Geometry Manager

将其放在窗口上
yourLabel.place(anchor=CENTER, relx=0.5, rely=0.5, x=-100, y=50)

这会将标签的中心设置为相对于其父中心的坐标(-100,50)(relx = 0.5,依赖= 0.5)。使用不同的(x,y)坐标更改位置调用.place()

像素

要在运行时更改图像像素,您可以使用.blank()的{​​{1}},.get().put()方法。它们不在TkInter book中,但您可以在python控制台的PhotoImage中看到它们。要将单个像素(x,y)设置为颜色#fa1414,请使用:

help(PhotoImage)

这里的yourPhotoImage.put("{#fa1414}", to=(x,y)) 参数实际上是一个像素列表。 Tk可以在一次调用中放置一个矩形像素块。颜色是逐行指定的,用空格分隔,每行用大括号括起来。 NxM颜色块看起来像“{C 0,0 C 1,0 ... C N-1,0 } {C 0,1 C 1,1 ... C N-1,1 } ... {C 0,M- 1 C 1,M-1 ... C N-1,M-1 }“。例如,要将2x2像素放入坐标(4,6),请使用:

"{#fa1414}"

除#rrggbb语法外,Tk还识别了许多symbolic color names

请注意,所有更改都会立即显示。您无需手动“重新显示”图像。例如。如果您在某处定义了yourPhotoImage.put("{red green} {#7f007f blue}", to=(4,6)) ,则在修改PhotoPmage后会显示更改。

图片

PhotoImage也可以从base64编码的字符串加载图像。因此,从技术上讲,要跳过保存/加载文件,您可以从字符串加载图像,其中包含base64编码的.gif或.png格式{{3}在Tk):

Label(image=yourPhotoImage)

newimg = PhotoImage(data="R0lGODlhHgAUAPAAAP//AAAAACH5BAAAAAAALAAAAAAeABQAAAIXhI+py+0Po5y02ouz3rz7D4biSJZmUgAAOw==") 也支持base64字符串。例如,如果您将行星作为图像加载到base64字符串中,则可以将它们放入图像中:

.put()

最后,如果您正在使用PIL,可以从PIL.Image yourPhotoImage.put(base64_mars_image_string, to=(100,50)) 创建supported natively并在任何地方使用它Tkinter接受图像对象 PIL.ImageTk.PhotoImage

img

图形基元

如果你想要线条或弧线,你也可以使用[ref]。它提供了一种将不同的小部件,图像,文本,图形基元组合在一起并移动它们或配置与它们的交互的方法。基于画布的行星系统看起来像这样(python2语法):

from PIL import ImageTk
photoimg = ImageTk.PhotoImage(img)

请注意,在您删除它们之前,会保留在画布上创建的项目。如果要更改图形,可以使用from Tkinter import * import math, time color = ["#fffc00", "#a09991", "#b6b697", "#2c81ca", "#a36447", "#b16811", "#e5ca9d", "#bcdaf2", "#7e96bc", "#d3ac8b"] size = [20, 4, 7, 7, 5, 15, 13, 9, 9, 4] start_time = time.time() def update_positions(): dt = (time.time() - start_time)*5 for i in range(len(planets)): px, py = 350+35*i*math.cos(dt/(i+1)/size[i]+4*i), 350+35*i*math.sin(dt/(i+1)/size[i]+4*i) canvas.coords(planets[i], (px-size[i],py-size[i],px+size[i],py+size[i])) root.after(100, update_positions) root = Tk() canvas = Canvas(root, width=700, height=700, bg="black") arcs = [canvas.create_oval(350-35*i, 350-35*i, 350+35*i, 350+35*i, outline=color[i]) for i in range(len(color))] planets = [canvas.create_oval(350, 350, 350, 350, fill=color[i]) for i in range(len(color))] update_positions() canvas.pack() root.mainloop() .coords().itemconfig()等方法修改项目,也可以使用.move()删除它们。