Reputation: 15
Okay, so I'm trying to put together a really simple app that essentially just takes a scanned barcode value, which is tied to an image file, and goes into a dictionary of images, finds the image whose key matches the barcode value, and displays that image in the Tkinter window.
I actually got it working consistently when just using a raw input() value, but when I tried to incorporate an Entry box into the window to take the barcode value, that's when I ran into problems.
I want the Entry widget to kick off a function whenever it's edited, so that all that needs to be done is scan the barcode and the image will appear. I looked up solutions to this and the most common one I found was to use a StringVar, tie it to the Entry widget, and then use .trace() to kick off the desired function whenever the value in the Entry widget is altered.
The snag is that whenever I scan the barcode into the Entry box, I get the following error:
Exception in Tkinter callback
Traceback (most recent call last):
File "c:\program files\python37\Lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
TypeError: 'NoneType' object is not callable
This is my full code. I tried to comment out and explain the process as best I could. Naturally, it won't be able to grab the image files and populate the dictionary with them, but hopefully just looking at it, you'll be able to tell me where I went wrong.
from PIL import Image
from PIL import ImageTk as itk
import tkinter as tk
import cv2
import glob
import os, os.path
# INITIALIZE TKINTER WINDOW #
window = tk.Tk()
window.title('Projector Test')
#window.overrideredirect(1)
# Function to kick off whenever Tkinter Entry value is edited. Grabs value of StringVar and assigns it to variable 'barcode'. Checks to see if the barcode
# value is in 'images' dictionary. If so, grab image and display on Tkinter Canvas. If not, display Error message image.
def barcodeScanImage():
barcode = str(sv.get())
if barcode in images:
image_file = images.get(barcode)
scanImage = itk.PhotoImage(image_file)
width, height = image_file.size
canvas.create_image(0, 0, image = scanImage, anchor = tk.NW)
else:
image_file = images.get('error.gif')
errorImage = itk.PhotoImage(image_file)
width, height = image_file.size
canvas.create_image(0, 0, image = errorImage, anchor = tk.NW)
# Create Dictionary 'images' to store image files in. #
images = {}
# Iterate through projectorImages folder in directory and store each image found there in the 'images' dictionary, with its Key as its filename. #
for filename in os.listdir('projectorImages\\'):
image = Image.open(os.path.join('projectorImages\\', filename))
images[filename] = image
# Create startImage variable. Use .size function to get its width and height, which will be plugged into the tk.Canvas width and height arguments.
# This ensures the displayed image will be displayed in its entirety.
startImage = images.get('start.gif')
width, height = startImage.size
canvas = tk.Canvas(master = window, width = width, height = height)
# Create startImageReady variable reference to the same image file, using the itk.PhotoImage function to convert it into a readable format for Tkinter.
# Then, use canvas.create_image to actually display the image in the Tkinter canvas.
startImageReady = itk.PhotoImage(images.get('start.gif'))
canvas.pack()
canvas.create_image(0, 0, image = startImageReady, anchor = tk.NW)
sv = tk.StringVar()
entry = tk.Entry(master = window, textvariable = sv)
sv.trace("w", callback = barcodeScanImage())
entry.pack()
window.mainloop()
Thanks much for your time. I've been trying to figure out what's causing this issue, but I'm at the end of my beginner's rope! Lol
Upvotes: 0
Views: 1048
Reputation: 386285
Consider this line of code:
sv.trace("w", callback = barcodeScanImage())
It is functionally identical to this code:
result = barcodeScanImage()
sv.trace("w", callback=result)
Since barcodeScanImage()
returns None
, it's the same as this:
sv.trace("w", callback=None)
When you call trace
, you must give it a reference to a function (note the missing ()
):
sv.trace("w", callback=barcodeScanImage)
However, when you set up a trace, tkinter will pass some additional arguments to the function which you need to be prepared to accept. Since you're not using them, you can just ignore them:
def barcodeScanImage(*args):
...
For more information on the arguments that are passed in, see this question: What are the arguments to Tkinter variable trace method callbacks?
Upvotes: 3