Search code examples
python-2.7tkinterraspberry-pi2gpio

Can't update images changing GPIO pins


I am trying to create a program, that simply reads 2 pins in this case pin 17 and pin 27 using the BCM setmode. Depending inthe value of each pin ( 0 or 1 ) the program will show on a screen a different image.

My problem is, the first time i run the program the image it shows is the correct one, but if meanwhile i set any pin a different state (ON/OFF), the program don't upload the right image on the screen, showing me a error message.

If i just try to run "prints", it works fine, but with images i have always this problem. I never pass right after the first image. Being stuck with the initial image all program long. I get an error in create_image return self._create.

EDIT:Error message image in the link below

error i get https://i.sstatic.net/q6qgp.png

import Tkinter as tk
import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
GPIO.setup(17,GPIO.IN)
GPIO.setup(27,GPIO.IN)
app = tk.Tk()
app.attributes("-fullscreen", True)
app.title('Presence State')
screen_width = app.winfo_screenwidth()
screen_height = app.winfo_screenheight()

emptyP = tk.PhotoImage(file = "./images/emptyPresence.jpg")
leftP = tk.PhotoImage(file = "./images/leftPresence.jpg")
rightP = tk.PhotoImage(file = "./images/rightPresence.jpg")
bothP = tk.PhotoImage(file = "./images/bothSidesPresence.jpg")

fname = tk.Canvas(app, bg = "black" , width = screen_width, height =
        screen_height)

def empty():
    image = fname.create_image(screen_width/2, screen_height/2, anchor =  
            tk.CENTER, image = emptyP)

def left():
    image = fname.create_image(screen_width/2, screen_height/2, anchor = 
            tk.CENTER, image = leftP)

def right():
    image = fname.create_image(screen_width/2, screen_height/2, anchor = 
            tk.CENTER, image = rightP)

def both():
    image = fname.create_image(screen_width/2, screen_height/2, anchor = 
            tk.CENTER, image = bothP)

while(1):
        if GPIO.input(17) == 0 and GPIO.input(27) == 0:
                empty()
                time.sleep(.5)
        elif GPIO.input(17) == 1 and GPIO.input(27) == 0:
                  left()
                  time.sleep(.5)
        elif GPIO.input(17) == 0 and GPIO.input(27) == 1:
                  right()
                  time.sleep(.5)
        else:
                  both()
                  time.sleep(.5)


        fname.pack()
        app.mainloop()

Solution

  • I don't have a RaspberryPi so I've created two Checkbuttons to simulate the IO pins. I've shown the result in a Label. Amending the result to show images shouldn't be too difficult. The function on_after calls itself every 500 milliseconds in place of the original sleep(0.5)s

    import tkinter as tk
    from tkinter import ttk
    
    root = tk.Tk()
    root.geometry('400x100')
    root.title('"After" Demonstation')
    
    # Set up fake GPIO Pins as Checkbuttons
    # IntVars to easily read the state.
    gpio17 = tk.IntVar()
    gpio27 = tk.IntVar()
    # Initialise to zero
    gpio17.set(0)
    gpio27.set(0)
    
    ttk.Checkbutton(root, variable = gpio17, text = 'GPIO 17', width = 20).grid( row = 0, column = 0)
    ttk.Checkbutton(root, variable = gpio27, text = 'GPIO 27', width = 20).grid( row = 0, column = 2)
    
    # I'm using a label for simplicity. Amendments required 
    # below to cope with images.
    result = tk.StringVar()
    ttk.Label(root, textvariable = result, width = 20 ).grid(row=1, column=1)
    
    DELAY = 500 # in milliseconds
    
    def on_after():
        """ Reads the state of the io pins and sets the result
            to the appropriate value. """
        # Code to fetch the IO states will be different with real pins. 
        io17 = gpio17.get()  # Get the button states
        io27 = gpio27.get()
    
        # Set the result. Will be different with images.
        if io17:
            if io27:
                result.set('Both')
            else:
                result.set('Left')
        else:
            if io27:
                result.set('Right')
            else:
                result.set('None')
    
        id = root.after( DELAY, on_after) # This implements the loop by calling on_after again.
    
    id = root.after( 1, on_after) # Start the loop.
    
    root.mainloop()