im 100% new to coding and just started to follow some guides a few days ago. I am now making a digital clock for my desktop and i want to change my background to a custom image that i have.
Can someone explain to me where i can change it so that the background becomes my image that i have? BR
from tkinter import Tk
from tkinter import Label
import time
from PIL import Image, ImageTk
root = Tk()
root.title("Klocka")
root.attributes("-topmost", 1)
root.attributes('-alpha', 1)
root.iconbitmap('klocka.ico (1).ico')
root.geometry('600x400+50+50')
window_width = 255
window_height = 50
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
center_x = int(screen_width/3500 - window_width / 0.97)
center_y = int(screen_height/1 - window_height / 0.62)
root.geometry(f'{window_width}x{window_height}+{center_x}+{center_y}')
def present_time():
display_time = time.strftime("%I:%M:%S")
digi_clock.config(text=display_time)
digi_clock.after(200,present_time)
digi_clock = Label(root, font=("Arial",50),bg="black",fg="red")
digi_clock.pack()
present_time()
root.mainloop()
you can try image path and background image concept. First you have to choose image, then it's size and it's position.
IMAGE_PATH = 'PicNameHere.png'
WIDTH, HEIGTH = 200, 50
bkrgframe = BkgrFrame(root, IMAGE_PATH, WIDTH, HEIGTH)
bkrgframe.pack()
Code sample is below.
from tkinter import Tk
from tkinter import Label
import time
from PIL import Image, ImageTk
IMAGE_PATH = 'PicNameHere.png'
WIDTH, HEIGTH = 200, 50
root = Tk()
root.title("Klocka")
root.attributes("-topmost", 1)
root.attributes('-alpha', 1)
root.iconbitmap('klocka.ico (1).ico')
root.geometry('600x400+50+50')
window_width = 255
window_height = 50
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
center_x = int(screen_width/3500 - window_width / 0.97)
center_y = int(screen_height/1 - window_height / 0.62)
root.geometry(f'{window_width}x{window_height}+{center_x}+{center_y}')
bkrgframe = BkgrFrame(root, IMAGE_PATH, WIDTH, HEIGTH)
bkrgframe.pack()
def present_time():
display_time = time.strftime("%I:%M:%S")
digi_clock.config(text=display_time)
digi_clock.after(200,present_time)
digi_clock = Label(root, font=("Arial",50),bg="black",fg="red")
digi_clock.pack()
present_time()
root.mainloop()
You can show both an image and text in a Label widget using text, image and compound options:
img_tk = ImageTk.PhotoImage(file="path/to/image.png")
digi_clock = Label(root, font=("Arial",50), fg="red", image=img_tk, compound="center")
digi_clock.pack()
from tkinter import Tk
from tkinter import Label
import time
from PIL import Image, ImageTk
root = Tk()
root.title("Klocka")
root.attributes("-topmost", 1)
root.attributes('-alpha', 1)
root.iconbitmap('klocka.ico (1).ico')
root.geometry('600x400+50+50')
bg = PhotoImage(file = "Your_img.png")
canvas1 = Canvas( root, width = 400,
height = 400)
canvas1.pack(fill = "both", expand = True)
canvas1.create_image( 0, 0, image = bg,
anchor = "nw")
window_width = 255
window_height = 50
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
center_x = int(screen_width/3500 - window_width / 0.97)
center_y = int(screen_height/1 - window_height / 0.62)
root.geometry(f'{window_width}x{window_height}+{center_x}+{center_y}')
def present_time():
display_time = time.strftime("%I:%M:%S")
digi_clock.config(text=display_time)
digi_clock.after(200,present_time)
digi_clock = Label(root, font=("Arial",50),bg="black",fg="red")
digi_clock.pack()
present_time()
root.mainloop()
Related
I wanted to make the turtle go to a certain coordinate on a map and I got it working when I set it up as a standalone
import turtle
screen = turtle.Screen()
screen.setup(720, 360)
screen.bgpic('map.gif')
screen.setworldcoordinates(-180, -90, 180, 90)
quake = turtle.Turtle()
quake.color("red")
quake.turtlesize(1)
quake.shape("circle")
quake.penup()
quake.goto(-178.4746, -17.9625)
quake.stamp()
turtle.exitonclick()
This is what the correct location is supposed to be:
However, when I tried to have the turtle screen embedded on tkinter, the coordinates were off.
import turtle
from turtle import RawTurtle, TurtleScreen
import tkinter as tk
from tkinter import *
window = tk.Tk()
window.minsize(width = 720, height = 800)
def geoviz():
quake.goto(-178.4746, -17.9625)
quake.stamp()
button = Button(window, text="Compute Map", command= geoviz)
button.pack()
canvas = Canvas(window, width = 720, height = 360)
canvas.pack()
quake = RawTurtle(canvas)
quake.shape("circle")
quake.color("red")
screen = TurtleScreen(canvas)
screen.bgpic('map.gif')
screen.setworldcoordinates(-180, -90, 180, 90)
mainloop()
This is where the turtle stamp is instead, which is way off from the correct location:
Quick answer is, if you want to use your user defined coords then you need to use the screen as well:
quake = RawTurtle(screen)
will solve your issue.
def __init__(self, cv):
self.cv = cv
if isinstance(cv, ScrolledCanvas):
w = self.cv.canvwidth
h = self.cv.canvheight
else: # expected: ordinary TK.Canvas
w = int(self.cv.cget("width"))
h = int(self.cv.cget("height"))
self.cv.config(scrollregion = (-w//2, -h//2, w//2, h//2 ))
self.canvwidth = w
self.canvheight = h
self.xscale = self.yscale = 1.0
The coordinatesytem is given by the cv, if you wont work with canvas coordinates and use screencoordinates, you will need to pass the right argument. Full code:
import turtle
from turtle import RawTurtle, TurtleScreen
import tkinter as tk
from tkinter import *
window = tk.Tk()
window.minsize(width = 720, height = 800)
def geoviz():
quake.goto(-178.4746, -17.9625)
quake.stamp()
button = Button(window, text="Compute Map", command= geoviz)
button.pack()
canvas = Canvas(window, width = 720, height = 360)
canvas.pack()
screen = TurtleScreen(canvas)
screen.bgpic('map.gif')
screen.setworldcoordinates(-180, -90, 180, 90)
quake = RawTurtle(screen)
quake.shape("circle")
quake.color("red")
mainloop()
I am currently trying to display images on a canvas. More specifically, I would like to have the images that are drawn on the canvas to be resized based on the size of the window (this way the images are always going to fit on the canvas).
I start off with a simple canvas that fills the entire screen.
import tkinter as tk
from PIL import Image, ImageTk
root = tk.Tk()
WIDTH, HEIGHT = root.winfo_screenwidth(), root.winfo_screenheight()
root.geometry('%dx%d+0+0' % (WIDTH, HEIGHT))
canvas = tk.Canvas(root)
canvas.pack(fill="both", expand=True)
I then get set up with my background images and images that will be able to get resized on the background.
backgroundImage = ImageTk.PhotoImage(Image.open("filepath"))
image1 = Image.open("filepath")
image2 = ...
....
....
I then created a method for resizing the images.
"""
This method resizes a image so that all the images fits on the GUI. This first creates an Image object,
but since the Image object does not allow access to the width and height of the Image object, a ImageTk
object needs to be created from the Image object. The ImageTk object cannot resize, but the Image object
can. So using ImageTk object to get the height and width and the Image object to resize, a new Image object
that is resized to fit the GUI is created.
#imageFile- the image file that is being resized
#windowMeasure- the measurement of the window to proportionally resize the image
#useHeight- determine the measurement being proportioned
"""
def resizedImageTk(image, windowMeasure, useHeight):
imageTk = ImageTk.PhotoImage(image)
area = windowMeasure * 4/5
tileSize = area / 4
if useHeight:
proportion = tileSize / imageTk.height()
else:
proportion = tileSize / imageTk.width()
resizedImage = image.resize((int(imageTk.width()*proportion), int(imageTk.height()*proportion)))
resizedImageTk = ImageTk.PhotoImage(resizedImage)
return resizedImageTk
I then use a method for redrawing the resized images when there is a change to the size of the window and bind it to the root. Note: I know that this can be extremely computational and so I have reduced the number of times this occurs
numResizes = 0
def handle_configure(event):
if numResizes % 5 == 0:
geometry = root.geometry()
width = int(geometry[0:geometry.index("x")])
height = int(geometry[geometry.index("x")+1:geometry.index("+")])
canvas.create_image((0,0), image=backgroundImageTk, anchor="nw")
if height < width:
measurement = height
else:
measurement = width
resizedImage1 = resizedImageTk(image1, measurement, height < width)
resizedImage2 = ....
....
....
images = [resizedImage1, resizedImage2, ...]
imageWidth = resizedImage1.width()
imageHeight = resizedImage1.height()
i = 0
for row in range(0, int(len(images) / 4)):
for column in range(0, int(len(images) / 5):
x = imageWidth*column + int(width/2) - imageWidth * 2
y = imageHeight*row + int(height/2) - int(imageHeight*2.5)
canvas.create_image((x, y), image=images[i])
i=i+1
numResizes = numResizes + 1
root.bind("<Configure>", handle_configure)
root.mainloop()
I have run this with my images and have had some success, however, it does not work completely. I have my background image get displayed but my other images do not. I do not know why since when I use the create_line function for the canvas in the nested for loop (where the images are not being shown), I do get the line showing.
If someone could give some advice on this, I would appreciate it!
Thanks
Update:
Here is a simple sample of what I am trying to do. You can use any sample image to test this.
import tkinter as tk
from PIL import Image, ImageTk
root = tk.Tk()
WIDTH, HEIGHT = int(root.winfo_screenwidth() * 103/104), int(root.winfo_screenheight() * 11/12)
root.geometry('%dx%d+0+0' % (WIDTH, HEIGHT))
canvas = tk.Canvas(root)
canvas.pack(fill="both", expand=True)
testImage = Image.open("enter file path here!")
testImageTk = ImageTk.PhotoImage(testImage)
resizedTestImage = None
resizedTestImageTk = None
def handle_configure(event):
geometry = root.geometry()
width = int(geometry[0:geometry.index("x")])
height = int(geometry[geometry.index("x")+1:geometry.index("+")])
useHeight = height < width
if useHeight:
measurement = height
else:
measurement = width
if useHeight:
proportion = measurement / testImageTk.height()
else:
proportion = measurement / testImageTk.width()
resizedTestImage = testImage.resize((int(testImageTk.width()*proportion), int(testImageTk.height()*proportion)))
resizedTestImageTk = ImageTk.PhotoImage(resizedTestImage)
canvas.create_image((0,0), image=resizedTestImageTk, anchor="nw")
print("(image width, image height): (" + str(resizedTestImageTk.width()) + " " + str(resizedTestImageTk.height()) + ")")
root.bind("<Configure>", handle_configure)
root.mainloop()
Your new code has problem with bug in PhotoImage.
Inside handle_configure you assign to local variable resizedTestImageTk even if you already created external/global variable resizedTestImageTk
It works for me if I inform function that it has to use global to inform function that it has to assign it to external variable instead of local one
def handle_configure(event):
global resizedTestImageTk # <-- inform function to assign image to global variable instead of using local one
or I assign local resizedTestImageTk to global class.
canvas.resizedTestImageTk = resizedTestImageTk # <-- assign local `resizedTestImageTk` to global class.
Minimal working code.
I changed some calculations to make it more readable.
import tkinter as tk
from PIL import Image, ImageTk
# --- functions ---
def handle_configure(event):
global resizedTestImageTk # <-- inform function to assign image to global variable instead of using local one
geometry = root.geometry()
window_width = int(geometry[0:geometry.index("x")])
window_height = int(geometry[geometry.index("x")+1:geometry.index("+")])
image_width = testImageTk.height()
image_height = testImageTk.width()
if window_height < window_width:
proportion = window_height / image_height
else:
proportion = window_width / image_width
image_width = int(image_width * proportion)
image_height = int(image_height * proportion)
resizedTestImage = testImage.resize((image_width, image_height))
resizedTestImageTk = ImageTk.PhotoImage(resizedTestImage)
canvas.create_image((0,0), image=resizedTestImageTk, anchor="nw")
#canvas.resizedTestImageTk = resizedTestImageTk # <-- assign local `resizedTestImageTk` to global class.
print(f"(image width, image height): ({image_width} {image_height})")
# --- main ---
root = tk.Tk()
WIDTH = int(root.winfo_screenwidth() * 103/104)
HEIGHT = int(root.winfo_screenheight() * 11/12)
root.geometry('%dx%d+0+0' % (WIDTH, HEIGHT))
canvas = tk.Canvas(root)
canvas.pack(fill="both", expand=True)
testImage = Image.open("lenna.png")
testImageTk = ImageTk.PhotoImage(testImage)
resizedTestImage = None
resizedTestImageTk = None
root.bind("<Configure>", handle_configure)
root.mainloop()
And image for test
Wikipedia: Lenna
EDIT:
I see other problem - not so visible. You always put new image on but you don't remove old image - so finally it may use more memory.
You could put image on canvas at start - and get its ID
image_id = canvas.create_image((0,0), image=testImageTk, anchor="nw")
and later replace image using ID
canvas.itemconfig(image_id, image=resizedTestImageTk)
Minimale working code:
import tkinter as tk
from PIL import Image, ImageTk
# --- functions ---
def handle_configure(event):
global resizedTestImageTk # <-- inform function to assign image to global variable instead of using local one
geometry = root.geometry()
window_width = int(geometry[0:geometry.index("x")])
window_height = int(geometry[geometry.index("x")+1:geometry.index("+")])
image_width = testImageTk.width()
image_height = testImageTk.height()
if window_height < window_width:
proportion = window_height / image_width
else:
proportion = window_width / image_height
image_width = int(image_width * proportion)
image_height = int(image_height * proportion)
resizedTestImage = testImage.resize((image_width, image_height))
resizedTestImageTk = ImageTk.PhotoImage(resizedTestImage)
canvas.itemconfig(image_id, image=resizedTestImageTk)
#canvas.resizedTestImageTk = resizedTestImageTk # <-- assign local `resizedTestImageTk` to global class.
print(f"(image width, image height): ({image_width} {image_height})")
# --- main ---
image_id = None # default value at start
root = tk.Tk()
WIDTH = int(root.winfo_screenwidth() * 103/104)
HEIGHT = int(root.winfo_screenheight() * 11/12)
root.geometry('%dx%d+0+0' % (WIDTH, HEIGHT))
canvas = tk.Canvas(root)
canvas.pack(fill="both", expand=True)
testImage = Image.open("lenna.png")
testImageTk = ImageTk.PhotoImage(testImage)
resizedTestImage = None
resizedTestImageTk = None
image_id = canvas.create_image((0,0), image=testImageTk, anchor="nw")
root.bind("<Configure>", handle_configure)
root.mainloop()
I created this little algorithm that is supposed to draw an image (imagine that my brush is an image) so that when I keep clicking I will draw the image, but as you can see if you test the code, it does not paint.
What it does is just moves the image across the Canvas.
Is there a way for the image to remain on the Canvas?
Here is my code:
from tkinter import *
from PIL import Image, ImageTk
master = Tk()
w = Canvas(master, width=800, height=400)
w.pack(expand = YES, fill = BOTH)
imagen = Image.open('C:/Users/Andres/Desktop/hola.png')
P_img = ImageTk.PhotoImage(imagen)
def paint( event ):
global w, P_img_crop
#I get the mouse coordinates
x, y = ( event.x - 1 ), ( event.y - 1 )
#I open and draw the image
img_crop = Image.open('C:/Users/Andres/Desktop/papa.png')
P_img_crop = ImageTk.PhotoImage(img_crop)
w.create_image((x,y), anchor=NW, image=P_img_crop)
w.bind( "<B1-Motion>", paint )
mainloop()
I GOT IT
I did not know that the image that was drawn on the canvas, should be saved, so what I did is store the images in a matrix, which belongs to the canvas.
Here is the code, just in case ...
from tkinter import *
from PIL import Image, ImageTk
master = Tk()
w = Canvas(master, width=800, height=400)
w.dib = [{} for k in range(10000)]
w.pack(expand = YES, fill = BOTH)
puntero = 0
def paint( event ):
global w, P_img_crop, puntero
#I get the mouse coordinates
x, y = ( event.x - 1 ), ( event.y - 1 )
#I open and draw the image
img_crop = Image.open('C:/Users/Andres/Documents/PROYECTOS INCONCLUSOS/PAINT MATEW PYTHON/hola.png')
w.dib[puntero]['image'] = ImageTk.PhotoImage(img_crop)
w.create_image((x,y), anchor=NW, image=w.dib[puntero]['image'])
puntero += 1
if(puntero >=10000):
puntero = 0
w.bind( "<B1-Motion>", paint )
mainloop()
All you need to do remove the image creation inside the paint() function. Then you will achieve what you want because otherwise it creates the image again and doesn't save a copy behind. In other words, when you move the brush, the previous image is garbage collected.
Code:
from tkinter import *
from PIL import Image, ImageTk
master = Tk()
w = Canvas(master, width=800, height=400)
w.pack(expand = YES, fill = BOTH)
img_crop = Image.open('yes.png')
P_img_crop = ImageTk.PhotoImage(img_crop)
def paint(event):
global P_img_crop
#I get the mouse coordinates
x, y = event.x - 1, event.y - 1
#I open and draw the image
w.create_image(x, y, image = P_img_crop)
w.bind("<B1-Motion>", paint)
master.mainloop()
Hope this helps!
I was trying to create and display an empty image to edit and update later on. This code worked when not using tkinter, just the image display. When i run the following code:
from random import randint
from time import *
from PIL import Image as Img
from PIL import ImageTk as ImgTk
from tkinter import *
main = Tk()
main.geometry('1001x1001')
width, height = map(int, input('width and height\n').split())
canvas = Canvas(main, width = width, height = height)
canvas.pack()
next_cells = []
img = Img.new('RGB', (width, height))
pix = img.load()
tkpix = ImgTk.PhotoImage(pix)
imgsprite = canvas.create_image(width,height,image=pix)
main.mainloop()
I get the following error:
File "/Applications/eeie", line 14, in <module>
tkpix = ImgTk.PhotoImage(pix)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/PIL/ImageTk.py", line 108, in __init__
mode = Image.getmodebase(mode)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/PIL/Image.py", line 275, in getmodebase
return ImageMode.getmode(mode).basemode
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/PIL/ImageMode.py", line 64, in getmode
return _modes[mode]
builtins.KeyError: <PixelAccess object at 0x108aa4790>
What is causing this error?
Here you go, description in code.
from tkinter import *
import Image, ImageTk
# create canvas
canvas = Canvas(width=300, height=200, bg='black')
canvas.pack()
# create image object
img = Image.new('RGB', (60, 30), color='red')
new_image = ImageTk.PhotoImage(img)
# load into canvas
canvas.create_image(50, 10, image=new_image, anchor=NW)
mainloop()
Output:
To update canvas create function, and update root after changes to the object are made.
from tkinter import *
import Image, ImageTk
import time
def update_position():
while True:
canvas.move(rectangle, 30, 10)
time.sleep(1)
root.update()
root = Tk()
# create canvas
canvas = Canvas(root, width=300, height=200, bg='black')
canvas.pack()
# create image object
img = Image.new('RGB', (60, 30), color='red')
new_image = ImageTk.PhotoImage(img)
# load into canvas
rectangle = canvas.create_image(50, 10, image=new_image, anchor=NW)
update_position()
root.mainloop()
I am trying to paste several images end to end and then display on canvas. I cannot figure out why this image is showing as black. Any Ideas?
from tkinter import *
from PIL import Image, ImageTk
root = Tk()
canvas = Canvas(root, width=1000, height=800)
canvas.pack()
grass = Image.open(r"C:\pathto\grass.gif")
water = Image.open(r"C:\pathto\ffwater.gif")
r1 = ['g','g','g','w','w','w','g','g']
row = Image.new('RGB', (1000, 800))
xx = 0
for i in r1:
if i == 'g':
img = grass
if i == 'w':
img = water
row.paste(img, (xx, 0))
xx = xx + img.size[0]
worldr1 = ImageTk.PhotoImage(row)
canvas.create_image(0,0, image=worldr1)
root.mainloop()
The image is black because it is only partially visible on the Canvas. I replaced
canvas.create_image(0,0, image=worldr1)
by
canvas.create_image(0,0, anchor="nw", image=worldr1)
and the full image was visible on the Canvas (the default value is anchor="center").