问题描述
简单地说,我通过 tkinter.filedialog
函数上传图像,并希望图像与我通过单击另一个按钮提供的名称同时存储到数据库中,名称存储良好,但不是图像。
这是代码。
from tkinter import *
from tkinter import ttk
from PIL import Image,ImageTk
from tkinter import ttk,messageBox
from tkinter import filedialog
import sqlite3
root=Tk()
root.geometry("600x400")
#==========Database================
con = sqlite3.connect(database="std.db")
cur = con.cursor()
cur.execute("CREATE TABLE IF NOT EXISTS std (name TEXT,photo BLOB )")
#==========Variblels================
var_name = StringVar()
var_photo = StringVar()
#==========Method to Upload Image ================
def uploadImg():
filename = filedialog.askopenfilename(initialdir = "/",title = "Select an Image",filetype = (("jpeg files","*.jpg"),("PNG files","*.png")))
image = Image.open(filename) # Read the Image
resize_image = image.resize((200,150)) # Reszie the image using resize() method
show_img = ImageTk.PhotoImage(resize_image) # create label and to add the resize image
var_photo = Label(img_LabelFrame,image=show_img)
var_photo.image = show_img
var_photo.pack()
#==========Method to add The Name and Image to Database ================
def add():
con=sqlite3.connect(database="std.db")
cur=con.cursor()
try:
if var_name.get()=="":
messageBox.showerror("Error","Student Name is required")
else:
cur.execute("select * from std where name =? ",( var_name.get(),) )
row=cur.fetchone()
if row!=None:
messageBox.showerror("Error","Student name is already exists")
else:
cur.execute("insert into std (name,photo) values (?,?)",(
var_name.get(),var_photo.get()
))
con.commit()
messageBox.showinfo("Success","Student Add Successfully")
except Exception as ex:messageBox.showerror("Error",f"Error duo to {str(ex)}")
#==========Entry Fileds ================
bl_Name=Label(root,text="Student Name:",font= ("Arial",15,)).place(x=10,y=40 )
En_Name= Entry( textvariable=var_name,),bg="lightyellow" ).place(x=150,y=40,width=250)
lbl_Std_photo = Label(root,text="Student Photo: ",y=90 )
img_LabelFrame = ttk.LabelFrame(root,text="")
img_LabelFrame.place(x=150,y=90,width=200,height=150)
btn_upload_img = Button(text="Upload Image",bg="green",command= uploadImg).place(x=200,y=280,width= 150,height=40)
btn_save = Button( text="Save",command=add).place(x=200,y=330,height=40)
mainloop()
解决方法
尝试改变这个:
def uploadImg():
...
show_img = ImageTk.PhotoImage(resize_image)
var_photo = Label(img_LabelFrame,image=show_img)
var_photo.image = show_img
var_photo.pack()
进入这个:
var_photo_list = []
def uploadImg():
...
show_img = ImageTk.PhotoImage(resize_image)
var_photo = Label(img_LabelFrame,image=show_img)
var_photo.image = show_img
var_photo.pack()
var_photo_list.append(var_photo)
这可确保 var_photo
不会超出范围。如果 var_photo
超出范围,show_img
也会超出范围并被 python 删除。所以它也从 tkinter
世界消失了。
在 var_photo
中使用的 uploadImg()
是一个局部变量,因此在 uploadImg()
中对其进行的任何更改都不会更新全局 var_photo
。因此,当执行 add()
时,var_photo.get()
将返回空字符串,因为它永远不会更新。
为了更新全局 var_photo
,您需要使用 var_photo.set()
。
我修改了你的代码:
-
把
var_photo = StringVar()
改成var_photo = Variable()
,这样就可以保存图片数据,即字节数据 -
在全局范围内创建
label_photo
并在uploadImg()
函数中使用它 -
添加代码将
resize_image
保存到var_photo
中,以便在add()
中使用它来将图像保存到数据库
from io import BytesIO
...
var_photo = Variable() # use Variable() instead of StringVar()
def uploadImg():
...
resize_image = image.resize((200,150))
show_img = ImageTk.PhotoImage(resize_image)
# show the resized image
label_photo.config(image=show_img)
label_photo.image = show_img
# save the image data into var_photo
outfile = BytesIO()
resize_image.save(outfile,"PNG")
var_photo.set(outfile.getvalue())
...
# create the label_photo inside img_LabelFrame
label_photo = Label(img_LabelFrame)
label_photo.pack()
...
从数据库中检索图像后,使用以下示例代码显示图像:
cur.execute("SELECT photo FROM std WHERE name = ?",(var_name.get(),))
row = cur.fetchone()
if row:
photo = ImageTk.PhotoImage(data=row[0])
label_photo.config(image=photo)
label_photo.image = photo