Add lable, textbox and button to tkinter canvas - python

How to add a label, textbox and button to a program in which an image is display using tkinter canvas. In this program, an image is displayed to user. Lines are drawn over image on mouse click at different position. I want to add a textbox and a button, so that user can enter name for the object drawn using mouse clicks. For example, Enter label: textboxforinputname__Button to enter.
from Tkinter import *
import Image, ImageTk, ImageDraw
import numpy as np
coord=[] # for saving coord of each click position
Dict_Polygon={} # Dictionary for saving polygon
list_of_points=[]
flag=True
label=0
def draw_lines(event):
mouse_xy = (event.x, event.y)
func_Draw_lines(mouse_xy)
def func_Draw_lines(mouse_xy):
center_x, center_y = mouse_xy
if canvas.old_coords:
x1, y1 = canvas.old_coords
canvas.create_line(center_x, center_y, x1, y1)
# add clicked positions to list
if flag==True:
list_of_points.append(mouse_xy)
canvas.old_coords = center_x, center_y
# Main function
if __name__ == '__main__':
root = Tk()
# Input image
img = Image.open("test.jpg")
# Draw canvas for iput image to pop up image for clicks
filename = ImageTk.PhotoImage(img)
canvas = Canvas(root,height=img.size[0],width=img.size[0])
canvas.image = filename
canvas.create_image(0,0,anchor='nw',image=filename)
canvas.pack()
canvas.old_coords = None
# bind function to canvas to generate event
canvas.bind("<Button 3>", draw_lines)
root.mainloop()

Related

Pyglet displaying text over image

I am trying to display some text over an image using the pyglet library. However, I keep getting this "Texture Region" popping up instead of the actual text I included..Hoping someone can help.
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
# width of window
width = 900
# height of window
height = 900
# caption i.e title of the window
title = "E MAJOR"
# creating a window
window = pyglet.window.Window(width, height, title)
# text
text = "E MAJOR"
# creating label with following properties
# font = cooper
# position = 250, 150
# anchor position = center
label = pyglet.text.Label("E MAJOR",
font_name='Cooper',
color=(255,255,255,255),
font_size=36,
x=425,
y=50,
anchor_x='center',
anchor_y='center')
# creating a batch
batch = pyglet.graphics.Batch()
# loading geeksforgeeks image
image = pyglet.image.load('e-major.png')
# creating sprite object
# it is instance of an image displayed on-screen
sprite = pyglet.sprite.Sprite(image, x=100, y=25)
# on draw event
#window.event
def on_draw():
# clear the window
window.clear()
# draw the image on screen
sprite.draw()
# draw the label
label.draw()
# key press event
#window.event
def on_key_press(symbol, modifier):
# key "C" get press
if symbol == key.C:
# printing the message
print("Key : C is pressed")
# image for icon
img = image = pyglet.resource.image("e-major.png")
# setting image as icon
window.set_icon(img)
# loading image resource
value = pyglet.resource.image("e-major.png")
# setting text of label
label.text = str(value)
# start running the application
pyglet.app.run()
Looks like getting rid of
# setting text of label
label.text = str(value)
fixed this issue

Image not getting drawn on tkinter canvas

I would like to display a knapsack image on green canvas. The height and width of that canvas is 250X250 pixels.
And the size of the image is 260X280 pixels.
When I try to execute below code, I get the output as shown in screenshot above 1. The location of the code file and image file is same.
from tkinter.font import BOLD
from tkinter import *
import tkinter
from PIL import Image, ImageTk
root = Tk()
def draw():
global canvas
root.geometry('1080x720')
root.state('zoomed')
canvas = Canvas(root,bg='black',highlightthickness=0)
canvas.pack(fill=tkinter.BOTH, expand=True)
sw = root.winfo_screenwidth()
sh = root.winfo_screenheight()
canvas.create_line(int(sw*0.0000),int(sh*0.1736),int(sw*0.6510),int(sh*0.1736),fill='white')
canvas.create_line(int(sw*0.6510),int(sh*0.0000),int(sw*0.6510),int(sh*1.0000),fill='white')
canvas.create_line(int(sw*0.6510),int(sh*0.1157),int(sw*1.0000),int(sh*0.1157),fill='white')
canvas.create_line(int(sw*0.6510),int(sh*0.8101),int(sw*1.0000),int(sh*0.8101),fill='white')
UI_frame1 = Frame(canvas,bg='black',width=int(sw*0.6510),height=int(sh*0.1580))
canvas.create_window(0,0, anchor=NW,window=UI_frame1)
N = Label(UI_frame1,text='N',bg ='black',fg='white',font=(12))
N.grid(row=0,column=0, padx=139,pady=22)
weights = Label(UI_frame1,text='Weights',bg ='black',fg='white',font=(12))
weights.grid(row=0,column=1,padx=140,pady=22)
val = Label(UI_frame1,text='Values',bg ='black',fg='white',font=(12))
val.grid(row=0,column=2,padx=140,pady=22)
n = Entry(UI_frame1,bg='white',width=4,font=(12))
n.grid(row=1,column=0,padx=50,pady=17)
value_arr = Entry(UI_frame1,bg='white',font=(12))
value_arr.grid(row=1,column=1,padx=50,pady=17)
weight_arr = Entry(UI_frame1,bg='white',font=(12))
weight_arr.grid(row=1,column=2,padx=50,pady=17)
Label(canvas,text='i',bg='black',fg='white',font=(14)).place(x=150,y=185)
i = Label(canvas,text=" i ",bg='white',font=(12)).place(x=175,y=185)
Label(canvas,text='j',bg='black',fg='white',font=(14)).place(x=525,y=185)
j = Label(canvas,text=" j ",bg='white',font=(12)).place(x=550,y=185)
table = Canvas(canvas,bg='red',width=600,height=450)
table.place(x=75,y=300)
w = int(600/8)
h = int(450/5)
x=0
y=0
for r in range(5):
for c in range(8):
table.create_rectangle(x,y,x+w,y+h)
x+=w
y+=h
x=0
UI_frame2 = Frame(canvas,bg='blue',width=250,height=250)
canvas.create_window(835,630, anchor=CENTER,window=UI_frame2)
image_c = Canvas(UI_frame2,bg='green',highlightthickness=0,width=250,height=250)
image_c.grid(row=0,column=0,padx=0,pady=0)
photo = ImageTk.PhotoImage(file ='knapsack.png')
image_c.create_image(835,630,image=photo,anchor=NW)
draw()
root.mainloop()
I would like to cover the entire green canvas with single image of knapsack. I am not any error while running the GUI. Anyone could help me out, I'll be really thankful.
There are two problems:
First:
You display in position (835,630) but canvas has visible only (250, 250) - (top left corner is (0,0)) - so photo is in place which you can see.
Second:
There is bug in PhotoImage() which removes image from memory when it is assigned to local variable. One of solution is to use global photo to assign it to global variable.
def draw():
global canvas
global photo # use global variable
#... code ...
photo = ImageTk.PhotoImage(file='knapsack.png')
image_c.create_image(0, 0,image=photo, anchor=NW) # position (0,0)
Doc (on archive.org): PhotoImage - see Note at the botton of doc.
Other problem can be that image has big (transparent) margins around object and it may show object in differnt place then you may expect.
Screenshot shows photo in position (0,0) but object is in center of green canvas.

Image in Button tkinter

I am having a problem in making a login image to a button. I have succeeded in making the image with a transparent background, but I can't succeed to make the button with transparent background.
I attached a screenshot that shows what I mean. The upper 'login' is a image (with transparent background), the lower is Login button but there is a white background around it. I want to make a button with transparent background.
self.login_image = Image.open('images/LoginButton.png')
self.login_image = ImageTk.PhotoImage(self.login_image)
self.main_screen_canvas.create_image(700, 300, image=self.login_image)
self.login_button = Button(self.main_screen_canvas, borderwidth=0, image=self.login_image)
self.login_button.place(x=300,y=400)
What should I do?
BackgroundImage
LoginButtonImage
Here's how to do what I was suggesting in the comment which uses the technique shown in another answer of mine to simulate a tkinter Button on a Canvas that has a transparent image placed on it (instead of text).
One issue I ran into was that fact that your 2421 × 1210 pixel background image was larger than my screen. To deal with it I added a fitrect() helper function to determine a new smaller size for it that would fit. I wrote it a long time ago, but have found it handy to have around many times (like now). Note that in the code ll and ur refer to the lower-left and upper-right corners of the rectangles involved.
Here's the resulting code:
from PIL import Image, ImageTk
import tkinter as tk
class CanvasButton:
""" Create left mouse button clickable canvas image object.
The x, y coordinates are relative to the top-left corner of the canvas.
"""
flash_delay = 100 # Milliseconds.
def __init__(self, canvas, x, y, image_source, command, state=tk.NORMAL):
self.canvas = canvas
if isinstance(image_source, str):
self.btn_image = tk.PhotoImage(file=image_source)
else:
self.btn_image = image_source
self.canvas_btn_img_obj = canvas.create_image(x, y, anchor='nw', state=state,
image=self.btn_image)
canvas.tag_bind(self.canvas_btn_img_obj, "<ButtonRelease-1>",
lambda event: (self.flash(), command()))
def flash(self):
self.set_state(tk.HIDDEN)
self.canvas.after(self.flash_delay, self.set_state, tk.NORMAL)
def set_state(self, state):
""" Change canvas button image's state.
Normally, image objects are created in state tk.NORMAL. Use value
tk.DISABLED to make it unresponsive to the mouse, or use tk.HIDDEN to
make it invisible.
"""
self.canvas.itemconfigure(self.canvas_btn_img_obj, state=state)
def fitrect(r1_ll_x, r1_ll_y, r1_ur_x, r1_ur_y, r2_ll_x, r2_ll_y, r2_ur_x, r2_ur_y):
""" Find the largest rectangle that will fit within rectangle r2 that has
rectangle r1's aspect ratio.
Note: Either the width or height of the resulting rect will be
identical to the corresponding dimension of rect r2.
"""
# Calculate aspect ratios of rects r1 and r2.
deltax1, deltay1 = (r1_ur_x - r1_ll_x), (r1_ur_y - r1_ll_y)
deltax2, deltay2 = (r2_ur_x - r2_ll_x), (r2_ur_y - r2_ll_y)
aspect1, aspect2 = (deltay1 / deltax1), (deltay2 / deltax2)
# Compute size of resulting rect depending on which aspect ratio is bigger.
if aspect1 > aspect2:
result_ll_y, result_ur_y = r2_ll_y, r2_ur_y
delta = deltay2 / aspect1
result_ll_x = r2_ll_x + (deltax2 - delta) / 2.0
result_ur_x = result_ll_x + delta
else:
result_ll_x, result_ur_x = r2_ll_x, r2_ur_x
delta = deltax2 * aspect1
result_ll_y = r2_ll_y + (deltay2 - delta) / 2.0
result_ur_y = result_ll_y + delta
return result_ll_x, result_ll_y, result_ur_x, result_ur_y
def btn_clicked():
""" Prints to console a message every time the button is clicked """
print("Button Clicked")
background_image_path = 'background_image.jpg'
button_image_path = 'button_image.png'
root = tk.Tk()
root.update_idletasks()
background_img = Image.open(background_image_path) # Must use PIL for JPG images.
scrnwidth, scrnheight = root.winfo_screenwidth(), root.winfo_screenheight()
bgrdwidth, bgrdheight = background_img.size
border_width, border_height = 20, 20 # Allow room for window's decorations.
# Determine a background image size that will fit on screen with a border.
bgr_ll_x, bgr_ll_y, bgr_ur_x, bgr_ur_y = fitrect(
0, 0, bgrdwidth, bgrdheight,
0, 0, scrnwidth-border_width, scrnheight-border_height)
bgr_width, bgr_height = int(bgr_ur_x-bgr_ll_x), int(bgr_ur_y-bgr_ll_y)
# Resize background image to calculated size.
background_img = ImageTk.PhotoImage(background_img.resize((bgr_width, bgr_height)))
# Create Canvas same size as fitted background image.
canvas = tk.Canvas(root, bd=0, highlightthickness=0, width=bgr_width, height=bgr_height)
canvas.pack(fill=tk.BOTH)
# Put background image on Canvas.
background = canvas.create_image(0, 0, anchor='nw', image=background_img)
# Put CanvasButton on Canvas centered at the bottom.
button_img = tk.PhotoImage(file=button_image_path)
btn_x, btn_y = (bgr_width/2), (bgr_height-button_img.height())
canvas_btn1 = CanvasButton(canvas, btn_x, btn_y, button_img, btn_clicked)
root.mainloop()
And here's the result of running it:

Draggable Tkinter Label With Transparent Image Still Covers Image from Parent Canvas

I am working on adding drag-able labels on top of a background image, where the labels are images with a transparent background. The images used for the label themselves are transparent, but the Label itself is not transparent in relation to its parent canvas. Since the labels are drag-able, I can't easily use the parent image for label, and paste the transparent image on top.
The dragon is a drag-able label, with a transparent background, but you see that the label itself is not transparent, and covers the canvas image.
The dragon image itself has a transparent background, as the normal background is blue, so I know the issue is with the label transparency.
The desired behavior would be to allow the label to be transparent, so when the image on the label is transparent, the label should show through to the image below.
Here is a minimal example:
from PIL import Image, ImageTk
import numpy as np
import tkinter as tk
#Creates a blue square with a transparent border
blue_square_transparent_border = [[[0,0,0,0]]*100]*10 + [[[0,0,0,0]]*30 + [[0,0,255,255]]*40 + [[0,0,0,0]]*30]*40 + [[[0,0,0,0]]*100]*10
blue_square_transparent_border = np.array(blue_square_transparent_border, dtype='uint8')
#convert numpy array to PIL image
pil_image = Image.fromarray(blue_square_transparent_border)
root = tk.Tk()
root.configure(background='red')
#convert PIL image to tkinter image
tk_image = ImageTk.PhotoImage(pil_image)
#create label
image_label = tk.Label(root, image=tk_image)
image_label.pack()
root.mainloop()
What I would like to see is a blue square, on a red background, with no border. In the above example though, the border of grey appears, as it is the label being seen through the transparent image; it is easy to see this when you resize the window. I suspect if the label were transparent, this would solve my issues.
Any help would be great, Thanks!
If you want to drag partially transparent images (like the dragon) over a background image, you can do it with a Canvas:
The idea is not to use labels, but the create_image method of the Canvas.
First, display your background image with canvas.create_image(0, 0, image=background_image, anchor='nw'), then display all the draggable images with the tag 'draggable': canvas.create_image(x, y, image=draggable_image, anchor='nw', tag='draggable'). Finally, bind the tag 'draggable' to mouse events.
Here is an example:
import tkinter as tk
import numpy as np
from PIL import Image, ImageTk
# drag callbacks
dragged_item = None
current_coords = 0, 0
def start_drag(event):
global current_coords
global dragged_item
result = canvas.find_withtag('current')
if result:
dragged_item = result[0]
current_coords = canvas.canvasx(event.x), canvas.canvasy(event.y)
else:
dragged_item = None
def stop_drag(event):
dragged_item = None
def drag(event):
global current_coords
xc, yc = canvas.canvasx(event.x), canvas.canvasy(event.y)
dx, dy = xc - current_coords[0], yc - current_coords[1]
current_coords = xc, yc
canvas.move(dragged_item, dx, dy)
#Create pictures
blue_square_transparent_border = [[[0,0,0,0]]*100]*10 + [[[0,0,0,0]]*30 + [[0,0,255,255]]*40 + [[0,0,0,0]]*30]*40 + [[[0,0,0,0]]*100]*10
blue_square_transparent_border = np.array(blue_square_transparent_border, dtype='uint8')
pil_image = Image.fromarray(blue_square_transparent_border)
background_data = np.zeros((200, 400, 4))
background_data[:, :, 0] = 255 * np.ones((200, 400))
background_data[:, :, 3] = 255 * np.ones((200, 400))
background_data = np.array(background_data, dtype='uint8')
pil_image_bg = Image.fromarray(background_data)
# create GUI
root = tk.Tk()
background_image = ImageTk.PhotoImage(pil_image_bg)
tk_image = ImageTk.PhotoImage(pil_image)
canvas = tk.Canvas(root, width=400, height=200)
canvas.pack()
# bind 'draggable' tag to mouse events
canvas.tag_bind('draggable', '<ButtonPress-1>', start_drag)
canvas.tag_bind('draggable', '<ButtonRelease-1>', stop_drag)
canvas.tag_bind('draggable', '<B1-Motion>', drag)
# display pictures
canvas.create_image(0, 0, image=background_image, anchor='nw')
canvas.create_image(0, 0, image=tk_image, anchor='nw', tag='draggable')
root.mainloop()

Tkinter bind widgets below a rectangle widget to a mouse event

I hope I am explaining the problem correctly.
My example below is able to move two images defined on a canvas. The problem is that I want a rectangle, also defined on the canvas, on top of the images. When I do that using .tag_raise, the event triggered by mouse drag is triggered by the rectangle, not the images.
I tried using bing_class but that did not work. I tried to define a separate canvas for the rectangle but it has to overlay the main canvas and I got stuck.
How to keep the rectangle on top but bind the images to my mouse drag event?
import Tkinter as tk # for Python2
import PIL.Image, PIL.ImageTk
win = tk.Tk()
canvas = tk.Canvas(win, height = 500, width = 500)
#Create a rectangle with stipples on top of the images
rectangle = canvas.create_rectangle(0, 0, 400, 300, fill = "gray", stipple = "gray12")
#Create two images
SPRITE = PIL.Image.open("image.jpg")
imagePIL = SPRITE.resize((100, 100))
imagePI = PIL.ImageTk.PhotoImage(imagePIL)
image1 = canvas.create_image(100, 100, image = imagePI, tags = "image")
image2 = canvas.create_image(200, 200, image = imagePI, tags = "image")
#Callback
# Here I select image1 or image2 depending on where I click, and
# drag them on the canvas. The problem is when I put the rectangle
# on top using tag_raise (see below).
def callback(event):
id = canvas.find_withtag(tk.CURRENT)
canvas.coords(id, (event.x, event.y))
#Binding
canvas.bind("<B1-Motion>", callback)
#Place the rectangle on top of all
canvas.pack()
# This is the problem. I want to have the rectangle on top and be able to use the callback
#canvas.tag_raise(rectangle)
canvas.mainloop()
SOLUTION: I enhanced Nehal's answer with the following code. His answer had a glitch, by which images could be switched. In my enhancement I solve it by storing a lock for each image so that, while dragging an image around on the canvas, the same image is dragged. When I move e.g. image1 over image2 I notice that image1 does not completely move over image2, which is fine for me.
import Tkinter as tk # for Python2
import PIL.Image, PIL.ImageTk
win = tk.Tk()
canvas = tk.Canvas(win, height = 500, width = 500)
#Create a rectangle with stipples on top of the images
rectangle = canvas.create_rectangle(0, 0, 400, 300, fill = "gray", stipple = "gray12")
#Create two images
SPRITE = PIL.Image.open("image.jpg")
imagePIL = SPRITE.resize((100, 100))
imagePI = PIL.ImageTk.PhotoImage(imagePIL)
image1 = canvas.create_image(100, 100, image = imagePI, tags = "image")
image2 = canvas.create_image(200, 200, image = imagePI, tags = "image")
images = [image1, image2]
locks = [True, True]
def getImage(x, y):
for image in images:
curr_x, curr_y = canvas.coords(image)
x1 = curr_x - imagePI.width()/2
x2 = curr_x + imagePI.width()/2
y1 = curr_y - imagePI.height()/2
y2 = curr_y + imagePI.height()/2
if (x1 <= x <= x2) and (y1 <= y <= y2):
return image
#Callback
# Here I select image1 or image2 depending on where I click, and
# drag them on the canvas.
def callback(event):
id = getImage(event.x, event.y)
if id:
if locks[images.index(id)] is False: #Hold on to the image on which I originally clicked
canvas.coords(id, (event.x, event.y))
def mouseClick(event):
id = getImage(event.x, event.y)
if id:
locks[images.index(id)] = False
print(locks)
def mouseRelease(event):
id = getImage(event.x, event.y)
if id:
locks[images.index(id)] = True
print(locks)
#Binding
canvas.bind("<ButtonPress-1>", mouseClick) #unlock the image to move it
canvas.bind("<ButtonRelease-1>", mouseRelease) #lock the image
canvas.bind("<B1-Motion>", callback)
#Place the rectangle on top of all
canvas.pack()
# This was the original problem
canvas.tag_raise(rectangle)
canvas.mainloop()
I don't know a tkinter specific way to do this, however, you can try to get the coordinates of the closest image and play with them. Like this:
import Tkinter as tk # for Python2
import PIL.Image, PIL.ImageTk
win = tk.Tk()
canvas = tk.Canvas(win, height = 500, width = 500)
#Create a rectangle with stipples on top of the images
rectangle = canvas.create_rectangle(0, 0, 400, 300, fill = "gray", stipple = "gray12")
#Create two images
SPRITE = PIL.Image.open("image.jpg")
imagePIL = SPRITE.resize((100, 100))
imagePI = PIL.ImageTk.PhotoImage(imagePIL)
image1 = canvas.create_image(100, 100, image = imagePI, tags = "image")
image2 = canvas.create_image(200, 200, image = imagePI, tags = "image")
images = [image1, image2]
def getImage(x, y):
for image in images:
curr_x, curr_y = canvas.coords(image)
x1 = curr_x - imagePI.width()/2
x2 = curr_x + imagePI.width()/2
y1 = curr_y - imagePI.height()/2
y2 = curr_y + imagePI.height()/2
if (x1 <= x <= x2) and (y1 <= y <= y2):
return image
#Callback
# Here I select image1 or image2 depending on where I click, and
# drag them on the canvas. The problem is when I put the rectangle
# on top using tag_raise (see below).
def callback(event):
id = getImage(event.x, event.y)
if id:
canvas.coords(id, (event.x, event.y))
#Binding
canvas.bind("<B1-Motion>", callback)
#Place the rectangle on top of all
canvas.pack()
# This is the problem. I want to have the rectangle on top and be able to use the callback
canvas.tag_raise(rectangle)
canvas.mainloop()

Categories