Play mp4 video in python with GUI - python

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"

Related

HTML Video in Tkinter Window

is there any way to embed a HTML Video File in an tkinter window ?
I would be pleased for all kind of input!
Thanks a lot
One of solution is to use cv2 to read video frame-by-frame and replace frame on tk.Label or tk.Canvas - and you will see video.
(And cv2 uses ffmpeg for this)
cv2 can read from video file, local webcam or from remote stream (HTTP or RTMP)
Because it works with frames so you can draw some text or figures on frame before displaying - this way you can add some buttons or descriptions. You may also make modifications - crop, flip, convert to gray, etc.
But it has one problem: cv2 doesn't work with audio - so it can't play audio from file.
import tkinter as tk
from PIL import Image, ImageTk
import cv2
# --- functions ---
def update_frame():
ret, frame = video.read()
if ret: # check status - because sometimes it may have problem to read frame
# cv2 keeps image as `BGR` and it needs to convert to `RGB`
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# resize to tkinter's window
frame = cv2.resize(frame, (800, 600))
image = Image.fromarray(frame) # convert numpy.array to PIL.Image
photo.paste(image) # copy image on photo
# update again after some time (in milliseconds) (ie. 1000ms/25fps = 40ms)
root.after(int(1000/fps), update_frame)
# --- main ---
#video = cv2.VideoCapture(0) # local webcam
video = cv2.VideoCapture(BigBuckBunny.mp4")
#w = video.get(cv2.CAP_PROP_FRAME_WIDTH)
#h = video.get(cv2.CAP_PROP_FRAME_HEIGHT)
fps = video.get(cv2.CAP_PROP_FPS)
# get first frame to create photo
ret, frame = video.read()
# cv2 keeps image as `BGR` and it needs to convert to `RGB`
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# resize to tkinter's window
frame = cv2.resize(frame, (800, 600))
image = Image.fromarray(frame) # convert numpy.array to PIL.Image
# - GUI -
root = tk.Tk()
root.geometry('800x600')
photo = ImageTk.PhotoImage(image) # it has to be after `tk.Tk()`
canvas = tk.Canvas(root, width=photo.width(), height=photo.height())
canvas.pack(fill='both', expand=True)
image_id = canvas.create_image((0,0), image=photo, anchor='nw')
update_frame() # update it first time
root.mainloop() # run loop all time - it shows window
# - after close window -
# close stream
video.release()
Using Google I found module tkVideo.
It uses imageio to read frame-by-frame. (And imageio uses ffmpeg for this).
And it use threading instead of root.after().
It has the same problem: iamgeio doesn't work with audio - so it can't play audio from file.
EDIT:
Other method is to embed some Video Player like VLC, MPlayer, etc.. And it should gives video with audio but it doesn't allow to draw elements
I found example code in documentation for video player VLC but it seems complex because it adds also buttons to start/stop/pause video.
http://git.videolan.org/?p=vlc/bindings/python.git;a=blob;f=examples/tkvlc.py;h=55314cab09948fc2b7c84f14a76c6d1a7cbba127;hb=HEAD
#! /usr/bin/python
# -*- coding: utf-8 -*-
# tkinter example for VLC Python bindings
# Copyright (C) 2015 the VideoLAN team
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
#
"""A simple example for VLC python bindings using tkinter.
Requires Python 3.4 or later.
Author: Patrick Fay
Date: 23-09-2015
"""
# Tested with Python 3.7.4, tkinter/Tk 8.6.9 on macOS 10.13.6 only.
__version__ = '20.05.04' # mrJean1 at Gmail
# import external libraries
import vlc
# import standard libraries
import sys
if sys.version_info[0] < 3:
import Tkinter as Tk
from Tkinter import ttk
from Tkinter.filedialog import askopenfilename
from Tkinter.tkMessageBox import showerror
else:
import tkinter as Tk
from tkinter import ttk
from tkinter.filedialog import askopenfilename
from tkinter.messagebox import showerror
from os.path import basename, expanduser, isfile, join as joined
from pathlib import Path
import time
_isMacOS = sys.platform.startswith('darwin')
_isWindows = sys.platform.startswith('win')
_isLinux = sys.platform.startswith('linux')
if _isMacOS:
from ctypes import c_void_p, cdll
# libtk = cdll.LoadLibrary(ctypes.util.find_library('tk'))
# returns the tk library /usr/lib/libtk.dylib from macOS,
# but we need the tkX.Y library bundled with Python 3+,
# to match the version number of tkinter, _tkinter, etc.
try:
libtk = 'libtk%s.dylib' % (Tk.TkVersion,)
prefix = getattr(sys, 'base_prefix', sys.prefix)
libtk = joined(prefix, 'lib', libtk)
dylib = cdll.LoadLibrary(libtk)
# getNSView = dylib.TkMacOSXDrawableView is the
# proper function to call, but that is non-public
# (in Tk source file macosx/TkMacOSXSubwindows.c)
# and dylib.TkMacOSXGetRootControl happens to call
# dylib.TkMacOSXDrawableView and return the NSView
_GetNSView = dylib.TkMacOSXGetRootControl
# C signature: void *_GetNSView(void *drawable) to get
# the Cocoa/Obj-C NSWindow.contentView attribute, the
# drawable NSView object of the (drawable) NSWindow
_GetNSView.restype = c_void_p
_GetNSView.argtypes = c_void_p,
del dylib
except (NameError, OSError): # image or symbol not found
def _GetNSView(unused):
return None
libtk = "N/A"
C_Key = "Command-" # shortcut key modifier
else: # *nix, Xwindows and Windows, UNTESTED
libtk = "N/A"
C_Key = "Control-" # shortcut key modifier
class _Tk_Menu(Tk.Menu):
'''Tk.Menu extended with .add_shortcut method.
Note, this is a kludge just to get Command-key shortcuts to
work on macOS. Other modifiers like Ctrl-, Shift- and Option-
are not handled in this code.
'''
_shortcuts_entries = {}
_shortcuts_widget = None
def add_shortcut(self, label='', key='', command=None, **kwds):
'''Like Tk.menu.add_command extended with shortcut key.
If needed use modifiers like Shift- and Alt_ or Option-
as before the shortcut key character. Do not include
the Command- or Control- modifier nor the <...> brackets
since those are handled here, depending on platform and
as needed for the binding.
'''
# <https://TkDocs.com/tutorial/menus.html>
if not key:
self.add_command(label=label, command=command, **kwds)
elif _isMacOS:
# keys show as upper-case, always
self.add_command(label=label, accelerator='Command-' + key,
command=command, **kwds)
self.bind_shortcut(key, command, label)
else: # XXX not tested, not tested, not tested
self.add_command(label=label, underline=label.lower().index(key),
command=command, **kwds)
self.bind_shortcut(key, command, label)
def bind_shortcut(self, key, command, label=None):
"""Bind shortcut key, default modifier Command/Control.
"""
# The accelerator modifiers on macOS are Command-,
# Ctrl-, Option- and Shift-, but for .bind[_all] use
# <Command-..>, <Ctrl-..>, <Option_..> and <Shift-..>,
# <https://www.Tcl.Tk/man/tcl8.6/TkCmd/bind.htm#M6>
if self._shortcuts_widget:
if C_Key.lower() not in key.lower():
key = "<%s%s>" % (C_Key, key.lstrip('<').rstrip('>'))
self._shortcuts_widget.bind(key, command)
# remember the shortcut key for this menu item
if label is not None:
item = self.index(label)
self._shortcuts_entries[item] = key
# The Tk modifier for macOS' Command key is called
# Meta, but there is only Meta_L[eft], no Meta_R[ight]
# and both keyboard command keys generate Meta_L events.
# Similarly for macOS' Option key, the modifier name is
# Alt and there's only Alt_L[eft], no Alt_R[ight] and
# both keyboard option keys generate Alt_L events. See:
# <https://StackOverflow.com/questions/6378556/multiple-
# key-event-bindings-in-tkinter-control-e-command-apple-e-etc>
def bind_shortcuts_to(self, widget):
'''Set the widget for the shortcut keys, usually root.
'''
self._shortcuts_widget = widget
def entryconfig(self, item, **kwds):
"""Update shortcut key binding if menu entry changed.
"""
Tk.Menu.entryconfig(self, item, **kwds)
# adjust the shortcut key binding also
if self._shortcuts_widget:
key = self._shortcuts_entries.get(item, None)
if key is not None and "command" in kwds:
self._shortcuts_widget.bind(key, kwds["command"])
class Player(Tk.Frame):
"""The main window has to deal with events.
"""
_geometry = ''
_stopped = None
def __init__(self, parent, title=None, video=''):
Tk.Frame.__init__(self, parent)
self.parent = parent # == root
self.parent.title(title or "tkVLCplayer")
self.video = expanduser(video)
# Menu Bar
# File Menu
menubar = Tk.Menu(self.parent)
self.parent.config(menu=menubar)
fileMenu = _Tk_Menu(menubar)
fileMenu.bind_shortcuts_to(parent) # XXX must be root?
fileMenu.add_shortcut("Open...", 'o', self.OnOpen)
fileMenu.add_separator()
fileMenu.add_shortcut("Play", 'p', self.OnPlay) # Play/Pause
fileMenu.add_command(label="Stop", command=self.OnStop)
fileMenu.add_separator()
fileMenu.add_shortcut("Mute", 'm', self.OnMute)
fileMenu.add_separator()
fileMenu.add_shortcut("Close", 'w' if _isMacOS else 's', self.OnClose)
if _isMacOS: # intended for and tested on macOS
fileMenu.add_separator()
fileMenu.add_shortcut("Full Screen", 'f', self.OnFullScreen)
menubar.add_cascade(label="File", menu=fileMenu)
self.fileMenu = fileMenu
self.playIndex = fileMenu.index("Play")
self.muteIndex = fileMenu.index("Mute")
# first, top panel shows video
self.videopanel = ttk.Frame(self.parent)
self.canvas = Tk.Canvas(self.videopanel)
self.canvas.pack(fill=Tk.BOTH, expand=1)
self.videopanel.pack(fill=Tk.BOTH, expand=1)
# panel to hold buttons
self.buttons_panel = Tk.Toplevel(self.parent)
self.buttons_panel.title("")
self.is_buttons_panel_anchor_active = False
buttons = ttk.Frame(self.buttons_panel)
self.playButton = ttk.Button(buttons, text="Play", command=self.OnPlay)
stop = ttk.Button(buttons, text="Stop", command=self.OnStop)
self.muteButton = ttk.Button(buttons, text="Mute", command=self.OnMute)
self.playButton.pack(side=Tk.LEFT)
stop.pack(side=Tk.LEFT)
self.muteButton.pack(side=Tk.LEFT)
self.volMuted = False
self.volVar = Tk.IntVar()
self.volSlider = Tk.Scale(buttons, variable=self.volVar, command=self.OnVolume,
from_=0, to=100, orient=Tk.HORIZONTAL, length=200,
showvalue=0, label='Volume')
self.volSlider.pack(side=Tk.RIGHT)
buttons.pack(side=Tk.BOTTOM, fill=Tk.X)
# panel to hold player time slider
timers = ttk.Frame(self.buttons_panel)
self.timeVar = Tk.DoubleVar()
self.timeSliderLast = 0
self.timeSlider = Tk.Scale(timers, variable=self.timeVar, command=self.OnTime,
from_=0, to=1000, orient=Tk.HORIZONTAL, length=500,
showvalue=0) # label='Time',
self.timeSlider.pack(side=Tk.BOTTOM, fill=Tk.X, expand=1)
self.timeSliderUpdate = time.time()
timers.pack(side=Tk.BOTTOM, fill=Tk.X)
# VLC player
args = []
if _isLinux:
args.append('--no-xlib')
self.Instance = vlc.Instance(args)
self.player = self.Instance.media_player_new()
self.parent.bind("<Configure>", self.OnConfigure) # catch window resize, etc.
self.parent.update()
# After parent.update() otherwise panel is ignored.
self.buttons_panel.overrideredirect(True)
# Estetic, to keep our video panel at least as wide as our buttons panel.
self.parent.minsize(width=502, height=0)
if _isMacOS:
# Only tested on MacOS so far. Enable for other OS after verified tests.
self.is_buttons_panel_anchor_active = True
# Detect dragging of the buttons panel.
self.buttons_panel.bind("<Button-1>", lambda event: setattr(self, "has_clicked_on_buttons_panel", event.y < 0))
self.buttons_panel.bind("<B1-Motion>", self._DetectButtonsPanelDragging)
self.buttons_panel.bind("<ButtonRelease-1>", lambda _: setattr(self, "has_clicked_on_buttons_panel", False))
self.has_clicked_on_buttons_panel = False
else:
self.is_buttons_panel_anchor_active = False
self._AnchorButtonsPanel()
self.OnTick() # set the timer up
def OnClose(self, *unused):
"""Closes the window and quit.
"""
# print("_quit: bye")
self.parent.quit() # stops mainloop
self.parent.destroy() # this is necessary on Windows to avoid
# ... Fatal Python Error: PyEval_RestoreThread: NULL tstate
def _DetectButtonsPanelDragging(self, _):
"""If our last click was on the boarder
we disable the anchor.
"""
if self.has_clicked_on_buttons_panel:
self.is_buttons_panel_anchor_active = False
self.buttons_panel.unbind("<Button-1>")
self.buttons_panel.unbind("<B1-Motion>")
self.buttons_panel.unbind("<ButtonRelease-1>")
def _AnchorButtonsPanel(self):
video_height = self.parent.winfo_height()
panel_x = self.parent.winfo_x()
panel_y = self.parent.winfo_y() + video_height + 23 # 23 seems to put the panel just below our video.
panel_height = self.buttons_panel.winfo_height()
panel_width = self.parent.winfo_width()
self.buttons_panel.geometry("%sx%s+%s+%s" % (panel_width, panel_height, panel_x, panel_y))
def OnConfigure(self, *unused):
"""Some widget configuration changed.
"""
# <https://www.Tcl.Tk/man/tcl8.6/TkCmd/bind.htm#M12>
self._geometry = '' # force .OnResize in .OnTick, recursive?
if self.is_buttons_panel_anchor_active:
self._AnchorButtonsPanel()
def OnFullScreen(self, *unused):
"""Toggle full screen, macOS only.
"""
# <https://www.Tcl.Tk/man/tcl8.6/TkCmd/wm.htm#M10>
f = not self.parent.attributes("-fullscreen") # or .wm_attributes
if f:
self._previouscreen = self.parent.geometry()
self.parent.attributes("-fullscreen", f) # or .wm_attributes
self.parent.bind("<Escape>", self.OnFullScreen)
else:
self.parent.attributes("-fullscreen", f) # or .wm_attributes
self.parent.geometry(self._previouscreen)
self.parent.unbind("<Escape>")
def OnMute(self, *unused):
"""Mute/Unmute audio.
"""
# audio un/mute may be unreliable, see vlc.py docs.
self.volMuted = m = not self.volMuted # self.player.audio_get_mute()
self.player.audio_set_mute(m)
u = "Unmute" if m else "Mute"
self.fileMenu.entryconfig(self.muteIndex, label=u)
self.muteButton.config(text=u)
# update the volume slider text
self.OnVolume()
def OnOpen(self, *unused):
"""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()
# Create a file dialog opened in the current home directory, where
# you can display all kind of files, having as title "Choose a video".
video = askopenfilename(initialdir = Path(expanduser("~")),
title = "Choose a video",
filetypes = (("all files", "*.*"),
("mp4 files", "*.mp4"),
("mov files", "*.mov")))
self._Play(video)
def _Pause_Play(self, playing):
# re-label menu item and button, adjust callbacks
p = 'Pause' if playing else 'Play'
c = self.OnPlay if playing is None else self.OnPause
self.fileMenu.entryconfig(self.playIndex, label=p, command=c)
# self.fileMenu.bind_shortcut('p', c) # XXX handled
self.playButton.config(text=p, command=c)
self._stopped = False
def _Play(self, video):
# helper for OnOpen and OnPlay
if isfile(video): # Creation
m = self.Instance.media_new(str(video)) # Path, unicode
self.player.set_media(m)
self.parent.title("tkVLCplayer - %s" % (basename(video),))
# set the window id where to render VLC's video output
h = self.videopanel.winfo_id() # .winfo_visualid()?
if _isWindows:
self.player.set_hwnd(h)
elif _isMacOS:
# XXX 1) using the videopanel.winfo_id() handle
# causes the video to play in the entire panel on
# macOS, covering the buttons, sliders, etc.
# XXX 2) .winfo_id() to return NSView on macOS?
v = _GetNSView(h)
if v:
self.player.set_nsobject(v)
else:
self.player.set_xwindow(h) # plays audio, no video
else:
self.player.set_xwindow(h) # fails on Windows
# FIXME: this should be made cross-platform
self.OnPlay()
def OnPause(self, *unused):
"""Toggle between Pause and Play.
"""
if self.player.get_media():
self._Pause_Play(not self.player.is_playing())
self.player.pause() # toggles
def OnPlay(self, *unused):
"""Play video, if none is loaded, open the dialog window.
"""
# if there's no video to play or playing,
# open a Tk.FileDialog to select a file
if not self.player.get_media():
if self.video:
self._Play(expanduser(self.video))
self.video = ''
else:
self.OnOpen()
# Try to play, if this fails display an error message
elif self.player.play(): # == -1
self.showError("Unable to play the video.")
else:
self._Pause_Play(True)
# set volume slider to audio level
vol = self.player.audio_get_volume()
if vol > 0:
self.volVar.set(vol)
self.volSlider.set(vol)
def OnResize(self, *unused):
"""Adjust the window/frame to the video aspect ratio.
"""
g = self.parent.geometry()
if g != self._geometry and self.player:
u, v = self.player.video_get_size() # often (0, 0)
if v > 0 and u > 0:
# get window size and position
g, x, y = g.split('+')
w, h = g.split('x')
# alternatively, use .winfo_...
# w = self.parent.winfo_width()
# h = self.parent.winfo_height()
# x = self.parent.winfo_x()
# y = self.parent.winfo_y()
# use the video aspect ratio ...
if u > v: # ... for landscape
# adjust the window height
h = round(float(w) * v / u)
else: # ... for portrait
# adjust the window width
w = round(float(h) * u / v)
self.parent.geometry("%sx%s+%s+%s" % (w, h, x, y))
self._geometry = self.parent.geometry() # actual
def OnStop(self, *unused):
"""Stop the player, resets media.
"""
if self.player:
self.player.stop()
self._Pause_Play(None)
# reset the time slider
self.timeSlider.set(0)
self._stopped = True
# XXX on macOS libVLC prints these error messages:
# [h264 # 0x7f84fb061200] get_buffer() failed
# [h264 # 0x7f84fb061200] thread_get_buffer() failed
# [h264 # 0x7f84fb061200] decode_slice_header error
# [h264 # 0x7f84fb061200] no frame!
def OnTick(self):
"""Timer tick, update the time slider to the video time.
"""
if self.player:
# since the self.player.get_length may change while
# playing, re-set the timeSlider to the correct range
t = self.player.get_length() * 1e-3 # to seconds
if t > 0:
self.timeSlider.config(to=t)
t = self.player.get_time() * 1e-3 # to seconds
# don't change slider while user is messing with it
if t > 0 and time.time() > (self.timeSliderUpdate + 2):
self.timeSlider.set(t)
self.timeSliderLast = int(self.timeVar.get())
# start the 1 second timer again
self.parent.after(1000, self.OnTick)
# adjust window to video aspect ratio, done periodically
# on purpose since the player.video_get_size() only
# returns non-zero sizes after playing for a while
if not self._geometry:
self.OnResize()
def OnTime(self, *unused):
if self.player:
t = self.timeVar.get()
if self.timeSliderLast != int(t):
# this is a hack. The timer updates the time slider.
# This change causes this rtn (the 'slider has changed' rtn)
# to be invoked. I can't tell the difference between when
# the user has manually moved the slider and when the timer
# changed the slider. But when the user moves the slider
# tkinter only notifies this rtn about once per second and
# when the slider has quit moving.
# Also, the tkinter notification value has no fractional
# seconds. The timer update rtn saves off the last update
# value (rounded to integer seconds) in timeSliderLast if
# the notification time (sval) is the same as the last saved
# time timeSliderLast then we know that this notification is
# due to the timer changing the slider. Otherwise the
# notification is due to the user changing the slider. If
# the user is changing the slider then I have the timer
# routine wait for at least 2 seconds before it starts
# updating the slider again (so the timer doesn't start
# fighting with the user).
self.player.set_time(int(t * 1e3)) # milliseconds
self.timeSliderUpdate = time.time()
def OnVolume(self, *unused):
"""Volume slider changed, adjust the audio volume.
"""
vol = min(self.volVar.get(), 100)
v_M = "%d%s" % (vol, " (Muted)" if self.volMuted else '')
self.volSlider.config(label="Volume " + v_M)
if self.player and not self._stopped:
# .audio_set_volume returns 0 if success, -1 otherwise,
# e.g. if the player is stopped or doesn't have media
if self.player.audio_set_volume(vol): # and self.player.get_media():
self.showError("Failed to set the volume: %s." % (v_M,))
def showError(self, message):
"""Display a simple error dialog.
"""
self.OnStop()
showerror(self.parent.title(), message)
if __name__ == "__main__":
_video = ''
while len(sys.argv) > 1:
arg = sys.argv.pop(1)
if arg.lower() in ('-v', '--version'):
# show all versions, sample output on macOS:
# % python3 ./tkvlc.py -v
# tkvlc.py: 2019.07.28 (tkinter 8.6 /Library/Frameworks/Python.framework/Versions/3.7/lib/libtk8.6.dylib)
# vlc.py: 3.0.6109 (Sun Mar 31 20:14:16 2019 3.0.6)
# LibVLC version: 3.0.6 Vetinari (0x3000600)
# LibVLC compiler: clang: warning: argument unused during compilation: '-mmacosx-version-min=10.7' [-Wunused-command-line-argument]
# Plugin path: /Applications/VLC3.0.6.app/Contents/MacOS/plugins
# Python: 3.7.4 (64bit) macOS 10.13.6
# Print version of this vlc.py and of the libvlc
print('%s: %s (%s %s %s)' % (basename(__file__), __version__,
Tk.__name__, Tk.TkVersion, libtk))
try:
vlc.print_version()
vlc.print_python()
except AttributeError:
pass
sys.exit(0)
elif arg.startswith('-'):
print('usage: %s [-v | --version] [<video_file_name>]' % (sys.argv[0],))
sys.exit(1)
elif arg: # video file
_video = expanduser(arg)
if not isfile(_video):
print('%s error: no such file: %r' % (sys.argv[0], arg))
sys.exit(1)
# Create a Tk.App() to handle the windowing event loop
root = Tk.Tk()
player = Player(root, video=_video)
root.protocol("WM_DELETE_WINDOW", player.OnClose) # XXX unnecessary (on macOS)
root.mainloop()

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.

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

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.

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