Image viewer app: function to display next picture not working - python

I've been watching this youtube tutorial and had (I thought) a way better idea of solving the build an image viewer app.
But nothing happens on input, and I don't understand why, I think I might have totally misunderstood list as it doesn't start with the first picture (index 0).
The code is here
from tkinter import *
from PIL import ImageTk,Image
i = 0
root = Tk()
root.title("Learning to code")
root.iconbitmap('blue.PNG')
my_img1 = ImageTk.PhotoImage(Image.open("pics\me1.JFIF"))
my_img2 = ImageTk.PhotoImage(Image.open("pics\me2.JPG"))
my_img3 = ImageTk.PhotoImage(Image.open("pics\me3.JPG"))
my_img4 = ImageTk.PhotoImage(Image.open("pics\me4.JPG"))
my_img5 = ImageTk.PhotoImage(Image.open("pics\pop.JPG"))
img_list = [my_img1,my_img2,my_img3,my_img4,my_img5]
my_label = Label(image=img_list[i])
my_label.grid(row=0,column=0,columnspan=3)
def f_fwd():
global i
global my_label
if i < 4 :
my_label.grid_forget()
i =+1
my_label = Label(image=img_list[i])
my_label.grid(row=0,column=0,columnspan=3)
def f_bwd():
return
button_bwd = Button(root, text= "<<")
button_bwd.grid(row=1,column=0)
button_quit =Button(root, text="Exit", command= root.quit)
button_quit.grid(row=1,column=1)
button_fwd = Button(root, text=">>", command=f_fwd())
button_fwd.grid(row=1,column=2)
root.mainloop()
Sorry if I worded the problem poorly.
I expected the index to go up and display the next picture in the list when the f_fwd function is called from the button command, and I don't understand why its not working.

Related

how could i update integer variable with tkinter?

i found a tutorial on google which integer value could be update by using .config(). So I had using the below code to update the value. I think my logic it wrong by put the while loop like that , but i not sure how could i update the a = a + 1 on to the gui.
My code :
import tkinter as tk
from random import randint
master_window = tk.Tk()
master_window.geometry("250x150")
master_window.title("IntVar Example")
lab = tk.Label(master_window)
integer_variable = tk.IntVar()
integer_variable.set(2)
label = tk.Label(master_window,text="output", height=50)
label.place(x=80, y=80)
a = 25
def update():
my_data=integer_variable.get(a) # read the value of selected radio button
label.config(text=str(my_data)) # Update the Label with data
while True:
a = a + 1
master_window.update()
master_window.mainloop()
The setup you have so far is quite strange and your intuition that the logic is wrong is accurate.
Here's an alternative to get you started - note how I refrain from using external variables and instead use the .set() and get() operations to change the value of the integer_variable:
import tkinter as tk
master_window = tk.Tk()
master_window.geometry("250x150")
master_window.title("IntVar Example")
integer_variable = tk.IntVar()
integer_variable.set(2)
label = tk.Label(master_window, text=integer_variable.get())
label.grid(row=0, column=0)
button = tk.Button(master_window, text="Update value", command=update)
button.grid(row=1, column=0)
def update():
curr_integer_variable_value = integer_variable.get()
updated_integer_value = curr_integer_variable_value + 1
integer_variable.set(updated_integer_value)
label.config(text=str(integer_variable.get()))
master_window.mainloop()

How can I put image on Button in python tkinter?

This is my code in Tkinter. I tried to show buttons with the image when I select the grid size in tkinter UI. My problem is that when I go to put an image inside a button, it does not display it. List grid2 already have images with using the shuffle method.
Any help is appreciated.
import tkinter
import tkinter.ttk
import random
def startButton():
global my_list, roundNum, tmp_list, startTime
grid_size = combobox1.get()[0]
roundNum = combobox2.get()[0]
gridActorList(my_list)
imageUpdate()
startTime=time.time()
def imageUpdate():
global grid_size
t = []
if grid_size == 2:
photo_1 = tkinter.PhotoImage(file="picture/"+grid2[0]+".png")
photo_2 = tkinter.PhotoImage(file="picture/"+grid2[1]+".png")
photo_3 = tkinter.PhotoImage(file="picture/"+grid2[2]+".png")
photo_4 = tkinter.PhotoImage(file="picture/"+grid2[3]+".png")
for k in range(1,5):
t.append(tkinter.Button(window, image=photo_+str(k)))
for i in range(0,4):
t[i].pack()
window = tkinter.Tk()
window.title('Finding different picture!')
window.geometry('500x400')
#combobox
values1=[str(i)+"x"+str(i) for i in range(2,6)] #grid size
values2=[str(j)+"times" for j in range(1,10,2)] #play time size
combobox1=tkinter.ttk.Combobox(window, height=5, width=15, values=values1,
justify='center', takefocus=True )
combobox2=tkinter.ttk.Combobox(window, height=5, width=15, values=values2,
justify='center', takefocus=True )
combobox1.set("select size")
combobox2.set("select times")
combobox1.place(x=15, y=15)
combobox2.place(x=155, y=15)
#startButton
startBtn = tkinter.Button(window, text='start', command=startButton)
startBtn.place(x=300, y=15)
#variables
my_list = []
roundNnum = 0
window.mainloop()
I've tried to minimize the code. If there are more codes required, I'll edit it.
Your code does not run. This makes it hard to debug. But I can see that you're not saving references to the images you put in the buttons.
As the images are created inside a function they will be garbage collected when the function exits. Fix this by saving a reference to the image with the button widget. Examine the example below:
import tkinter as tk
def create_button():
photo = tk.PhotoImage(file="images/gilliam.png")
image_button = tk.Button(window, image=photo)
image_button.image = photo # Save a reference to the image
image_button.pack()
window = tk.Tk()
create_button()
window.mainloop()

TKinter button images didn't show up

I wanted to make my app look more beautiful and it's harder than I though! Now I had an app with mainly 2 buttons and date-time label on top. Buttons are just with text, but I want to use pictures on them. That's my code now:
def showMainMenu():
global cardNumber, allowToGPIO
cardNumber = "" #Reset cardNumber global value
allowToGPIO = True
clear()
showNewTime()
watchDog.awake()
GuestTestButton = Button(canvas, text="GUEST TEST", width=buttonwidth, height=buttonheight, compound = TKinter.CENTER, command = guestTest)
GuestTestButton.config(font=("Mojave-Regular.ttf", 24))
#GuestTestButton.pack()
GuestTestButton.place(x=90, y=100)
AddEmployeeButton = Button(canvas, text="ADD NEW USER", width=buttonwidth, height=buttonheight, compound = TKinter.CENTER, command = addEmployee)
AddEmployeeButton.config(font=("Mojave-Regular.ttf", 24))
#AddEmployeeButton.pack()
AddEmployeeButton.place(x=90, y=270)
And for now, it works. But when I tried to make them more colorful (just use image instead of text), button shows up without anything on it. Is it even possible to make things like that in TKinter? Everything I do is on canvas:
app = TKinter.Tk()
canvas = TKinter.Canvas()
I tried to do this that way:
GuestImage = TKinter.PhotoImage(file="guest.gif")
GuestTestButton = Button(canvas, text="GUEST TEST", width=buttonwidth, height=buttonheight, compound = TKinter.CENTER, command = guestTest)
GuestTestButton.config(image=GuestImage, font=("Mojave-Regular.ttf", 24))
GuestTestButton.place(x=90, y=100)
But as I said, it's not working properly :D Thanks in advance for any help!
I got it now, my images shows up but it dissapears after miliseconds, now I made the GuestImage and AddEmployeeImage as global variables and it works perfectly!

Switching images based on arduino input in a python 2.7 generated Tkinter window won't show the images

I wrote an Arduino code which reacts to buttons and physical interactions and then send the results to the computer on which my python program (2.7) is running.
The python code has two functions:
Create a new text file named after the unixtimestamp and fill it
with all the data it receives.
Look through the data it receives for the code phrases "a1" and "b1"
and then show the corresponding image.
When the Arduino starts it will send the "a1" as a first value to fill the window. After that, it should switch based on the data it sends.
This is my current code:
from Tkinter import *
from random import *
import serial
import time
root = Tk()
prompt = StringVar()
root.title("vision")
label = Label(root, fg="dark green")
label.pack()
frame = Frame(root,background='red')
frame.pack()
canvas = Canvas(height=200,width=200)
canvas.pack()
timestamp = int(time.time())
filename=str(timestamp)+".txt"
f = open(str(filename),"w")
f.write("\n")
f.write(str(filename))
f.write("\n")
arduino = serial.Serial('COM5', 115200, timeout=.1)
while True:
data = arduino.readline()[:-2] #the last bit gets rid of the new-line chars
print data
f.write(str(data))
f.write("\n")
#Invoking through button
TextWindow = Label(frame,anchor = NW, justify = LEFT, bg= 'white', fg = 'blue', textvariable = prompt, width = 75, height=20)
TextWindow.pack(side = TOP)
if data == "a1":
canvas.delete("all")
image1 = PhotoImage(file = "c2.gif")
canvas.create_image(0,0,anchor='nw',image=image1)
canvas.image = image1
if data == "b1":
canvas.delete("all")
image1 = PhotoImage(file = "c2.gif")
canvas.create_image(0,0,anchor='nw',image=image1)
canvas.image = image1
root.mainloop()
It generates the window but it is empty.
I can not seem to find where my error is.
Additionaly:
I used an other tutorial wich gave me he basic code for the gui and images. In this there are two buttons wich switch the images which works.
from Tkinter import *
from random import *
pathy = randint(1, 2)
root = Tk()
prompt = StringVar()
root.title("vision")
label = Label(root, fg="dark green")
label.pack()
frame = Frame(root,background='red')
frame.pack()
canvas = Canvas(height=200,width=200)
canvas.pack()
def Image1():
canvas.delete("all")
image1 = PhotoImage(file = "c2.gif")
canvas.create_image(0,0,anchor='nw',image=image1)
canvas.image = image1
def Image2():
canvas.delete("all")
image1 = PhotoImage(file = "c1.gif")
canvas.create_image(0,0,anchor='nw',image=image1)
canvas.image = image1
TextWindow = Label(frame,anchor = NW, justify = LEFT, bg= 'white', fg = 'blue', textvariable = prompt, width = 75, height=20)
TextWindow.pack(side = TOP)
conversationbutton = Button(frame, text='right button',width=25,fg="green",command = Image1)
conversationbutton.pack(side = RIGHT)
stopbutton = Button(frame, text='left button',width=25,fg="red",command = Image2)
stopbutton.pack(side = RIGHT)
root.mainloop()
Once the mainloop() function has been called you have to use callbacks in order to run your own code. The Tkinter after() method can be used to run a section of code after a set amount of time.
In your case your code would look something like:
def update():
#your code here
root.after(1000, update)
update()
root.mainloop()
Calling root.after() inside of the update functions allows the function to keep running until the window is closed.
The after method as described at effbot gives the arguments as:
root.after(milliseconds, callback)
In your case you might have to call your processing code more often then every second.

TKinter Update Image list

I am using TKinter to display some images of a folder. Those are loaded from a list:
image_list = [os.path.join("/home/pi/fotos/previews",fn) for fn in next(os.walk("/home/pi/fotos/previews"))[2]]
But the folder is beeing updated with new photos from time to time, so TKinter has to be refreshed somehow, to show those new images as well.
How could I refresh TKinter with a new image list?
Here's the full code:
#!/usr/bin/python
import Image
import ImageTk
import Tkinter
import glob
import sys
import os.path
import os
image_list = [os.path.join("/home/pi/fotos/previews",fn) for fn in next(os.walk("/home/pi/fotos/previews"))[2]]
sorted_imagelist = sorted(image_list, key=str.swapcase, reverse=True)
current = 0
def move(delta):
global current, sorted_imagelist
if not (0 <= current - delta < len(sorted_imagelist)):
tkMessageBox.showinfo('End', 'No more image.')
return
current -= delta
image = Image.open(sorted_imagelist[current])
photo = ImageTk.PhotoImage(image)
label['image'] = photo
label.photo = photo
root = Tkinter.Tk()
root.configure(background="#eee")
label = Tkinter.Label(root, compound=Tkinter.TOP, bg="#eee")
label.pack()
label.place(x=90, y=30)
frame = Tkinter.Frame(root, bg="#eee")
frame.pack()
Tkinter.Button(frame, text='Refresh', height=10, width=25, command=root.update).pack(side=Tkinter.LEFT)
Tkinter.Button(frame, text='Previous picture', height=10, width=25, command=lambda: move(-1)).pack(side=Tkinter.LEFT)
Tkinter.Button(frame, text='Next picture', height=10, width=25, command=lambda: move(+1)).pack(side=Tkinter.LEFT)
Tkinter.Button(frame, text='Quit', height=10, width=25, command=root.quit).pack(side=Tkinter.LEFT)
move(0)
root.attributes('-fullscreen', True)
root.mainloop()
Thanks for help!
I found a solution and will answer my own question to help others:
Actually I created a function that will simply check the list again.
def refresh(delta):
global current, sorted_imagelist
text_list = next(os.walk("/home/pi/fotos/previews"))[2]
image_list = [os.path.join("/home/pi/fotos/previews",fn) for fn in next(os.walk("/home/pi/fotos/previews"))[2]]
sorted_textlist = sorted(text_list, key=str.swapcase, reverse=True)
sorted_imagelist = sorted(image_list, key=str.swapcase, reverse=True)
print (sorted_imagelist)
print ('Refreshed')
This function is called every second, so everything works fast.
def updater():
threading.Timer(1.0, updater).start()
refresh(0)
updater()
Only problem I am having so far is, that when the current viewed image is the last one of the old list, the 'new' last photo is not being loaded correctly into TKinter. I have to navigate back to the previous and I'm then able to move forward to see the new one.
I am working on a solution to solve that last one.
If you store the list of filenames at time A and then later get the new list of filenames at time B then you can use the set operation symmetric_difference to find the items in B that are not in A (i.e: new files). The Tk after method can let you schedule a function to do this at intervals. You can then create the new Tk images for the new files and add those to your list of Tk images.
Each platform has some API for requesting your application be notified when changes occur to the filesystem. On Windows that's the FindFirstChangeNotification function and its friends or inotify on Linux. However, the simplest cross-platform method is to poll the contents of the directory on a timer.

Categories