How to update tkinter label text in real time - python

I have an application that gets the css3 colour of the pixel your cursor is on, and I would like to use tkinter to display the text in a little window. I following is the tkinter part of my code:
import pyautogui, PIL
import tkinter as tk
def cursorpixel():
x,y = pyautogui.position()
pixel = (x,y,x+1,y+1)
return pixel
def grabColor(square, max_colors=256):
img=PIL.ImageGrab.grab(square)
color = img.getcolors(max_colors)
return color
def main():
root=tk.Tk()
root.minsize(150, 50)
color = tk.Label(root,
text= grabColor(cursorpixel()),
fg = "black",
font = "Arial").pack()
root.mainloop()
while __name__ == "__main__":
main()
This works as I want, without the function of updating the label text whenever my cursor moves across the screen. It works once when launching the application and the label text stays the same. How would I make it so the label text updates whenever my cursor moves? I am using python 3.7
Thank you

Assigning a variable to the text argument doesn't help, because even if the value of the variable changes, it will not be reflected in the label. Here is my approach to this (this is just one out of many possible ways)
import pyautogui, PIL
import tkinter as tk
from threading import Thread
def cursorpixel():
x,y = pyautogui.position()
pixel = (x,y,x+1,y+1)
grabColor(pixel)
def grabColor(square, max_colors=256):
global color_label,root
img=PIL.ImageGrab.grab(square)
color = img.getcolors(max_colors)
color_label.config(text=color)
def refresh():
while True:
cursorpixel()
def main():
global color_label,root
root=tk.Tk()
root.minsize(150, 50)
color_label = tk.Label(root,
fg = "black",
font = "Arial")
color_label.pack()
Thread(target=refresh).start()
root.mainloop()
if __name__ == "__main__":
main()
NOTES
I have used multi threading instead and created a function refresh() which triggers the cursorpixel() in an infinite loop.
I have called the grabColor() function from cursorpixel() having pixel as parameter.
I have used the color_label.config() method to change the text in the label, you could also use color_label['text'] or maybe assign a textvariable var = StringVar() to the label and then use var.set() on it.
I am not sure if it is a good choice to put the __name__='__main__' in a while loop as you will not be able to close the window without terminating the task, new one will pop up every time you try to do so.

Answer
I added the .after command into the grabColor() function and combined the cursorpixel and grabColor() functions. I used .config to update the color. Here is the code:
import pyautogui, PIL
from tkinter import *
root=Tk()
root.minsize(150, 50)
colortext = Label(root)
colortext.pack()
def grabColor():
x,y = pyautogui.position()
pixel = (x,y,x+1,y+1)
img=PIL.ImageGrab.grab(bbox=pixel)
color = img.getcolors()
colortext.config(text=str(color))
root.after(100, grabColor)
grabColor()
root.mainloop()
Sources / Additional Resources
How do I create an automatically updating GUI using Tkinter?

You can use after() to grab the color periodically:
import tkinter as tk
from PIL import ImageGrab
def grab_color(label):
x, y = label.winfo_pointerxy()
color = ImageGrab.grab((x, y, x+1, y+1)).getpixel((0, 0))
label.config(text=str(color))
label.after(100, grab_color, label)
def main():
root = tk.Tk()
color_label = tk.Label(root, width=20)
color_label.pack(padx=10, pady=10)
grab_color(color_label)
root.mainloop()
if __name__ == "__main__":
main()
Note that winfo_pointerxy() is used instead of pyautogui.position() to reduce dependency on external module.

Related

Images not getting applied on the button in Tkinter

The following project is supposed to show a message when clicking a certain colored button. But, whenever I execute the program it shows blank(white) buttons in the correct alignment, etc. Due to some reason the images are not loaded.
In future, I plan to add different images hence testing with colored image created in Paint and not in-built commands to show the color.
I will add the result below after the code.
Edit: All images are 100x100 pixels created in Microsoft Paint.I have tried other modules like PIL but to no avail.
# importing the module
import tkinter
import tkinter.messagebox
from tkinter import *
# importing the module
# initialising tkinter
class window(Frame):
def __init__(self,master = None):
Frame.__init__(self,master)
self.master = master
# initialising tkinter
# creating the window
root = Tk()
app = window(root)
root.geometry("350x350")
# creating the window
# colours
WHITE = (255,255,255)
BLACK = (0,0,0)
BLUE = (0,0,255)
RED = (255,0,0)
# colours
# image
red_image = "red.png"
blue_image = "blue.png"
yellow_image = "yellow.png"
green_image = "green.png"
# image
# creating a button function
def create_button(x,y,color,color2,picture):
click = Button(root, image = PhotoImage(picture), width= 150, height=150, command = lambda : tkinter.messagebox.showinfo( "Hello Python", "This is " + color))
click.image = PhotoImage(picture)
click.grid( row = x, column = y)
# creating a button function
create_button(0,0,'red','pink',red_image)
create_button(0,2,'blue','lightblue',blue_image)
create_button(2,0,'green','lightgreen',green_image)
create_button(2,2,'yellow','lightyellow',yellow_image)
# starting the widget
root.mainloop()
# starting the widget
There are two issues in your code:
You passed filename to PhotoImage() without using file keyword: PhotoImage(picture) should be PhotoImage(file=picture)
You did not keep the reference of the image assigned to button, but another instance of image
Below is the updated create_button() function that fixes the issues:
def create_button(x, y, color, color2, picture):
image = PhotoImage(file=picture)
click = Button(root, image=image, width=150, height=150, command=lambda: tkinter.messagebox.showinfo("Hello Python", "This is "+color))
click.image = image
click.grid(row=x, column=y)
For adding image in Button you have not use appropriate keywords.
Here is a simple example for you to add image in button
from tkinter import *
from tkinter.ttk import *
# creating tkinter window
root = Tk()
# Adding widgets to the root window
Label(root, text = 'Image adding', font =( 'Verdana',15)).pack(side = TOP, pady = 10)
# Creating a photoimage object to use image
photo = PhotoImage(file = "C:\Gfg\circle.png")
# here, image option is used to
# set image on button
Button(root, text = 'Click Me !', image = photo).pack(side = TOP)
root.mainloop()
I think it may help you

Create functions to pack one widget and remove all others when different keys are pressed

I am making a controller for a car with Python and I was going to have 3 separate images to represent whether the wheels are turning left, right, or neutral. I need only one of these images to be shown at a time.
So far I have used bind to trigger functions because I haven't seen any other way to do so. I have looked into pack and pack_forget but I don't know how I could trigger them to be activated by other widgets (since I am using bind).
import tkinter as tk
win = tk.Tk()
def forwards(event):
print("going forwards...")
def left(event):
print("turning left...")
def right(event):
print("turning right...")
def backwards(event):
print("going backwards...")
neutralImage = tk.PhotoImage(file="neutral.gif")
leftImage = tk.PhotoImage(file="turnedLeft.gif")
rightImage = tk.PhotoImage(file="turnedRight.gif")
neutralPosition = tk.Label(win, image=neutralImage)
leftPosition = tk.Label(win, image=leftImage)
rightPosition = tk.Label(win, image=rightImage)
win.bind("w", forwards)
win.bind("a", left)
win.bind("d", right)
win.bind("s", backwards)
I have identified the problem as the following: I can't hide or show the widgets unless it is them that I press the button over.
Instead of having three widgets what you can do is replace the image of the same widget when you need it.
import tkinter as tk
def changeImage(imageLabelWidget, newImage):
imageLabelWidget.configure(image=newImage)
imageLabelWidget.image = newImage
win = tk.Tk()
neutralImage = tk.PhotoImage(file="neutral.gif")
leftImage = tk.PhotoImage(file="turnedLeft.gif")
rightImage = tk.PhotoImage(file="turnedRight.gif")
neutralPosition = tk.Label(win, image=neutralImage)
neutralPosition.image = neutralImage
neutralPosition.pack()
win.bind("w", lambda event, imageLabelWidget=neutralPosition, newImage=neutralImage:
changeImage(imageLabelWidget, newImage))
win.bind("a", lambda event, imageLabelWidget=neutralPosition, newImage=leftImage:
changeImage(imageLabelWidget, newImage))
win.bind("d", lambda event, imageLabelWidget=neutralPosition, newImage=rightImage:
changeImage(imageLabelWidget, newImage))
win.mainloop()

Fast changing labels in Tkinter?

I would like to display some numbers, as fast as possible in Tkinter. The Program, I am trying to do, gets many numbers send and should show those.
Here is an similar environment, where tinter has to change a label very quickly.
from tkinter import *
import time
window = Tk()
lbl13 = Label(window, text="-")
lbl13.grid(column=0, row=0)
x = 0
while 1:
lbl13.config(text = str(x))
time.sleep(2)
x +=1
window.mainloop()
The Tkinter window doesn't even open on my computer. Is that because i have too weak hardware? What could I change that this Program also runs on my Computer. Thank you for every answer!
The infinite while loop will keep the program from getting to the line where you call window.mainloop(). You should call window.update() repeatedly instead of window.mainloop() at the end:
from tkinter import *
import time
window = Tk()
lbl13 = Label(window, text="-")
lbl13.grid(column=0, row=0)
x = 0
while 1:
lbl13.config(text = str(x))
window.update()
x +=1
Using after and a proper mainloop is probably a more more flexible way to achieve what you want; it is also reusable in different contexts, and can be used in an application that does more than trivially increment a number on a label:
maybe something like this:
import tkinter as tk
if __name__ == '__main__':
def increment():
var.set(var.get() + 1)
label.after(1, increment)
window = tk.Tk()
var = tk.IntVar(0)
label = tk.Label(window, textvariable=var)
label.pack()
increment()
window.mainloop()

Tkinter Button not changing from entry

Just messing around with tkinter for the first time and I dont know why my buttons are not working. Basically the input_grade is supposed to get a value from entry_for_grades which is quiz_amount and just print it on the same window but I keep getting back 0
I looked up and thought I was suppose to use lambda but it keeps giving me 0 regardless of what I have in entry and press ok
from tkinter import *
quiz_amount = IntVar()
def quiz():
quiz_window = Tk()
window(quiz_window)
quiz_window.title('Quiz Grades')
width = quiz_window.winfo_width()
height= quiz_window.winfo_height()
quiz_window.geometry('{}x{}'.format(width, height))
entry_for_grades = Entry(quiz_window, textvariable=quiz_amount)
entry_for_grades.pack()
grade_amount = Button(quiz_window,text='Ok',command=lambda:see_text(quiz_window)).place(x=85,y=60)
def see_text(window):
Label(window,text=float(quiz_amount.get())).place(x=85,y=90)
I used your code and made it a Minimal, Reproducible Example (I think) and it works fine for me.
Here is the code:
from tkinter import *
def quiz(quiz_window):
# window(quiz_window)
quiz_window.title('Quiz Grades')
width = quiz_window.winfo_reqwidth()
height= quiz_window.winfo_reqheight()
quiz_window.geometry('{}x{}'.format(width, height))
entry_for_grades = Entry(quiz_window, textvariable=quiz_amount)
entry_for_grades.pack()
grade_amount = Button(quiz_window,text='Ok',command=lambda:see_text(quiz_window)).place(x=85,y=60)
def see_text(window):
Label(window,text=float(quiz_amount.get())).place(x=85,y=90)
if __name__ == '__main__':
quiz_window = Tk()
quiz_amount = IntVar()
quiz(quiz_window)
quiz_window.mainloop()
The only problem I can think of is, like Novel said, you are using more than one Tk() window and trying to pass variables between these windows.
You should almost never use more than one Tk() window since you cannot pass information between two Tk() windows. Instead use TopLevel() windows, information can flow freely between Tk() and TopLevel() windows.

How do i pause my code before displaying the label

In my code, I am trying to make a loading screen for a frogger game but for some reason I am encountering a problem where I display a picture and then do the .sleep function before displaying a label over the top of it however it displays both of them at the same time it just runs the code 1 second after it should, can anyone help?
Here is my code below:
from tkinter import *
import tkinter as tk
import time
window = Tk()
window.geometry("1300x899")
LoadingScreen = PhotoImage(file = "FroggerLoad.gif")
Loading = Label(master = window, image = LoadingScreen)
Loading.pack()
Loading.place(x = 65, y = 0)
time.sleep(1)
FroggerDisplay = Label(master = window, font ("ComicSans",100,"bold"),text = "Frogger")
FroggerDisplay.pack()
FroggerDisplay.place(x = 500, y = 300)
window.mainloop()
When you use time.sleep(1) before starting the window.mainloop(), the window is created only after 1 second, and the FroggerDisplay label will be created at the same time with it. So, you can't use time.sleep(seconds) now.However, you can use window.after(ms, func) method, and place into the function all the code between time.sleep(1) and window.mainloop(). Note, that unlike the time.sleep(seconds) you must give the time to window.after (the first argument) as milliseconds.Here is the edited code:
from tkinter import *
def create_fd_label():
frogger_display = Label(root, font=("ComicSans", 100, "bold"), text="Frogger") # create a label to display
frogger_display.place(x=500, y=300) # place the label for frogger display
root = Tk() # create the root window
root.geometry("1300x899") # set the root window's size
loading_screen = PhotoImage(file="FroggerLoad.gif") # create the "Loading" image
loading = Label(root, image=loading_screen) # create the label with the "Loading" image
loading.place(x=65, y=0) # place the label for loading screen
root.after(1000, create_fd_label) # root.after(ms, func)
root.mainloop() # start the root window's mainloop
PS: 1) Why do you use .pack(...) and then .place(...) methods at the same time - the first one (.pack(...) here) will be ignored by Tkinter.
2) It's better to use a Canvas widget for creating a game - unlike labels it supports transparency and simpler to use. For example:
from tkinter import *
root = Tk() # create the root window
root.geometry("1300x899") # set the root window's size
canv = Canvas(root) # create the Canvas widget
canv.pack(fill=BOTH, expand=YES) # and pack it on the screen
loading_screen = PhotoImage(file="FroggerLoad.gif") # open the "Loading" image
canv.create_image((65, 0), image=loading_screen) # create it on the Canvas
root.after(1000, lambda: canv.create_text((500, 300),
font=("ComicSans", 100, "bold"),
text="Frogger")) # root.after(ms, func)
root.mainloop() # start the root window's mainloop
Note: you might need to change coords with Canvas.

Categories