Upload Image by TKinter Filedialog functions and stored by another button

859 Views Asked by At

Simply, I upload image by tkinter.filedialog functions and wanted the image to be stored to the database simultaneous with the name I provide by clicking another the button, the name stored well but not the image.

Here is the code.

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 , font= ("Arial",15,), bg="lightyellow" ).place(x=150, y=40, width=250)

lbl_Std_photo = Label(root, text="Student Photo: ", font= ("Arial",15,)).place(x=10,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", bg="green", command=add).place(x=200, y=330, width= 150 , height=40)

mainloop()
2

There are 2 best solutions below

2
TheLizzard On

Try changing this:

def uploadImg():
    ...
    show_img = ImageTk.PhotoImage(resize_image)

    var_photo = Label(img_LabelFrame,image=show_img)
    var_photo.image = show_img
    var_photo.pack()

into this:

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)

This makes sure that var_photo doesn't go out of scope. If var_photo does out of scope, show_img also goes out of scope and is deleted by python. So it also disappears from the tkinter world.

0
acw1668 On

The var_photo used inside uploadImg() is a local variable so any change on it inside uploadImg() will not update the global var_photo. Therefore, when add() is executed, var_photo.get() will return empty string as it is never updated.

In order to update global var_photo, you need to use var_photo.set().

I have modified your code:

  • change var_photo = StringVar() to var_photo = Variable(), so it can hold the image data which is bytes data

  • create label_photo in global scope and use it inside uploadImg() function instead

  • add code to save resize_image into var_photo so that it can be used in add() to save the image to database

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()

...


After you retrieve the image from database, use below sample code to show the image:

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