How do I use the same mp3 file more then once? - python

import tkinter as tk
from tkinter import filedialog
from pygame import mixer
mixer.init()
firsttime = False
song2switch = True
root = tk.Tk()
canvas = tk.Canvas(root, width=400, height=250)
canvas.pack()
def loadsong1():
global song1
song1 = tk.filedialog.askopenfile(parent=root, initialdir="C:/",title="choose first song",filetypes=[("mp3 files", ".mp3")])
def loadsong2():
global song2
song2 = tk.filedialog.askopenfile(parent=root, initialdir="C:/",title="choose second song",filetypes=[("mp3 files", ".mp3")])
def play():
mixer.music.load(song1)
mixer.music.play()
def switch():
global firsttime
global song2switch
global time_of_song
if firsttime == False:
time_of_song = mixer.music.get_pos()
time_of_song /= 1000
mixer.music.stop()
mixer.music.load(song2)
mixer.music.play(start = time_of_song)
firsttime = True
song2switch = False
else:
if song2switch == False:
time_of_song = mixer.music.get_pos()
time_of_song /= 1000
mixer.music.stop()
mixer.music.load(song1)
mixer.music.play(start = time_of_song)
song2switch = True
playbutton = tk.Button(canvas,text="PLAY",command=play)
canvas.create_window(200,240,window=playbutton)
load1button = tk.Button(canvas, text="Load Song One",command=loadsong1)
canvas.create_window(100,240,window=load1button)
load2button = tk.Button(canvas, text="Load Song Two", command=loadsong2)
canvas.create_window(300,240,window=load2button)
switchbutton = tk.Button(canvas, text="SWITCH", command=switch)
canvas.create_window(200,200, window=switchbutton)
root.mainloop()
I'm trying to make this music player that can switch between two songs while keeping the same time between each other (for example, when I switch a song that has been playing for a minute, the other will start a minute in), but when i try to switch it to the first song, it makes this error:
pygame.error: Couldn't read first 12 bytes of audio data
How do I fix this?

It is because you have used askopenfile(...) which will open the selected file in read mode and return the file handle.
When you switch to song2, song1 is closed. When you want to switch back to song1 again, mixer.music.load(song1) will fail with exception because the file is already closed.
Use askopenfilename() instead of askopenfile().
Note 1: mixer.music.get_pos() returns the elapsed time relative to start, not the beginning.
Note 2: your switching logic will not work properly after switching two times.

Related

VLC causes buffer when embedded in Python Tkinter Frame

I have been working on a music player app that uses VLC to play songs directly from the internet and has features like seeking and a progress bar. But as the normal tkinter progress bar looks kinda old so I used customtkinter.CTkSlider widget but using this causes buffering. The song plays smoothly on using Tk.Scale.
Here, is the code:
# import external libraries
import vlc
import tkinter as Tk
from tkinter import ttk
import pyautogui
import customtkinter
import pafy
# import standard libraries
import os
from threading import Thread, Event
import time
import platform
import requests
class ttkTimer(Thread):
"""a class serving same function as wxTimer... but there may be better ways to do this
"""
def __init__(self, callback, tick):
Thread.__init__(self)
self.callback = callback
self.stopFlag = Event()
self.tick = tick
self.iters = 0
def run(self):
while not self.stopFlag.wait(self.tick):
self.iters += 1
self.callback()
def stop(self):
self.stopFlag.set()
def get(self):
return self.iters
class Player(Tk.Frame):
"""The main window has to deal with events.
"""
def __init__(self, parent, title=None):
Tk.Frame.__init__(self, parent)
self.parent = parent
if title == None:
title = "tk_vlc"
self.parent.title(title)
# Menu Bar
# File Menu
menubar = Tk.Menu(self.parent)
self.parent.config(menu=menubar)
fileMenu = Tk.Menu(menubar)
fileMenu.add_command(label="Open", underline=0, command=self.OnOpen)
fileMenu.add_command(label="Exit", underline=1, command=_quit)
menubar.add_cascade(label="File", menu=fileMenu)
# The second panel holds controls
self.player = None
self.videopanel = ttk.Frame(self.parent)
self.canvas = Tk.Canvas(self.videopanel).pack(fill=Tk.BOTH,expand=1)
self.videopanel.pack(fill=Tk.BOTH,expand=1)
ctrlpanel = ttk.Frame(self.parent)
pause = ttk.Button(ctrlpanel, text="Pause", command=self.OnPause)
play = ttk.Button(ctrlpanel, text="Play", command=self.OnPlay)
stop = ttk.Button(ctrlpanel, text="Stop", command=self.OnStop)
volume = ttk.Button(ctrlpanel, text="Volume", command=self.OnSetVolume)
pause.pack(side=Tk.LEFT)
play.pack(side=Tk.LEFT)
stop.pack(side=Tk.LEFT)
volume.pack(side=Tk.LEFT)
self.volume_var = Tk.IntVar()
self.volslider = Tk.Scale(ctrlpanel, variable=self.volume_var, command=self.volume_sel,
from_=0, to=100, orient=Tk.HORIZONTAL, length=100)
self.volslider.pack(side=Tk.LEFT)
ctrlpanel.pack(side=Tk.BOTTOM)
ctrlpanel2 = ttk.Frame(self.parent)
self.scale_var = Tk.DoubleVar()
self.timeslider_last_val = ""
self.timeslider = customtkinter.CTkSlider(ctrlpanel2, variable=self.scale_var, command=self.scale_sel,
from_=0, to=1000, orient=Tk.HORIZONTAL) # This causes buffer
self.timeslider.pack(side=Tk.BOTTOM, fill=Tk.X,expand=1)
self.timeslider_last_update = time.time()
ctrlpanel2.pack(side=Tk.BOTTOM,fill=Tk.X)
# VLC player controls
self.Instance = vlc.Instance()
self.player = self.Instance.media_player_new()
self.timer = ttkTimer(self.OnTimer, 1.0)
self.timer.start()
self.parent.update()
#self.player.set_hwnd(self.GetHandle()) # for windows, OnOpen does does this
def Extract(self,topic):
"""Will play video on following topic, takes about 10 to 15 seconds to load"""
url = 'https://www.youtube.com/results?q=' + topic
count = 0
cont = ''
try:
cont = requests.get(url)
except:
print('Error','Cannot Connect.. Internet not connected or invalid URL or id.')
cont = ''
data = cont.content
data = str(data)
lst = data.split('"')
for i in lst:
count+=1
if i == 'WEB_PAGE_TYPE_WATCH':
break
if lst[count-5] == "/results":
print("Error","No video found.")
return "https://www.youtube.com"+lst[count-5]
def OnExit(self, evt):
"""Closes the window.
"""
self.Close()
def OnOpen(self):
"""Pop up a new dialow window to choose a file, then play the selected file.
"""
# if a file is already running, then stop it.
self.OnStop()
fullname = pafy.new(self.Extract(pyautogui.password(mask="", title="Enter Song Name:", text="Enter Song Name:"))).getbest().url
self.Media = self.Instance.media_new(fullname)
self.player.set_media(self.Media)
# set the window id where to render VLC's video output
if platform.system() == 'Windows':
self.player.set_hwnd(self.GetHandle())
else:
self.player.set_xwindow(self.GetHandle()) # this line messes up windows
# FIXME: this should be made cross-platform
self.OnPlay()
# set the volume slider to the current volume
#self.volslider.SetValue(self.player.audio_get_volume() / 2)
self.volslider.set(self.player.audio_get_volume())
def OnPlay(self):
"""Toggle the status to Play/Pause.
If no file is loaded, open the dialog window.
"""
# check if there is a file to play, otherwise open a
# Tk.FileDialog to select a file
if not self.player.get_media():
self.OnOpen()
else:
# Try to launch the media, if this fails display an error message
if self.player.play() == -1:
self.errorDialog("Unable to play.")
def GetHandle(self):
return self.videopanel.winfo_id()
#def OnPause(self, evt):
def OnPause(self):
"""Pause the player.
"""
self.player.pause()
def OnStop(self):
"""Stop the player.
"""
self.player.stop()
# reset the time slider
self.timeslider.set(0)
def OnTimer(self):
"""Update the time slider according to the current movie time.
"""
if self.player == None:
return
# since the self.player.get_length can change while playing,
# re-set the timeslider to the correct range.
length = self.player.get_length()
dbl = length * 0.001
self.timeslider.config(to=dbl)
# update the time on the slider
tyme = self.player.get_time()
if tyme == -1:
tyme = 0
dbl = tyme * 0.001
self.timeslider_last_val = ("%.0f" % dbl) + ".0"
# don't want to programatically change slider while user is messing with it.
# wait 2 seconds after user lets go of slider
if time.time() > (self.timeslider_last_update + 2.0):
self.timeslider.set(dbl)
def scale_sel(self, evt):
if self.player == None:
return
nval = self.scale_var.get()
sval = str(nval)
if self.timeslider_last_val != sval:
self.timeslider_last_update = time.time()
mval = "%.0f" % (nval * 1000)
self.player.set_time(int(mval)) # expects milliseconds
def volume_sel(self, evt):
if self.player == None:
return
volume = self.volume_var.get()
if volume > 100:
volume = 100
if self.player.audio_set_volume(volume) == -1:
self.errorDialog("Failed to set volume")
def OnToggleVolume(self, evt):
"""Mute/Unmute according to the audio button.
"""
is_mute = self.player.audio_get_mute()
self.player.audio_set_mute(not is_mute)
# update the volume slider;
# since vlc volume range is in [0, 200],
# and our volume slider has range [0, 100], just divide by 2.
self.volume_var.set(self.player.audio_get_volume())
def OnSetVolume(self):
"""Set the volume according to the volume sider.
"""
volume = self.volume_var.get()
# vlc.MediaPlayer.audio_set_volume returns 0 if success, -1 otherwise
if volume > 100:
volume = 100
if self.player.audio_set_volume(volume) == -1:
self.errorDialog("Failed to set volume")
def errorDialog(self, errormessage):
"""Display a simple error dialog.
"""
Tk.tkMessageBox.showerror(self, 'Error', errormessage)
def Tk_get_root():
if not hasattr(Tk_get_root, "root"): #(1)
Tk_get_root.root= Tk.Tk() #initialization call is inside the function
return Tk_get_root.root
def _quit():
print("_quit: bye")
root = Tk_get_root()
root.quit() # stops mainloop
root.destroy() # this is necessary on Windows to prevent
# Fatal Python Error: PyEval_RestoreThread: NULL tstate
os._exit(1)
if __name__ == "__main__":
# Create a Tk.App(), which handles the windowing system event loop
root = Tk_get_root()
root.protocol("WM_DELETE_WINDOW", _quit)
player = Player(root, title="tkinter vlc")
# show the player window centred and run the application
root.mainloop()
Kindly help
Regards.

Timer that prints elapsed time and resets with a button click

I have a GUI where the user can click a button named "next set" that allows them to move onto the next task. I wanted to add a timer that starts as soon as they start the application and run the timer until they press the button "next set". When clicked, I want the time elapsed to print and the timer to restart until they press "next set" button again. I would like the timer to start automatically when the code runs. Currently, the "next set" button has two actions, one is to retrieve the next set of images and the other action I am trying to include is to reset the timer and print time elapsed. I also only included part of the code that felt relevant because it is long.
import time
import tkinter as tk
import csv
from pathlib import Path
import PIL.Image
import PIL.ImageDraw
import PIL.ImageTk
MAX_HEIGHT = 500
IMAGES_PATH = Path("Images")
CSV_LABELS_KEY = "New Labels"
CSV_FILE_NAME_KEY = "FolderNum_SeriesNum"
CSV_BOUNDING_BOX_KEY = "correct_flip_bbox"
counter = 0
timer_id = None
class App(tk.Frame):
def __init__(self, master=None):
super().__init__(master) # python3 style
self.config_paths = ["config 1.yaml", "config 2.yaml", "config 3.yaml"]
self.config_index = 0
self.clickStatus = tk.StringVar()
self.loadedImages = dict()
self.loadedBoxes = dict() # this dictionary will keep track of all the boxes drawn on the images
self.master.title('Slideshow')
frame = tk.Frame(self)
tk.Button(frame, text=" Next set ", command=lambda:[self.get_next_image_set(), self.reset()]).pack(side=tk.RIGHT)
tk.Button(frame, text=" Exit ", command=self.destroy).pack(side=tk.RIGHT)
frame.pack(side=tk.TOP, fill=tk.BOTH)
self.canvas = tk.Canvas(self)
self.canvas.pack()
self._load_dataset()
self.reset()
self.start_timer = None
t = time()
t.start()
def start_timer(self, evt=None):
if self._start_timer is not None:
self._start_timer = time.perf_counter()
# global counter
# counter += 1
# label.config(text=str(counter))
# label.after(1000, count)
def reset(self):
if self._start_timer is None:
elapsed_time = time.perf_counter() - self._start_timer
self._start_timer = None
print('Time elapsed (hh:mm:ss.ms) {}'.format(elapsed_time))
def _load_dataset(self):
try:
config_path = self.config_paths[self.config_index]
self.config_index += 1
except IndexError:
return
image_data = loadData(config_path)
# drawing the image on the label
self.image_data = image_data
self.currentIndex = 0
# start from 0th image
self._load_image()
def _load_image(self):
imgName = self.image_data[self.currentIndex]['image_file']
if imgName not in self.loadedImages:
self.im = PIL.Image.open(self.image_data[self.currentIndex]['image_file'])
ratio = MAX_HEIGHT / self.im.height
# ratio divided by existing height -> to get constant amount
height, width = int(self.im.height * ratio), int(self.im.width * ratio)
# calculate the new h and w and then resize next
self.canvas.config(width=width, height=height)
self.im = self.im.resize((width, height))
if self.im.mode == "1":
self.img = PIL.ImageTk.BitmapImage(self.im, foreground="white")
else:
self.img = PIL.ImageTk.PhotoImage(self.im)
imgData = self.loadedImages.setdefault(self.image_data[self.currentIndex]['image_file'], dict())
imgData['image'] = self.img
imgData['shapes'] = self.image_data[self.currentIndex]['shapes']
# for next and previous so it loads the same image adn don't do calculations again
self.img = self.loadedImages[self.image_data[self.currentIndex]['image_file']]['image']
self.canvas.create_image(0, 0, anchor=tk.NW, image=self.img)
self.show_drag_box()
def loadData(fname):
with open(fname, mode='r') as f:
return yaml.load(f.read(), Loader=yaml.SafeLoader)
if __name__ == "__main__":
data = loadData('config 1.yaml')
app = App(data)
app.pack() # goes here
app.mainloop()
I have used datetime instead of time, as subtracting two datetime objects will give an output with hours and minutes included, whereas subtracting two time objects only gives seconds. However, both will work, you may just need to do more reformatting using time.
Read the current time when the application starts and store it. Each time you press the button, subtract your stored time from the current time which gives you your time elapsed. Then simply store your new current time until the next button press. The code below demonstrates this.
import tkinter as tk
import datetime as dt
class TimeButton(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
# Start timer
self.current_time = dt.datetime.today()
# Button
self.next_set = tk.Button(self, text='Next Set', command = self.clicked)
self.next_set.pack()
def clicked(self):
now = dt.datetime.today()
time_elapsed = now - self.current_time
print(time_elapsed)
self.current_time = now
if __name__ == "__main__":
window = tk.Tk()
button = TimeButton(window)
button.pack()
window.mainloop()

Play mp4 video in python with GUI

I want to create a photo booth with a simple sequence. I used mp4 files as animations.
Everything has to start in GUI with a button "start" that will run a loop for users. Exit to GUI will be by pressing the esc key.
In the "user" loop there will be a start animation as mp4 video -in omx player, working over and over until the user touches the touch screen. I already did this with listener move_mouse to kill the process.
I then have another animation with a countdown after which the camera takes a picture and then displays the photo on the screen in a window with two buttons repeat or print.
The problem with the listener is it freezes the application after capturing the photo
How can I solve this problem?
try:
from Tkinter import * # Python2
except ImportError:
import tkinter as Tk # Python3import Tkinter as tk
import sys
from time import sleep
from PIL import Image, ImageTk
from datetime import datetime
from sh import gphoto2 as gp
import signal, os, subprocess, glob
from pynput import mouse
from pynput import keyboard
shot_date = datetime.now() .strftime("%Y-%m-%d")
shot_time = datetime.now() .strftime("%Y-%m-%d %H:%M:%S")
picID = "PIShots"
folder_name = shot_date + picID
save_location = "/home/pi/Desktop/gphoto/images/" + folder_name
# listener
def on_move(x,y):
print("mouse move")
playerOff()
#pynput.mouse.Listener.stop
playerOn()
capturePhoto()
# press key listener
#def on_release(key):
# print('{0} released'.format(
# key))
# if key == keyboard.Key.esc:
# Stop listener
# return False
#StartAnmation and listener
def Start():
omxc= subprocess.Popen(['omxplayer','-b','--loop','--no-osd',"/home/pi/Desktop/START.mp4"])
with mouse.Listener(
on_move=on_move) as listener:
listener.join()
# get the latest file
def get_latest_file(path, *paths):
"""Returns the name of the latest (most recent) file
of the joined path(s)"""
fullpath = os.path.join(path, *paths)
files = glob.glob(fullpath) # You may use iglob in Python3
if not files: # I prefer using the negation
return None # because it behaves like a shortcut
latest_file = max(files, key=os.path.getctime)
_, filename = os.path.split(latest_file)
return filename
#start_animation in OMX player
def playerOn():
omxc= subprocess.Popen(['omxplayer','-b',"/home/pi/Desktop/animacja.mp4"])
#Player Off
def playerOff():
os.system('killall omxplayer.bin')
#CreateSaveFolder
def createSaveFolder():
try:
os.makedirs(save_location)
except:
print("Failed to create the new directory")
os.chdir(save_location)
def quit(root):
root.destroy()
def capturePhoto():
status = 0
createSaveFolder()
sleep(6)
os.system('fswebcam -r 1920x1080 -s brightness=70% -s gain=50% -S 10 --set lights=off --no-banner %H%M%S.jpg')
print save_location
location=get_latest_file(save_location,'*.jpg')
#print location
sciezkaZdj= save_location + "/" + location
print sciezkaZdj
im = Image.open(sciezkaZdj)
width, height =im.size
LEFT_HALF = 200, 0, width-400 ,height
im = im.crop(LEFT_HALF)
im = im.transpose(Image.ROTATE_270)
ramka = Image.open("/home/pi/Desktop/ramka1.jpg")
text_img = Image.new('RGBA', (1200,2000), (0, 0, 0, 0))
text_img.paste(ramka, (0,0))
text_img.paste(im, (50,30))
text_img.save("ramka.png", format="png")
path = save_location + "/ramka.png"
top2 = Toplevel(window)
top2.geometry("1600x720")
top2.overrideredirect(1)
top2.title("fotobudka")
top2.configure(background='black')
img = ImageTk.PhotoImage(Image.open(path))
panel = Label(top2, image = img)
panel.pack(side = "bottom", fill = "both", expand = "yes")
playerOff()
#close gui
window.after(5000, lambda: top2.destroy())
#************MAIN
if __name__ == "__main__":
try:
#Gui main*********************************
window = Tk()
top1 = Toplevel(window)
top1.geometry("1600x720")
# top1.wm_attributes('-topmost',1) #zawsze na wierzchu
top1.configure(background='black')
button_start = Button(window, text='start',command=Start)
button_start.pack()
window.mainloop()
#Gui main end******************************
except KeyboardInterrupt:
print "koniec"

Omxplayer-wrapper problems when run from terminal

I have the following program that I've been working on (I didn't create all of it, so some of it is pretty weird) on a Raspberry Pi. It's basically supposed to open up a tkinter window with buttons, and if you click the buttons in the right order, a new process will start. If the buttons are clicked in the wrong order, it will play a video. All of this works in Thonny IDE. (Really, the specifics of the program don't matter much other than the fact that it is using omxplayer-wrapper to play videos)
import os, subprocess
import RPi.GPIO as GPIO
import sys
import os
import tkinter as tk
from tkinter import *
from PIL import Image, ImageTk
import time
from omxplayer.player import OMXPlayer
from pathlib import Path
GPIO.setmode(GPIO.BCM)
# Variables
wrongOrder=False
desired_order=[1,2,3,8,9,10] #Desired order of clicking on images
click_num=0 #Number of clicks
videoPath = "MOV5.mp4"
loopPath = "loop2.mp4"
incorrectPath = "Incorrect Password.mp4"
secondVideoPath = "Access Denied.mp4"
secondLoopPath = "loop1.mp4"
GPIO.setup(20, GPIO.OUT, initial=GPIO.HIGH)
GPIO.setup(19, GPIO.OUT, initial=GPIO.HIGH)
GPIO.setup(18, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(2, GPIO.IN) #The input for when the power rod is removed (stop 1st looping video)
GPIO.setup(3, GPIO.IN) #The input for when to stop the 2nd looping video
# Actions taken when clicked on each image
def on_click1(event=None):
global IM
print("image1 clicked")
IM=1 #the image number
order(IM)
def on_click2(event=None):
global IM
print("image2 clicked")
IM=2
order(IM)
def on_click3(event=None):
global IM
print("image3 clicked")
IM=3
order(IM)
def on_click4(event=None):
global IM
print("image4 clicked")
IM=4
order(IM)
def on_click5(event=None):
global IM
print("image5 clicked")
IM=5
order(IM)
def on_click6(event=None):
global IM
print("image6 clicked")
IM=6
order(IM)
def on_click7(event=None):
global IM
print("image7 clicked")
IM=7
order(IM)
def on_click8(event=None):
global IM
print("image8 clicked")
IM=8
order(IM)
def on_click9(event=None):
global IM
print("image9 clicked")
IM=9
order(IM)
def on_click10(event=None):
global IM
print("image10 clicked")
IM=10
order(IM)
root = tk.Tk()
#Function when an image is clicked
def order(IM):
global click_num, wrongOrder
if (IM != desired_order[click_num]): #If this is not the right button
wrongOrder = True
click_num += 1
aCanvas.itemconfigure(asterisks, text = aCanvas.itemcget(asterisks, "text")+"*") #Adds an asterisk to the text
if (click_num == 6): #If it is the last number
if (wrongOrder):
print("Wrong Order!")
click_num = 0
wrongOrder = False
aCanvas.itemconfigure(asterisks, text = "") #Set text back to no asterisks
incorrectVideo()
else:
print("Correct Order!")
afterPassword()
def afterPassword():
playVideo()
time.sleep(11) #Wait before door opens
PIN() #play_video, pin low
time.sleep(8)
root.destroy()
playFirstLoop() #This will have to wait for a GPIO pin to change
playSecondVideo()
PIN2()#Trigger different relay
relayFlash()
piOutput() #Trigger other pi
playSecondLoop()
def PIN():
GPIO.setup(21, GPIO.OUT, initial=GPIO.LOW) # set GPIO21 as an output
#GPIO.output(21, 0) # set GPIO21 to 0/GPIO.LOW/True
def PIN2():
GPIO.output(20,0)
def playVideo():
player = OMXPlayer(videoPath, args=["--win", "0 0 1280 1024"])
def playFirstLoop():
player = OMXPlayer(loopPath, args=["--loop","--no-osd", "--win", "0 0 1280 1024"])
while(True):
if (GPIO.input(2)==False):
player.quit()
break
def playSecondVideo():
player = OMXPlayer(secondVideoPath, args=["--win", "0 0 1280 1024"])
player.quit()
def playSecondLoop():
player = OMXPlayer(secondLoopPath, args=["--loop","--no-osd", "--win", "0 0 1280 1024"])
while(True):
if (GPIO.input(3)==False):
player.quit()
break
def incorrectVideo():
player = OMXPlayer(incorrectPath, args=["--win", "0 0 1280 1024"], dbus_name='org.mpris.MediaPlayer2.omxplayer0')
time.sleep(2)
player.quit()
def relayFlash():
GPIO.output(19,0)
time.sleep(0.5)
for i in range(0,14):
GPIO.output(19,1)
time.sleep(0.5)
GPIO.output(19,0)
time.sleep(0.5)
GPIO.output(19,1)
def piOutput():
GPIO.output(18,1)
size_x=249
size_y = 350
#Screen resolution: 1245 x 1044
# load images
image1 = Image.open("/home/pi/Documents/1.jpg")
image1 = image1.resize((size_x, size_y), Image.ANTIALIAS)
photo1 = ImageTk.PhotoImage(image1)
image2 = Image.open("/home/pi/Documents/2.jpg")
image2 = image2.resize((size_x, size_y), Image.ANTIALIAS)
photo2 = ImageTk.PhotoImage(image2)
image3 = Image.open("/home/pi/Documents/3.jpg")
image3 = image3.resize((size_x, size_y), Image.ANTIALIAS)
photo3 = ImageTk.PhotoImage(image3)
image4 = Image.open("/home/pi/Documents/4.jpg")
image4 = image4.resize((size_x, size_y), Image.ANTIALIAS)
photo4 = ImageTk.PhotoImage(image4)
image5 = Image.open("/home/pi/Documents/5.jpg")
image5 = image5.resize((size_x, size_y), Image.ANTIALIAS)
photo5= ImageTk.PhotoImage(image5)
image6 = Image.open("/home/pi/Documents/6.jpg")
image6 = image6.resize((size_x, size_y), Image.ANTIALIAS)
photo6 = ImageTk.PhotoImage(image6)
image7 = Image.open("/home/pi/Documents/7.jpg")
image7 = image7.resize((size_x, size_y), Image.ANTIALIAS)
photo7 = ImageTk.PhotoImage(image7)
image8 = Image.open("/home/pi/Documents/8.jpg")
image8 = image8.resize((size_x, size_y), Image.ANTIALIAS)
photo8 = ImageTk.PhotoImage(image8)
image9 = Image.open("/home/pi/Documents/9.jpg")
image9 = image9.resize((size_x, size_y), Image.ANTIALIAS)
photo9 = ImageTk.PhotoImage(image9)
image10 = Image.open("/home/pi/Documents/0.jpg")
image10 = image10.resize((size_x, size_y), Image.ANTIALIAS)
photo10 = ImageTk.PhotoImage(image10)
buttonFrame = Frame(root)
# button with image binded to the same function
b1 = tk.Button(buttonFrame, image=photo1, command=on_click1)
b2 = tk.Button(buttonFrame, image=photo2, command=on_click2)
b3 = tk.Button(buttonFrame, image=photo3, command=on_click3)
b4 = tk.Button(buttonFrame, image=photo4, command=on_click4)
b5 = tk.Button(buttonFrame, image=photo5, command=on_click5)
b6 = tk.Button(buttonFrame, image=photo6, command=on_click6)
b7 = tk.Button(buttonFrame, image=photo7, command=on_click7)
b8 = tk.Button(buttonFrame, image=photo8, command=on_click8)
b9 = tk.Button(buttonFrame, image=photo9, command=on_click9)
b10 = tk.Button(buttonFrame, image=photo10, command=on_click10)
aFrame = Frame(root,bg="white") #Make a new frame containing the canvas
aCanvas = Canvas(aFrame, width = 747, height = 324) #Make canvas for asterisks
aCanvas.create_rectangle(0,0,747,324, fill="white", width = 15) #Make rectangle for asterisks to display on
squarePaddingX = 0
squarePaddingXStart = 25
squarePaddingY = 87
squareLength = 117
for i in range(0,6):
aCanvas.create_rectangle((squarePaddingX * (i) + squarePaddingXStart)+(squareLength * i),squarePaddingY,(squarePaddingX*(i))+(squareLength * (i+1) + squarePaddingXStart),squareLength+squarePaddingY, width = 5) #Crazy code that creates squares. Set variables above, don't touch this
asterisks = aCanvas.create_text(25,50,text="",font=("Verdana", "175"), anchor=tk.NW) #Make text for asterisks
aCanvas.pack()
b1.grid(row=0,column=0)
b2.grid(row=0,column=1)
b3.grid(row=0,column=2)
b4.grid(row=0,column=3)
b5.grid(row=0,column=4)
b6.grid(row=1,column=0)
b7.grid(row=1,column=1)
b8.grid(row=1,column=2)
b9.grid(row=1,column=3)
b10.grid(row=1,column=4)
buttonFrame.grid(row=0) #Set buttonframe above asterisk frame
aFrame.grid(row=1)
root.mainloop()
GPIO.cleanup() #resets all GPIO ports used by this program
My problem is that I want this to run when the Pi boots up, which involves starting the program from the terminal. If I use "sudo python3 [file path]", it tells me: "Traceback (most recent call last):
File "/home/pi/Documents/alienPasscodeV2.py", line 10, in
from omxplayer.player import OMXPlayer
ImportError: No module named 'omxplayer'".
If I use just "python3 [file path]", it starts off working, until it needs to play a video. Then it tells me:
"Exception in Tkinter callback Traceback (most recent call last):
File "/usr/lib/python3.5/tkinter/init.py", line 1562, in call
return self.func(*args) File "/home/pi/Documents/alienPasscodeV2.py", line 86, in on_click7
order(IM) File "/home/pi/Documents/alienPasscodeV2.py", line 121, in order
incorrectVideo() File "/home/pi/Documents/alienPasscodeV2.py", line 171, in incorrectVideo
player = OMXPlayer(incorrectPath, args=["--win", "0 0 1280 1024"], dbus_name='org.mpris.MediaPlayer2.omxplayer0') File
"/home/pi/.local/lib/python3.5/site-packages/omxplayer/player.py",
line 162, in init
self.load(source, pause=pause) File "/home/pi/.local/lib/python3.5/site-packages/omxplayer/player.py",
line 245, in load
self._load_source(source) File "/home/pi/.local/lib/python3.5/site-packages/omxplayer/player.py",
line 171, in _load_source
self._connection = self._setup_dbus_connection(self._Connection, self._bus_address_finder) File
"/home/pi/.local/lib/python3.5/site-packages/omxplayer/player.py",
line 231, in _setup_dbus_connection
raise SystemError('DBus cannot connect to the OMXPlayer process') SystemError: DBus cannot connect to the OMXPlayer process"
I have no idea why there's even a difference between using sudo and not using sudo. I've been trying to figure this out for hours and I have no idea. I'm so sorry for this program.
Turns out that when I was setting the paths, I needed to set the full path, not just the name of the file. So the paths changed to /home/pi/Documents/filename.

Run Images in Loop Tkinter

I am creating an app that will allow users to scan a ticket and a message will be displayed. I have created a short GIF animation to play when the app starts to show users where to scan their ticket.
I am having trouble understanding how to play a GIF image using tkinter in Python 3. I have tried many solutions and I came across a piece of code where you select the folder and the images in that folder will play in a loop but it's not working.
I think I'm not understanding the code. Here is my code for my app:
from tkinter import *
from tkinter import messagebox
import tkinter.filedialog
from tkinter.filedialog import askdirectory
import requests
import simplejson as json
import os
#from json import JSONEncoder
#class MyEncoder(JSONEncoder):
#def default(self, o):
#return o.__dict__
#Connect to API function
def apiconnect(statusvar):
ticektid = e1.get()
def to_serializable(ticketid):
return str(ticketid)
url = "https://staging3.activitar.com/ticket_api/tickets"
data = {'ticket_id':e1.get(),'direction': 'up'}
headers = {'Content-Type': 'application/json','Authorization' :'J0XDvDqVRy9hMF9Fo7j5'}
r = requests.post(url,data=json.dumps(data), headers=headers)
requestpost = requests.post(url, headers=headers, json=data)
response_data = requestpost.json()
statusvar = (response_data["status"])
messagevar = (response_data["message"])
json.dumps(url,data)
# MyEncoder().encode(ticketid)
#'{"ticekt_id": "/foo/bar"}'
#19 February 2018
#def from_json(json_object):
# if 'ticket_id' in json_object:
# return FileItem(json_object['ticket_id'])
# ticketid = JSONDecoder(object_hook = from_json).decode('{"ticket_id": "/foo/bar"}')
#Including GPIO config
if statusvar == "failed":
messagebox.showinfo("Cape Point", messagevar)
else: statusvar == "successful"
#Run at full screen automatically:
#---------------Function & Class--------------------------------#
class FullScreenApp(object):
def __init__(self, master, **kwargs):
self.master=master
pad=3
self._geom='200x200+0+0'
master.geometry("{0}x{1}+0+0".format(
master.winfo_screenwidth()-pad, master.winfo_screenheight()-pad))
master.bind('<Escape>',self.toggle_geom)
def toggle_geom(self,event):
geom=self.master.winfo_geometry()
print(geom,self._geom)
self.master.geometry(self._geom)
self._geom=geom
#--------------------------------------------------------------------#
def next_img():
img_label.img = PhotoImage(file=next(imgs))
img_label.config(image=img_label.img)
#create a textbox on a form
root = Tk()
#-----Full Screen-------#
app = FullScreenApp(root)
root.title("Cape Point")
root.configure(background = 'White')
#________ this code below was the original that displayed a static image _____#
#titlepic = PhotoImage(file = "ScanPlease.gif")
#shownpic = titlepic
#filename = shownpic
#Label(root, image = filename).grid(row=0, sticky=W)
img_dir = askdirectory(parent=root, initialdir= "C:/Users/Nickitaes/Desktop", title='Where To Scan')
os.chdir(img_dir)
imgs = iter(os.listdir(img_dir))
img_label = Label(root)
img_label.bind("<Return>",next_img())
next_img()
e1 = Entry(root)
e1.grid(row=1, column=0)
e1.focus_set() #set cursor focus to textbox
e1.bind("<Return>", apiconnect) #Return function
root.mainloop( )
Thanks for the help!
Well..., it was not hard to find other questions about this on StackOverflow. Here are some: Play Animations in GIF with Tkinter and Play an Animated GIF in python with tkinter.
I have combined the answers to take care of different number of subpictures an also commented the code a bit more.
from tkinter import *
import time
root = Tk()
framelist = [] # List to hold all the frames
for ix in range(1000): # range > frames in largest GIF
part = 'gif -index {}'.format(ix)
try: frame = PhotoImage(file='giphy.gif', format=part)
except:
last = len(framelist) - 1 # Save index for last frame
break # Will break when GIF index is reached
framelist.append(frame)
def update(ix):
if ix > last: ix = 0 # Reset frame counter if too big
label.configure(image=framelist[ix]) # Display frame on label
ix += 1 # Increase framecounter
root.after(100, update, ix) # Run again after 100 ms.
label = Label(root)
label.pack()
root.after(0, update, 0) # Start update(0) after 0 ms.
root.mainloop()
Adjust the for-loop for the GIF size you use, or rewrite as a while-loop.
I don't know how to read the frame delay from the GIF. You'll have to try different values in after() until it looks good.

Categories