Python Forum
How to redraw an existing image to a different image TkInter
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How to redraw an existing image to a different image TkInter
#1
Hello. I have a tkinter application running and I am trying to come up with a solution. I will explain the scenario briefly:

On my tkinter application, there is a "toggle" button that toggles the sensors ON and OFF. I have uploaded a green "tick" and red "cross" images to display the current state of the sensors. When the sensor is ON, a green "tick" image must be displayed , and when the sensor is toggled OFF red "cross" is displayed.


See the image of the button and green tick:
https://ibb.co/2qBLPTf



When the program starts, the default state is all the sensors are turned on, hence I create an image with a green tick next to the button:
        img_tick1 = Image.open("/home/pi/Desktop/PICK_TO_LIGHT/green_tick.png")
        img_tick1 = img_tick1.resize((50,50),Image.ANTIALIAS)
        img_green_tick = ImageTk.PhotoImage(img_tick1)
        self.img_tick = canvas.create_image(430,120,anchor='nw',image=img_green_tick)
I have assigned a variable for the canvas.create_image and called it self.img_tick (self keyword is used because this is a class member but you can ignore it).

When the button is pressed, the following function is being executed as an event, at the end of the function, I want to redraw an existing image instead of green tick to a red cross:
    def toggle_sensor(self):
        for x in range(0,len(active_devices)):
            while True:
                try:
                    master_modbus.execute(active_devices[x], cst.WRITE_SINGLE_REGISTER, 10, output_value=66)
                    break
                except Exception as e:
                    print("exception on remove item:",e)
        # swap the image with red tick here!
        #self.tick_img.config(image=img_red_tick)
Notice I have tried to use .config but it did not work as the create_image does not have a config method attached to it. Please could someone suggest me a possible solution for this? How can I redraw an image? I know this may not be the most efficient solution but please suggest me a possible fixes for this particular example

UPDATE

I may have found a solution but its not complete yet:

        canvas.delete(self.img_tick)
        self.img_tick = canvas.create_image(430,115,anchor='nw',image=self.img_red_tick)
The code above will delete the previous image and draw a new one at the same coordinates. However, now the next issue is how do I know what was the previous image. I can create a global variable and keep toggling it so I know what is the current state, but that is not the best solution in my opinion.

According to the following information about the create.canvas_image:
https://anzeljg.github.io/rin2/book2/240...image.html

This constructor returns the integer ID number of the image object for that canvas.. Is it possible to determine whether the current image is set to green tick or red cross based on the constructor ID?
Reply
#2
Your solution is not correct.
I think self.tick_img.config(img_red_tick)
or self.tick_img.config(img_green_tick)
is the proper way.
you can keep track of last color with by using a color variable:
    self.image_color = 0
then add:
# if in class:
def green_image(self):
    self.tick_img.config(img_green_tick)
    self.image_color = 0

def red_image(self):
    self.tick_img.config(img_green_tick)
    self.image_color = 1

def toggle_color(self):
    if self.color:
        self.green_image()
    else:
        self.red_image()
Again, I state that this is what I think will work.
I may be way off base.
Reply
#3
(Jul-08-2021, 11:17 AM)Larz60+ Wrote: Your solution is not correct.
I think self.tick_img.config(img_red_tick)
or self.tick_img.config(img_green_tick)
is the proper way.
you can keep track of last color with by using a color variable:
    self.image_color = 0
then add:
# if in class:
def green_image(self):
    self.tick_img.config(img_green_tick)
    self.image_color = 0

def red_image(self):
    self.tick_img.config(img_green_tick)
    self.image_color = 1

def toggle_color(self):
    if self.color:
        self.green_image()
    else:
        self.red_image()
Again, I state that this is what I think will work.
I may be way off base.

Hello. I have tried the .config method but it seems that canvas.create_image does not have config attribute. I am getting the following error:
Attributerror: 'int' object has no attribute 'config'
When trying to execute
self.tick_img.config(img_red_tick)
Reply
#4
I would use a label for this.
class Lamp(tk.Label):
    """Use images to display True/False value"""
    def __init__(self, window, on_img, off_img, **kvargs):
        super().__init__(window, image=off_img, **kvargs)
        self.images = (off_img, on_img)
        self._value = False

    @property
    def value(self):
        """Get current value"""
        return self._value

    @value.setter
    def value(self, value):
        """Set current value.  If value changed, update image to reflect new value"""
        if value != self._value:
            self._value = value
            self['image'] = self.images[int(self._value)]

def toggle():
    """Toggle value every second to demonstrate lamp"""
    lamp.value = not lamp.value
    lamp.after(1000, toggle)

root = tk.Tk()
lamp = Lamp(root, tk.PhotoImage(file=IMAGE_DIR/'ttt_x.png'), tk.PhotoImage(file=IMAGE_DIR/'ttt_o.png'))
lamp.pack()
toggle()
root.mainloop()
Reply
#5
import tkinter as tk

root = tk.Tk()
canvas = tk.Canvas(root, height=100, width=100)
image = tk.PhotoImage(file='some_image_file.png')
x = canvas.create_image(50, 50, image=image)
y = canvas.create_line(0, 0, 100, 100)
canvas.pack()
print(x, type(x), y, type(y))
root.mainloop()
Output:
1 <class 'int'> 2 <class 'int'>
canvas.create_* returns an int. This is a unique ID for the object that was just created. In my example x is 1 and y is 2. If I created another canvas object it would probably be 3. To Python, the id is just an int and it doesn't provide any methods for configuring the canvas object. To modify the object you use canvas methods and pass the ID of the object you want to modify. This program gets a dictionary of all the options/attributes you can configure for a canvas image object.
import tkinter as tk

root = tk.Tk()
canvas = tk.Canvas(root, height=100, width=100)
canvas.pack()

image= tk.PhotoImage(file='image.png')
x = canvas.create_image(50, 50, image=image)
config_items = canvas.itemconfigure(x)  # Call without option arguments to get dictionary of all options
for items in config_items.items():
    print(items)
root.mainloop()
Output:
('activeimage', ('activeimage', '', '', '', '')) ('anchor', ('anchor', '', '', 'center', 'center')) ('disabledimage', ('disabledimage', '', '', '', '')) ('image', ('image', '', '', '', 'pyimage1')) ('state', ('state', '', '', '', '')) ('tags', ('tags', '', '', '', ''))
image is one of the options you can configure. This code uses itemconfigure to change the image after the canvas image object is created.
import tkinter as tk

root = tk.Tk()
canvas = tk.Canvas(root, height=100, width=100)
canvas.pack()

one = tk.PhotoImage(file='one.png')
two = tk.PhotoImage(file='two.png')
x = canvas.create_image(50, 50, image=one) # Create image object using image one
canvas.itemconfigure(x, image=two)         # Change image from one to two.
root.mainloop()
Other interesting options/atributes are "disabledimage" and "state". This code creates an image object that has a disabledimage. It uses the state option to toggle between the normal and disabled images.
import tkinter as tk

root = tk.Tk()
canvas = tk.Canvas(root, height=100, width=100)
canvas.pack()

def toggle():
    if canvas.itemconfigure(x)['state'][4] == tk.DISABLED:
        canvas.itemconfigure(x, state=tk.NORMAL)
    else:
        canvas.itemconfigure(x, state=tk.DISABLED)
    canvas.after(1000, toggle)

x = canvas.create_image(50, 50, image=tk.PhotoImage(file='one.png'), disabledimage=tk.PhotoImage(file='two.png'))

toggle()

root.mainloop()
Reply
#6
My 2 cents - Using deanhystad's example with state and imagedisabled. Replaced the after with a button.

#! /usr/bin/env python3
import tkinter as tk

root = tk.Tk()
canvas = tk.Canvas(root, height=120, width=100)
canvas.pack()

def toggle():
    if canvas.itemconfigure(x)['state'][4] == tk.DISABLED:
        canvas.itemconfigure(x, state=tk.NORMAL)
        btn['text'] = 'Turn off'
        btn['fg'] = 'red'
    else:
        canvas.itemconfigure(x, state=tk.DISABLED)
        btn['text'] = 'Turn on'
        btn['fg'] = 'green'

on = tk.PhotoImage(file='on.png')
off = tk.PhotoImage(file='off.png')
x = canvas.create_image(50, 50, image=on, disabledimage=off)
btn = tk.Button(root, text='Turn off', fg='red', command=toggle)
btn.pack()

root.mainloop()
I welcome all feedback.
The only dumb question, is one that doesn't get asked.

My Scripts
CookBook - Shmup - PyQt5 Music Player


Reply
#7
I can't decide if using disabledimage and state is a clever or really stupid idea. I'm leaning toward stupid and think Label is a much better choice for making an indicator lamp type widget. I only wrote the canvas/image version to provide ideas on how such a thing can be done. And also to show how you can dive in and get information about tkinter. I don't do a lot of tkinter programming, but from my limited experience I don't think the canvas fits in well with the other widgets. Everything except the canvas works one way, and the canvas does everything different. If I never had a need for scrolling views I wouldn't use the canvas at all (unless I needed something to draw on).
menator01 likes this post
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [Tkinter] Why does the image for the button not appear? finndude 4 117 Oct-21-2021, 06:41 PM
Last Post: deanhystad
  How can I loop PyAutoGUI's locateCenterOnScreen until the image is found? Tiel 2 302 Sep-26-2021, 09:39 AM
Last Post: Tiel
  looking for scripts that do simple image display Skaperen 10 675 Sep-13-2021, 05:35 PM
Last Post: FullOfHelp
  [Tkinter] image inside button rwahdan 4 639 Jul-12-2021, 08:49 PM
Last Post: deanhystad
  [Tkinter] image in label not showing? rwahdan 2 676 Jun-25-2021, 10:27 AM
Last Post: rwahdan
  tkinter showing image in button rwahdan 3 1,051 Jun-16-2021, 06:08 AM
Last Post: Yoriz
  [Tkinter] Overlay Still Image on Webcam Video KDog 4 1,060 May-18-2021, 08:29 PM
Last Post: KDog
  tkinter button image Nick_tkinter 4 1,321 Mar-04-2021, 11:33 PM
Last Post: deanhystad
  PyQt5 adding image thewolf 3 740 Feb-21-2021, 08:28 PM
Last Post: thewolf
  how to resize image in canvas tkinter samuelmv30 2 5,116 Feb-06-2021, 03:35 PM
Last Post: joe_momma

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020