tkinter中利用Canvas创建图像,这个倒是正常,如果静态的纯手工写死几个文件路径,倒也能正常加载,但现在的问题,我通过askopenfilename这个函数调用文件对话框,实现让使用者自定义选择图片
self.filepath = filedialog.askopenfilename(filetypes=[('png', '.png')])
通过该功能获取文件路径和文件名,再通过cv.create_image的形式加载该图片,该功能倒也算正常,不过当打开添加第二张图。第N张图时,永远只显示出来最后一次加载的图片,之前的图片全部显示不出来。在网上查了好多资料,说是垃圾回收机制的原因,需要通过临时局部变量添加引用的形式,我也加了引用
cvImageID = self.cv.create_image(self.w / 2, self.h / 2, image=photo)
self.imageList.append(cvImageID)
self.iamgeList是在初始化时就创建的一个集合
但是我通过直接循环创建同一个图片,又能正常:
def createImage(self, photo):
for i in range(5):
cvImageID = self.cv.create_image(self.w / 2, self.h / 2, image=photo)
self.imageList.append(cvImageID)
print(self.imageList)
但此处又不可能单一的循环某一张图,仅作为测试用。
如果按照选一次图加载一张图出来,却永远只显示最后一张
下面给出主要的代码实现:
# -*- coding: utf-8 -*-
# @Author : SiriBen
# @Time : 2022/5/13 10:57
# @File : main.py
# @Descripts: 主界面
import tkinter as tk
from tkinter import filedialog
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
from PIL import Image, ImageGrab, ImageTk
# img = None
# imgT = None
# photo = None
class APP:
def __init__(self):
self.w = 1440
self.h = 900
self.frameTop = ttk.Frame(root)
self.frameTop.pack()
self.frameFooter = ttk.Frame(root)
self.frameFooter.pack()
self.str1 = ttk.StringVar()
self.imageList = []
self.main()
def button1(self, event):
#global filepath
button_text = event.widget['text']
print('触发按钮'.format(button_text))
#folderpath = filedialog.askdirectory()
try:
self.filepath = filedialog.askopenfilename(filetypes=[('png', '.png')])
print('选择文件为:{}'.format(self.filepath))
self.str1.set(self.filepath)
except Exception as e:
print(e)
return
def loadingImage(self, event):
global img, imgT, photo, cv
filepath2 = self.filepath
img = Image.open(filepath2)
print(img)
imgT = img.resize((int(img.size[0] * 0.5), int(img.size[1] * 0.5)), Image.ANTIALIAS)
print(imgT)
photo = ImageTk.PhotoImage(imgT)
print(photo)
self.createImage(photo)
def createImage(self, photo):
#for i in range(5):
cvImageID = self.cv.create_image(self.w / 2, self.h / 2, image=photo)
self.imageList.append(cvImageID)
print(self.imageList)
self.cv.bind("<ButtonPress-1>", self.StartMove) # 绑定鼠标左键按下事件
self.cv.bind("<ButtonRelease-1>", self.StopMove) # 绑定鼠标左键松开事件
self.cv.bind("<B1-Motion>", self.OnMotion) # 绑定鼠标左键被按下时移动鼠标事件
def StartMove(self, event):
global first_x, first_y, clickID
allID = self.cv.find_closest(event.x, event.y) # halo =3容易找到细直线
print(allID)
if len(allID) > 0:
clickID = allID[0]
first_x, first_y = event.x, event.y
def StopMove(self, event):
global first_x, first_y, clickID
# cv.move(clickID,event.x-first_x,event.y-first_y)
# cv.delete(clickID)#删除对象ID的画布
clickID = -1
def OnMotion(self, event):
global first_x, first_y, clickID
if clickID != -1:
self.cv.move(clickID, event.x - first_x, event.y - first_y)
first_x, first_y = event.x, event.y
def main(self):
b1 = ttk.Button(self.frameTop, text="选择", bootstyle="success")
b1.pack(side=LEFT, padx=5, pady=10)
b1.bind('<Button-1>', self.button1)
b2 = ttk.Button(self.frameTop, text="加载", bootstyle="info-outline")
b2.pack(side=LEFT, padx=5, pady=10)
b2.bind('<Button-1>', self.loadingImage)
lable1 = ttk.Label(self.frameTop, text='当前文件路径:')
lable1.pack()
self.lable2 = ttk.Label(self.frameTop, text='路径', textvariable=self.str1)
self.lable2.pack()
self.cv = ttk.Canvas(root, width=self.w, height=self.h)
#cv = tk.Canvas(root, height=1440, width=2560, bg='#FFFFFF') # silver
self.cv.pack(side=LEFT, padx=5, pady=10)
if __name__ == '__main__':
w = 1440
h = 900
root = ttk.Window(
title='设计预览',
themename='superhero', #主题
size=(w, h), #大小
#resizable=None, #是否更改大小
alpha=1.0, #透明度
position=(50, 50) #位置
)
# style = ttk.Style()
# theme_names = style.theme_names() # 以列表形式返回多个主题名
# w = root.winfo_screenwidth()
# h = root.winfo_screenheight()
# root.geometry('%dx%d' % (w, h))
app = APP()
root.mainloop()
你要创建一个列表,保存图片的路径目录,这样每次刷新的时候,循环调用创建图片。这也是为什么同一张图片可以放好几次,因为路径是同一个,但是如果你不保存之前图片的路径,刷新的时候就丢失了。记住:所谓的刷新,其实就是重画。位置信息也是一样,如果要保持不变,也要建一个列表保存起来,下次刷新重新在那个位置画。时间紧,稍微这样改了一下,你试试:
class APP:
def __init__(self):
self.pathList = []
self.imageList = []
def loadingImage(self, event):
global img, imgT, photo, cv
filepath2 = self.filepath
self.pathList.append(filepath2)
img = []
photo = []
for i in range(len(self.pathList)):
img.append(Image.open(self.pathList[i]))
photo.append(ImageTk.PhotoImage(img[i].resize((int(img[i].size[0] * 0.5), int(img[i].size[1] * 0.5)), Image.ANTIALIAS)))
self.createImage(photo)
def createImage(self, photo):
for i in photo:
cvImageID = self.cv.create_image(self.w / 2, self.h / 2, image=i)
self.imageList.append(cvImageID)