Using Python, Tkinter, canvas ,and photoimage function with some threading
My webhost not allowing some file extension so need to put image as individually (sorry)
The images are for operator sequence , I tried to put them all in a zip but not allowed.
remember to update folder path to where the operator images are stored
Code (will also need the image files)
# -*- coding: utf-8 -*-
"""
Created on Thu Mar 30 08:29:16 2023
@author: aleja
"""
from tkinter import *
import math
import time
import os #for path filename join
import threading
Stop_Belt=1
UUT_is_on_belt=0
UUT_Pushed=0
Num_of_pass=0
Num_of_fail=0
Num_of_miss=0
Num_of_total_UUT=0
#GUI setup below
myWindow=Tk()
myWindow.title("myWindow")
myWindow.minsize(660,350)
myWindow.maxsize(660,350) #if you want to move the operator table to see rest of belt comment out
# do this or frame (last frame row number, in window will not follow window (expanding)
myWindow.grid_rowconfigure(1,weight=1) #Important This was the reason for on frame being stuck at bottom was row 0 but 3frames
myWindow.grid_columnconfigure(0,weight=1)
myWindow.configure(background='gray')
#frame1
# adjust r,c,sticky, row and column config as need
frame1=Frame(myWindow,width=200,height=200,bg='lightblue')
frame1.grid(row=0, column=0, sticky='NEWS', padx=10, pady=10, columnspan=2)
frame1.rowconfigure(0,weight=1)
frame1.columnconfigure(0,weight=1) #the lastcol goes along with rigth side expanding
#frame1
# adjust r,c,sticky, row and column config as need
frame2=Frame(myWindow,width=200,height=200,bg='lightblue')
frame2.grid(row=1, column=0, sticky='NEWS', padx=10, pady=10, columnspan=1)
frame2.rowconfigure(0,weight=1)
frame2.columnconfigure(3,weight=1) #the lastcol goes along with rigth side expanding
#Frame1 objects
#Conveyor belt
canv1=Canvas(frame1,width=190, height=190, bg='blue', bd=0, highlightthickness=0)
canv1.grid(row=0, column=0, columnspan=1,sticky="NEWS")
canv1.columnconfigure(0,weight=1)
#operator table
canv2=Canvas(frame1,width=250, height=250, bg='green', bd=0, highlightthickness=0)
canv2.grid(row=0, column=1, columnspan=2,sticky="NEWS")
canv2.columnconfigure(0,weight=1)
#LED1=canv1.create_oval(LTRX,LTRY,LTRX+dia,LTRY+dia,fill='orange')
location_down=20
Belt=canv1.create_rectangle(50,10+location_down,500,150+location_down,fill='orange')
#Solenoid to push UUT to pass bin
location_down_sp=15
sp_x1=220
sp_y1=10
sp_width=50
sp_height=20
Solenoid_Pass_Push=canv1.create_rectangle(sp_x1,sp_y1+location_down_sp,sp_x1+sp_width,sp_y1+sp_height+location_down_sp,fill='green')
#Solenoid to push UUT to fail bin
location_down_sf=15
sf_x1=110
sf_y1=10
sf_width=50
sf_height=20
Solenoid_Fail_Push=canv1.create_rectangle(sf_x1,sf_y1+location_down_sf,sf_x1+sp_width,sf_y1+sf_height+location_down_sf,fill='red')
#UUT is hiding under table ready for move
UUT_x1=460
UUT_y1=80
UUT_x2=490
UUT_y2=130
UUT_on_belt=canv1.create_rectangle(UUT_x1,UUT_y1,UUT_x2,UUT_y2,fill='lightgreen')
UUT_On_Belt=0
#after UUT so its top layer
#location of pass bin to collect UUT
pbinx1=sp_x1-30
pbiny1=200
pbin_width=50+50
pbin_height=70
Pass_Bin=canv1.create_rectangle(pbinx1,pbiny1,pbinx1+pbin_width,pbiny1+pbin_height,fill='green')
Pass_Bin_Label=canv1.create_text(pbinx1+50,pbiny1+20,fill="white",text="Pass Bin")
Pass_Bin_count=canv1.create_text(pbinx1+50,pbiny1+40,fill="white",text="0")
#canv1.itemconfig(Pass_Bin_count,text="1") #this is how to change text after create
#after UUT so its top layer
#location of pass bin to collect UUT
fbinx1=sf_x1-30
fbiny1=200
fbin_width=50+50
fbin_height=70
Fail_Bin=canv1.create_rectangle(fbinx1,fbiny1,fbinx1+fbin_width,fbiny1+fbin_height,fill='red')
Fail_Bin_Label=canv1.create_text(fbinx1+50,fbiny1+20,fill="darkblue",text="Fail Bin")
Fail_Bin_count=canv1.create_text(fbinx1+50,fbiny1+40,fill="darkblue",text="0")
Missed_Bin_Label=canv1.create_text(fbinx1-40,fbiny1+20,fill="white",text="Missed Bin")
Missed_Bin_count=canv1.create_text(fbinx1-40,fbiny1+40,fill="white",text="0")
#------------starting image------------------------------
#if you get pyimageN you may need to close the ipython console an try again
folder_for_image='C:/python/Python Move Object/images_ProductionLine/' #where you put your images for this project
imagepath=os.path.join(folder_for_image,"PersonTopViewProductionLine_NorthUUT.png")
print(imagepath)
img_Operator1=PhotoImage(file=(imagepath))
#image of operator
Operator1=canv2.create_image(130,160,image=img_Operator1)
Operator_label=canv2.create_text(fbinx1+50,fbiny1+20,fill="white",text="Operator Count")
Operator_count=canv2.create_text(fbinx1+50,fbiny1+40,fill="white",text="0")
#------------------------------------------------------
def Operator_Put_UUT_On_Belt():
global Stop_Belt
global UUT_is_on_belt
global Num_of_total_UUT
START_Operator['state']="disabled"
Start_Belt['state']="disabled"
Put_UUT_On_Belt_File_List=["PersonTopViewProductionLine_NorthUUT.png",\
"PersonTopViewProductionLine_NorthUUT_10West.png",\
"PersonTopViewProductionLine_NorthUUT_20West.png",\
"PersonTopViewProductionLine_NorthUUT_30West.png",\
"PersonTopViewProductionLine_NorthUUT_40West.png",\
"PersonTopViewProductionLine_NorthUUT_50West.png",\
"PersonTopViewProductionLine_NorthUUT_60West.png",\
"PersonTopViewProductionLine_NorthUUT_70West.png",\
"PersonTopViewProductionLine_NorthUUT_90West.png"] #yes i forget a 80 image
Back_For_Next_UUT_List=["PersonTopViewProductionLine_NorthUUT_90West.png",\
"PersonTopViewProductionLine_NorthUUT_90West_NoUUT.png",\
"PersonTopViewProductionLine_NorthUUT_80West_NoUUT.png",\
"PersonTopViewProductionLine_NorthUUT_70West_NoUUT.png",\
"PersonTopViewProductionLine_NorthUUT_60West_NoUUT.png",\
"PersonTopViewProductionLine_NorthUUT_50West_NoUUT.png",\
"PersonTopViewProductionLine_NorthUUT_40West_NoUUT.png",\
"PersonTopViewProductionLine_NorthUUT_30West_NoUUT.png",\
"PersonTopViewProductionLine_NorthUUT_20West_NoUUT.png",\
"PersonTopViewProductionLine_NorthUUT_10West_NoUUT.png",\
"PersonTopViewProductionLine_NorthUUT_0West_NoUUT.png",\
"PersonTopViewProductionLine_NorthUUT.png"] #yes i forget a 80 image
for imageFile in Put_UUT_On_Belt_File_List:
img_Operator1.config(file=os.path.join(folder_for_image,imageFile)) #do NOT make another PhotoImage
myWindow.update()
time.sleep(.2)
print("Operator moving to Belt with UUT") #temp slow down
print("UUT drop to conveyor belt")
canv1.coords(UUT_on_belt,UUT_x1,UUT_y1,UUT_x2,UUT_y2)
UUT_is_on_belt=1
Num_of_total_UUT=Num_of_total_UUT+1
print("Operator reported total UUT:",Num_of_total_UUT)
canv2.itemconfig(Operator_count,text=str(Num_of_total_UUT))
for imageFile in Back_For_Next_UUT_List:
img_Operator1.config(file=os.path.join(folder_for_image,imageFile)) #do NOT make another PhotoImage
myWindow.update()
time.sleep(.2)
print("Operator moving back for next UUT") #temp slow down
#start with button enabled=normal
START_Operator['state']="disabled"
Start_Belt['state']="normal"
Stop_Belt=0 #enable belt ok to move
print("UUT_is_on_belt",UUT_is_on_belt, "UUT pushed",UUT_Pushed)
return
def Move_UUT_On_Belt():
global Stop_Belt
global UUT_Pushed
global UUT_is_on_belt
global Num_of_miss
START_Operator['state']="disabled"
Start_Belt['state']="disabled"
for UUT_Location in range(UUT_x1-40):
if(Stop_Belt==0):
if(UUT_is_on_belt==0): break
canv1.coords(UUT_on_belt,UUT_x1-UUT_Location,UUT_y1,UUT_x2-UUT_Location,UUT_y2)
myWindow.update()
print("Belt is Moving ",UUT_Location)
time.sleep(.01)
if(UUT_is_on_belt==1):
canv1.coords(UUT_on_belt,UUT_x1,UUT_y1,UUT_x2,UUT_y2)
myWindow.update()
START_Operator['state']="normal"
Start_Belt['state']="disabled"
if (UUT_Location==(UUT_x1-40-1) and UUT_is_on_belt==1 and UUT_Pushed==0):
Num_of_miss=Num_of_miss+1
print("miss bin total: ",Num_of_miss)
canv1.itemconfig(Missed_Bin_count,text=str(Num_of_miss))
UUT_is_on_belt=0
print("Belt Stop")
print("UUT_is_on_belt",UUT_is_on_belt, "UUT pushed",UUT_Pushed)
return
def Move_PassPush():
UUT_coords=[]
Start_PassPush['state']="disabled"
global Stop_Belt
global UUT_is_on_belt
global location_down_sp
global Num_of_pass
global UUT_Pushed
Stop_Belt=1 #stop belt on any push attempt
for PassPushy in range(35):
canv1.coords(Solenoid_Pass_Push,sp_x1,sp_y1+location_down_sp+PassPushy,sp_x1+sp_width,sp_y1+sp_height+location_down_sp+PassPushy)
myWindow.update()
print("Pass Push ",PassPushy)
time.sleep(0.001)
location_down_sp=location_down_sp+40
print("get UUT position")
print(canv1.coords(UUT_on_belt))
UUT_coords=canv1.coords(UUT_on_belt)
# using thread so same time as push UUT_Move_to_bin(UUT_coords)
if (sp_x1<=UUT_coords[2] and UUT_coords[0]<=sp_x1+sp_width and UUT_is_on_belt==1): #check uut in pass push width
threading.Thread(target=UUT_Move_to_bin,args=(UUT_coords,)).start()#create and start same line
Stop_Belt=1
UUT_Pushed=1
Num_of_pass=Num_of_pass+1
print("Number of Pass UUT: ", Num_of_pass)
canv1.itemconfig(Pass_Bin_count,text=str(Num_of_pass))
else:
Stop_Belt=0
for PassPushy in range(35):
canv1.coords(Solenoid_Pass_Push,sp_x1,sp_y1+location_down_sp-PassPushy,sp_x1+sp_width,sp_y1+sp_height+location_down_sp-PassPushy)
myWindow.update()
print("Pass Push ",PassPushy)
time.sleep(0.001)
location_down_sp=location_down_sp-40
canv1.coords(Solenoid_Pass_Push,sp_x1,sp_y1+location_down_sp,sp_x1+sp_width,sp_y1+sp_height+location_down_sp)
myWindow.update()
if(UUT_Pushed==1):
Stop_Belt=1
else:
Stop_Belt=0#continue moving UUT left
Start_PassPush['state']="normal"
UUT_Pushed=0
print("UUT_is_on_belt",UUT_is_on_belt, "UUT pushed",UUT_Pushed)
return
#next put all changes dont on passpush into failPush
def Move_FailPush():
UUT_coords=[]
global Stop_Belt
global UUT_is_on_belt
global location_down_sf
global Num_of_fail
global UUT_Pushed
Start_FailPush['state']="disabled"
Stop_Belt=1
for FailPushy in range(35):
canv1.coords(Solenoid_Fail_Push,sf_x1,sf_y1+location_down_sf+FailPushy,sf_x1+sf_width,sf_y1+sf_height+location_down_sf+FailPushy)
myWindow.update()
print("Fail Push ",FailPushy)
time.sleep(0.001)
location_down_sf=location_down_sf+40
#Move UUT down
print("get UUT position")
print(canv1.coords(UUT_on_belt))
UUT_coords=canv1.coords(UUT_on_belt)
# using thread so same time as push UUT_Move_to_bin(UUT_coords)
if (sf_x1<=UUT_coords[2] and UUT_coords[0]<=sf_x1+sf_width and UUT_is_on_belt==1): #check uut in pass push width
threading.Thread(target=UUT_Move_to_bin,args=(UUT_coords,)).start()#create and start same line
Stop_Belt=1
UUT_Pushed=1
Num_of_fail=Num_of_fail+1
print("Number of Fail UUT: ", Num_of_fail)
canv1.itemconfig(Fail_Bin_count,text=str(Num_of_fail))
else:
Stop_Belt=0 #continue belt
#Return Fail Push back
for FailPushy in range(35):
canv1.coords(Solenoid_Fail_Push,sf_x1,sf_y1+location_down_sf-FailPushy,sf_x1+sf_width,sf_y1+sf_height+location_down_sf-FailPushy)
myWindow.update()
print("Fail Push ",FailPushy)
time.sleep(0.001)
location_down_sf=location_down_sf-40
canv1.coords(Solenoid_Fail_Push,sf_x1,sf_y1+location_down_sf,sf_x1+sf_width,sf_y1+sf_height+location_down_sf)
myWindow.update()
if(UUT_Pushed==1):
Stop_Belt=1
else:
Stop_Belt=0#continue moving UUT left
Start_FailPush['state']="normal"
UUT_Pushed=0
print("UUT_is_on_belt",UUT_is_on_belt, "UUT pushed",UUT_Pushed)
return
def UUT_Move_to_bin(UUT_coords):
global UUT_is_on_belt
UUT_is_on_belt=0
for UUT_down_y in range(100):
canv1.coords(UUT_on_belt,UUT_coords[0],UUT_coords[1]+UUT_down_y,UUT_coords[2],UUT_coords[3]+UUT_down_y)
time.sleep(0.001)
myWindow.update()
UUT_is_on_belt=0
print("UUT is off Belt")
return
Start_Belt=Button(frame2, text='START_Belt',width=15, command=lambda:Move_UUT_On_Belt())
Start_Belt.grid(row=1, column=0,padx=10,pady=10,sticky='')
Start_FailPush=Button(frame2, text='START_Fail_Push',width=15, command=lambda:Move_FailPush())
Start_FailPush.grid(row=1, column=1,padx=10,pady=10,sticky='')
Start_PassPush=Button(frame2, text='START_Pass_Push',width=15, command=lambda:Move_PassPush())
Start_PassPush.grid(row=1, column=2,padx=10,pady=10,sticky='')
START_Operator=Button(frame2, text='START_Operator',width=15, command=lambda:Operator_Put_UUT_On_Belt())
START_Operator.grid(row=1, column=3,padx=10,pady=10,sticky='E')
#start with button enabled=normal
START_Operator['state']="normal"
Start_Belt['state']="disabled"
#last Line
myWindow.mainloop()
download for python code incase select all text not available.
Download for operator images
Unzip the images of the operator to a folder and make sure to update the folder path in the python code.
I used spyder python ide if you forget to make the folder correct you may have to close the ipython console , fix the path and try again. Something in the PhotoImage in tkinter does not clean up correct when there is a python error. So i have to close the console part in the ide fix and rerun.
Notes
- Presentation: example GUI Production Line with Operator, Conveyor belt and Pass Fail plunger and counts
- Programming Language used: Python 3.7 in Spyder
- Presentation app: Microsoft’s PowerPoint,Paint,3D Paint for transparent images
- Python and Tkinter are product of respective company
- Presentation shown to spark ideas of use.
- This presentation is not connected to or endorsed by any company.
- Use at your own risk.
- Tags: Python, Python3.7, Tkinter , Canvas ,GUI, Sequence of Image, PhotoImage, Thread, Threading