如何动态地将 Pillow 图像导入 Tkinter
How to get Pillow images into Tkinter dynamically
根据我的阅读,ImageTk
应该将 Pillow 图像转换为 Tkinter 可以显示的格式。 (事实上 ,当我不这样做时,Tkinter 会失败并出现错误。)但是,当我在我的 Windows 计算机上 运行 这个程序时,Tkinter 框说它没有响应并且不显示图像。
from PIL import Image, ImageDraw
class Block:
def __init__(self, x=30, y=10, speed=None, size=2.5):
self.x = x
self.y = y
self.size = size # radius
if speed is None:
speed = self.size * 2
self.speed = speed
def draw(self, image):
width, height = image.size
drawer = ImageDraw.Draw(image)
drawer.rectangle(((self.x - self.size, height - (self.y - self.size)), (self.x + self.size, height - (self.y + self.size))), fill="white")
class BallDodge():
def __init__(self):
self.width = 400
self.height = 300
self.main_player = Block(self.width // 2)
self.balls = []
self.frame = 0
self.frames_between_balls = 20
self.frames_since_last_ball = self.frames_between_balls
self.input_function = self.get_human_input
self.states = []
@property
def state(self):
ans = Image.new('RGBA', (self.width, self.height), "black")
self.main_player.draw(ans)
return ans
def get_human_input(self, *args, **kwargs):
try:
ans = int(input("1, 2, 3, or 4:"))
if ans > 4:
raise ValueError("Can't be greater than 4")
elif ans < 1:
raise ValueError("Can't be less than 1")
if ans == 1:
return [1, 0]
elif ans == 2:
return [0, 0]
elif ans == 3:
return [0, 1]
elif ans == 4:
return [1, 1]
else:
raise ValueError("Somehow it's not one of the specified numbers. You are magical.")
except Exception as e:
print("Invalid input")
print(e)
return self.get_human_input()
def step(self):
inpt = self.input_function(self.state)
directions = [-1, 1]
for i in range(2):
self.main_player.x += directions[i] * inpt[i]
self.states.append(self.state)
if __name__ == "__main__":
game = BallDodge()
import tkinter as tk
from PIL import ImageTk, Image
root = tk.Tk()
my_image = ImageTk.PhotoImage(game.state)
game.state.show()
while True:
panel = tk.Label(image = ImageTk.PhotoImage(game.state), master = root)
panel.pack()
# panel = Label(root, image = ImageTk.PhotoImage(game.state))
# panel.pack(side = "bottom", fill = "both", expand = "yes")
root.update_idletasks()
root.update()
game.step()
我注意到的事情:
如果我这样做 game.state.show()
它会很好地打开图像,所以那里肯定有图像。
如果我按下其中一个数字键前进到下一帧,Tkinter window 会变成原来的两倍高,但仍然不显示任何内容。
如何获得一个循环,以便我可以在 Tkinter 中显示 Pillow 图像 window,获取用户输入,然后显示新图像?
使用以下循环对我有用。 (它很乱,可以改进,但它有效。)
if __name__ == "__main__":
import tkinter as tk
from PIL import ImageTk, Image
game = BallDodge()
root = tk.Tk()
pilImage = game.state
tkimage = ImageTk.PhotoImage(pilImage)
width, height = pilImage.size
root.geometry('{}x{}'.format(width+1, height+1))
canvas = tk.Canvas(root, width=width, height=height, bg="blue")
canvas.pack()
imagesprite = canvas.create_image(0, 0, anchor=tk.NW, image=tkimage)
while True:
tkimage = ImageTk.PhotoImage(game.state)
imagesprite = canvas.create_image(0, 0, anchor=tk.NW, image=tkimage)
root.update_idletasks()
root.update()
game.step()
根据我的阅读,ImageTk
应该将 Pillow 图像转换为 Tkinter 可以显示的格式。 (事实上 ,当我不这样做时,Tkinter 会失败并出现错误。)但是,当我在我的 Windows 计算机上 运行 这个程序时,Tkinter 框说它没有响应并且不显示图像。
from PIL import Image, ImageDraw
class Block:
def __init__(self, x=30, y=10, speed=None, size=2.5):
self.x = x
self.y = y
self.size = size # radius
if speed is None:
speed = self.size * 2
self.speed = speed
def draw(self, image):
width, height = image.size
drawer = ImageDraw.Draw(image)
drawer.rectangle(((self.x - self.size, height - (self.y - self.size)), (self.x + self.size, height - (self.y + self.size))), fill="white")
class BallDodge():
def __init__(self):
self.width = 400
self.height = 300
self.main_player = Block(self.width // 2)
self.balls = []
self.frame = 0
self.frames_between_balls = 20
self.frames_since_last_ball = self.frames_between_balls
self.input_function = self.get_human_input
self.states = []
@property
def state(self):
ans = Image.new('RGBA', (self.width, self.height), "black")
self.main_player.draw(ans)
return ans
def get_human_input(self, *args, **kwargs):
try:
ans = int(input("1, 2, 3, or 4:"))
if ans > 4:
raise ValueError("Can't be greater than 4")
elif ans < 1:
raise ValueError("Can't be less than 1")
if ans == 1:
return [1, 0]
elif ans == 2:
return [0, 0]
elif ans == 3:
return [0, 1]
elif ans == 4:
return [1, 1]
else:
raise ValueError("Somehow it's not one of the specified numbers. You are magical.")
except Exception as e:
print("Invalid input")
print(e)
return self.get_human_input()
def step(self):
inpt = self.input_function(self.state)
directions = [-1, 1]
for i in range(2):
self.main_player.x += directions[i] * inpt[i]
self.states.append(self.state)
if __name__ == "__main__":
game = BallDodge()
import tkinter as tk
from PIL import ImageTk, Image
root = tk.Tk()
my_image = ImageTk.PhotoImage(game.state)
game.state.show()
while True:
panel = tk.Label(image = ImageTk.PhotoImage(game.state), master = root)
panel.pack()
# panel = Label(root, image = ImageTk.PhotoImage(game.state))
# panel.pack(side = "bottom", fill = "both", expand = "yes")
root.update_idletasks()
root.update()
game.step()
我注意到的事情:
如果我这样做 game.state.show()
它会很好地打开图像,所以那里肯定有图像。
如果我按下其中一个数字键前进到下一帧,Tkinter window 会变成原来的两倍高,但仍然不显示任何内容。
如何获得一个循环,以便我可以在 Tkinter 中显示 Pillow 图像 window,获取用户输入,然后显示新图像?
使用以下循环对我有用。 (它很乱,可以改进,但它有效。)
if __name__ == "__main__":
import tkinter as tk
from PIL import ImageTk, Image
game = BallDodge()
root = tk.Tk()
pilImage = game.state
tkimage = ImageTk.PhotoImage(pilImage)
width, height = pilImage.size
root.geometry('{}x{}'.format(width+1, height+1))
canvas = tk.Canvas(root, width=width, height=height, bg="blue")
canvas.pack()
imagesprite = canvas.create_image(0, 0, anchor=tk.NW, image=tkimage)
while True:
tkimage = ImageTk.PhotoImage(game.state)
imagesprite = canvas.create_image(0, 0, anchor=tk.NW, image=tkimage)
root.update_idletasks()
root.update()
game.step()