Borderwidth attribute in Tkinter not working - python

I am trying to use borderwidth attribute to highlight only the "New Game" part of the png image, however, it isn't working, how do I solve this error?
from tkinter import *
from PIL import ImageTk, Image
root = Tk()
root.iconbitmap('unnamed.ico')
root.title('2048')
bg = ImageTk.PhotoImage(Image.open("welcome.png"))
new_game_btn = ImageTk.PhotoImage(Image.open("image_40.png"))
my_canvas = Canvas(root, width=780, height=550)
my_canvas.pack()
my_canvas.create_image(0, 0, image=bg, anchor=NW)
button1 = Button(root, image=new_game_btn, borderwidth=00, relief=FLAT)
button1_window = my_canvas.create_window(100, 100, anchor=NW, window=button1)
root.mainloop()

Your only option seems to be to draw the image to the canvas instead of creating a button (because widgets in Tkinter do not support transparency).
The drawback is, that you will have to check the mouse coordinates on the Canvas in order to see if your "Button" has been clicked.
The code would look like this:
from PIL import ImageTk, Image
root = Tk()
root.iconbitmap('unnamed.ico')
root.title('2048')
bg = ImageTk.PhotoImage(Image.open("welcome.png"))
new_game_btn = ImageTk.PhotoImage(Image.open("image_40.png"))
my_canvas = Canvas(root, width=780, height=550)
my_canvas.pack()
my_canvas.create_image(0, 0, image=bg, anchor=NW)
my_canvas.create_image(100, 100, image=new_game_btn, anchor=NW)
root.mainloop()
This results in that (don't mind the typo...):
If you want to check if that part of the canvas was clicked, I would just check for the bounding box like this:
from tkinter import *
from PIL import ImageTk, Image
x_pos = 100
y_pos = 100
width = 100
height = 100
def callback(event):
print("Canvas clicked at", event.x, event.y)
if (event.x > x_pos and event.x < x_pos + width):
if(event.y > y_pos and event.y < y_pos + height):
print("The button was clicked (approximately).")
root = Tk()
root.iconbitmap('unnamed.ico')
root.title('2048')
bg = ImageTk.PhotoImage(Image.open("welcome.png"))
new_game_btn = ImageTk.PhotoImage(Image.open("image_40.png"))
my_canvas = Canvas(root, width=780, height=550)
my_canvas.pack()
my_canvas.create_image(0, 0, image=bg, anchor=NW)
my_canvas.create_image(100, 100, image=new_game_btn, anchor=NW)
my_canvas.bind("<Button-1>", callback)
root.mainloop()

Related

Can't properly set an image as canvas background in tkinter

I want my Tkinter window to have four buttons, each with its own background image, disposed as a 2x2 grid. I tried using frames but you can't set an image as frame background so I had to switch to Canvas. This is the code for one of the four blocks.
from tkinter import *
from PIL import ImageTk, Image
root = Tk()
root.geometry("500x200")
root.wm_title("KnowYourArt")
styles_bg = ImageTk.PhotoImage(Image.open("images/styles_bg.png"))
canvas_styles = Canvas(root)
bg = canvas_styles.create_image(100, 100, image=styles_bg)
width = 4
height = 2
Button(canvas_styles, text="Styles", width=width, height=height).pack(side=TOP)
Label(canvas_styles, text="Gain info about styles").pack(side=BOTTOM)
canvas_styles.grid(row=0, column=0)
This is the output I get:
In my intentions, the background image dimensions should cover both the button and the label, and the image's dimensions should be independent from the dimensions of the widgets. Instead, I obtain a canvas where the height of the BG image is the same as the height of the button, and the width is the same as the label's width. I tried many alternative possibilities, including setting a width and height for the canvas, and none of them properly worked. What am I doing wrong?
I managed to find a solution. Here is the code:
from tkinter import *
from PIL import ImageTk, Image
width = 4
height = 1
def add_canvas(frame, img, x, y, text):
c = Canvas(frame, width=300, height=300)
c.focus()
c.pack(fill=BOTH, expand=True)
bg = c.create_image(x, y, image=img)
btn = Button(frame, text="Go!", width=width, height=height)
c.create_text(150, 190, text=text, font=('Helvetica', 15), fill='white')
c.create_window(100, 200, anchor="nw", window=btn)
return c
root = Tk()
root.geometry("600x600")
root.wm_title("Title")
f_1 = Frame(root)
f_2 = Frame(root)
f_3 = Frame(root)
f_4 = Frame(root)
bg1 = ImageTk.PhotoImage(Image.open("images/im1.png"))
bg2 = ImageTk.PhotoImage(Image.open("images/im2.png"))
bg3 = ImageTk.PhotoImage(Image.open("images/im3.png"))
bg4 = ImageTk.PhotoImage(Image.open("images/im4.jpg"))
canvas_1 = add_canvas(f_1, bg1, 0, 0, "foo")
canvas_2 = add_canvas(f_2, bg2, 240, 240, "foo")
canvas_3 = add_canvas(f_3, bg3, 120, 120, "foo")
canvas_4 = add_canvas(f_4, bg4, 100, 100, "foo")
f_1.grid(row=0, column=0)
f_2.grid(row=0, column=1)
f_3.grid(row=1, column=0)
f_4.grid(row=1, column=1)
And here's the output

Is there any way to make tkinter Radiobutton transparent on tkinter canvas?

I want to make radiobutton transparent on canvas image to make it look good, I tried passing lots of option parameters to radiobutton to somehow make it look better but nothing works.
Here is the code I am working with...
from tkinter import *
from tkinter import ttk
from tkinter.ttk import *
from PIL import ImageTk, Image
from tkinter import messagebox
class GUI_Prog:
def __init__(self):
root = Tk()
root.title("Risk Analysis")
root.geometry("1100x630")
r = IntVar()
#Setting up Canvas :
my_canvas = Canvas(root, width=1100, height=630)
my_canvas.pack(fill="both", expand=True)
#Background :
img = Image.open("diagnosis.png")
img = img.resize((1100,630), Image.ANTIALIAS)
bg = ImageTk.PhotoImage(img)
my_canvas.create_image(0,0,image=bg,anchor="nw")
#Creating title text :
my_canvas.create_text(540,40,text="Risk Analysis", font=("Times, 30"), fill = "white")
my_canvas.create_text(140,100,text="1) Do you smoke?", font=("helvetica, 15"), fill = "black")
but_1 = Radiobutton(root, text="yes", variable=r, value=1)
my_canvas.create_window(60, 150, window=but_1)
but_2= Radiobutton(root, text="no", variable=r, value=2)
my_canvas.create_window(150, 150, window=but_2)
mainloop()
obj = GUI_Prog()
Well I created my own RadioButton class but it only works on tkinter.Canvas:
from tkinter import *
from tkinter import ttk
from tkinter.ttk import *
from PIL import ImageTk, Image
from tkinter import messagebox
# Taken from: https://stackoverflow.com/a/17985217/11106801
def _create_circle(self, x, y, r, **kwargs):
return self.create_oval(x-r, y-r, x+r, y+r, **kwargs)
Canvas.create_circle = _create_circle
class Radiobutton:
def __init__(self, canvas, text="", variable=None, value=0, radius=10,
fill="black"):
self.canvas = canvas
self.variable = variable
self.fill = fill
self.text = text
self.value = value
self.radius = radius
self.variable.trace("w", self.redraw)
self.circle = None
def put(self, x, y):
self.x = x
self.y = y
self.canvas.create_circle(x, y, self.radius, outline=self.fill)
self.canvas.create_text(x + 2*self.radius, y, text=self.text,
fill=self.fill, anchor="w")
self.redraw()
self.canvas.bind("<Button-1>", self.select, add=True)
def select(self, event):
if (self.x - event.x)**2 + (self.y - event.y)**2 <= self.radius**2:
self.variable.set(self.value)
self.redraw()
def create_circle(self):
self.circle = self.canvas.create_circle(self.x, self.y, self.radius-4,
outline=self.fill,
fill=self.fill)
def redraw(self, *args):
if self.value == self.variable.get():
if self.circle is None:
self.create_circle()
else:
if self.circle is not None:
self.canvas.delete(self.circle)
self.circle = None
class GUI_Prog:
def __init__(self):
root = Tk()
root.title("Risk Analysis")
root.geometry("1100x630")
r = IntVar()
#Setting up Canvas:
my_canvas = Canvas(root, width=1100, height=630)
my_canvas.pack(fill="both", expand=True)
#Background:
img = Image.open("diagnosis.png")
img = img.resize((1100, 630), Image.ANTIALIAS)
bg = ImageTk.PhotoImage(img)
my_canvas.create_image(0, 0, image=bg, anchor="nw")
#Creating title text:
my_canvas.create_text(540, 40, text="Risk Analysis",
font=("Times", 30), fill="white")
my_canvas.create_text(140, 100, text="1) Do you smoke?",
font=("helvetica", 15), fill="black")
but_1 = Radiobutton(my_canvas, text="yes", variable=r, value=1,
fill="white")
but_1.put(60, 150)
but_2 = Radiobutton(my_canvas, text="no", variable=r, value=2,
fill="white")
but_2.put(150, 150)
r.set(1)
root.mainloop()
obj = GUI_Prog()
You create it as normal but you pass in the <tkinter.Canvas> as its master. After that you can just call .put with the position where you want it to be created. This is a very patchy solution so if someone else posts a better solution, I will delete this.

How to to resize canvas objects to window size in tkinter without using object oriented programming?

This is my code so far and I want to resize all of these widgets including the image to window size.
from tkinter import *
win = Tk()
win.title("xxx")
win.geometry("600x600")
win.resizable()
w = 700
h = 700
x = 600 // 2
y = 600 // 2
canvas = Canvas(win, width=w, height=h, bg="grey")
canvas.grid(row=0, column=0, padx=50, pady=50)
img = PhotoImage(file="c.png")
canvas.create_rectangle(0, 0, 75, 500, fill="green")
canvas.create_rectangle(425, 0, 500, 500, fill="green")
canvas.create_rectangle(75, 0, 80, 500, fill="brown")
image = canvas.create_image(x, 440, image=img)
win.mainloop()
You can resize all the items in the canvas using the Canvas.coords(tagorId, x0, y0...). This can be used for any item in the canvas other than the image. For image use Image.resize((x, y), resample).
Bind the <Configure> event to an event handler. So whenever the canvas is resized the event handler is called.
Here is a demo.(Note the other items on the canvas might be hidden by the image). The below code will automatically resize items to the canvas.
from tkinter import *
from PIL import ImageTk, Image
def resize_widgets(event):
global resized
for items in canvas.find_all():
if items != image:
canvas.coords(items, 0, 0, event.width, event.height)
resized = ImageTk.PhotoImage(im.resize((event.width, event.height), resample = Image.NEAREST))
canvas.itemconfig(image, image=resized)
canvas.moveto(image, 0, 0)
win = Tk()
win.title("Dodge Car Challenger")
win.geometry("600x600")
win.resizable()
w = 700
h = 700
x = 600 // 2
y = 600 // 2
resized = None
canvas = Canvas(win, width=w, height=h, bg="grey")
#canvas.grid(row=0, column=0, padx=50, pady=50)
canvas.pack(expand=True, fill='both')
canvas.bind('<Configure>', resize_widgets)
im = Image.open(r"your imagepath")
img = ImageTk.PhotoImage(im)
canvas.create_rectangle(0, 0, 75, 500, fill="green")
item = canvas.create_rectangle(425, 0, 500, 500, fill="green")
canvas.create_rectangle(75, 0, 80, 500, fill="brown")
image = canvas.create_image(x, 440, image=img)
win.mainloop()

How to clear part of a tkinter Canvas and show something when submit is pressed?

I'm creating a simple madlib style game and I've come into a bit of a problem. I cannot get the canvas to clear and show the results.
The following code places an image as the background of a canvas. It then places labels and entry fields in 2 columns for all of the words to be inserted. There is a submit button at the bottom of the page. I can't figure out how to get it clear everything except the background image, so that it can display the story, with the users words inserted. If i place it in the callback(), it clears just the background and keeps everything else. I want the opposite.
from tkinter import *
from PIL import Image, ImageTk
canvas_width = 360
canvas_height = 525
file = r"C:\Users\kraak\Desktop\PyCharm Community Edition 2017.1.2\borderedpaper.GIF"
master = Tk()
canvas = Canvas(master, width=canvas_width, height=canvas_height)
old_img = PhotoImage(file=file)
new_img = old_img.subsample(3, 3)
canvas.create_image(-11, -10, anchor=NW, image=new_img)
canvas.create_window(0, 0, height=1, width=1, anchor=NW)
canvas.create_text(0, 0, text="Test")
e1 = Entry(canvas)
canvas.create_window(250, 60, window=e1, height=15, width=100)
label = Label(text="Enter an adjective.")
label.place(x=40, y=50)
e1.focus_set()
e2 = Entry(canvas)
canvas.create_window(250, 85, window=e2, height=15, width=100)
label = Label(text="Enter a nationality.")
label.place(x=40, y=75)
e2.focus_set()
def callback():
print("Pizza was invented by a " + (e1.get()) + " " + (e2.get()))
def answer():
button = Button(text="Submit.", command=callback)
button.place(x=150, y=460)
answer()
canvas.pack()
mainloop()
As Bryan Oakley suggested you can store the id's of the widgets you want to get rid of in a list to make it easier to destroy() them all in the callback() function. Here's showing the modification to your code that would do that—note the lines with a # ADDED comments.
from tkinter import *
from PIL import Image, ImageTk
canvas_width = 360
canvas_height = 525
file = r"C:\Users\kraak\Desktop\PyCharm Community Edition 2017.1.2\borderedpaper.GIF"
master = Tk()
canvas = Canvas(master, width=canvas_width, height=canvas_height)
canvas_entry_widgets = [] # ADDED
old_img = PhotoImage(file=file)
new_img = old_img.subsample(3, 3)
canvas.create_image(-11, -10, anchor=NW, image=new_img)
canvas.create_window(0, 0, height=1, width=1, anchor=NW)
canvas.create_text(0, 0, text="Test")
e1 = Entry(canvas)
canvas.create_window(250, 60, window=e1, height=15, width=100)
label = Label(text="Enter an adjective.")
label.place(x=40, y=50)
e1.focus_set()
canvas_entry_widgets.append(e1) # ADDED
e2 = Entry(canvas)
canvas.create_window(250, 85, window=e2, height=15, width=100)
label = Label(text="Enter a nationality.")
label.place(x=40, y=75)
e2.focus_set()
canvas_entry_widgets.append(e2) # ADDED
def callback():
print("Pizza was invented by a " + (e1.get()) + " " + (e2.get()))
# destroy the canvas entry widgets and clear the list # ADDED
while canvas_entry_widgets: # ADDED
widget = canvas_entry_widgets.pop() # ADDED
widget.destroy() # ADDED
def answer():
button = Button(text="Submit.", command=callback)
button.place(x=150, y=460)
answer()
canvas.pack()
mainloop()
Every widget has a destroy method which can be used to delete the widget. In your callback you can simply call this method for every widget:
def callback():
e1.destroy()
e2.destroy()
...
In your specific case, if you want to delete all the labels you will have to give them unique names. Or, to make this even easier, you can store all of your widgets and iterate over the list.

Support required with displaying a slideshow of Images in Python w/ TKinter

I am trying to make a set of code that will open a window and displaying 6 images in sequence over and over again very quickly for 10 seconds. This is my code, however the program simply open a blank screen. What do I do?
import time
import tkinter as tk
root = tk.Tk()
root.overrideredirect(True)
width = root.winfo_screenwidth()
height = root.winfo_screenwidth()
root.geometry('%dx%d' % (width*1, height*1))
def SS_Part1():
image_file_ssp1 = "goat1.gif"
image = tk.PhotoImage(file=image_file_ssp1)
canvas = tk.Canvas(root, height=height*1, width=width*1, bg="black")
canvas.create_image(width*1/2, height*1/2, image=image)
canvas.pack()
def SS_Part2():
image_file_ssp2 = "goat2.gif"
image = tk.PhotoImage(file=image_file_ssp2)
canvas = tk.Canvas(root, height=height*1, width=width*1, bg="black")
canvas.create_image(width*1/2, height*1/2, image=image)
canvas.pack()
def SS_Part3():
image_file_ssp3 = "goat3.gif"
image = tk.PhotoImage(file=image_file_ssp3)
canvas = tk.Canvas(root, height=height*1, width=width*1, bg="black")
canvas.create_image(width*1/2, height*1/2, image=image)
canvas.pack()
def SS_Part4():
image_file_ssp4 = "goat4.gif"
image = tk.PhotoImage(file=image_file_ssp4)
canvas = tk.Canvas(root, height=height*1, width=width*1, bg="black")
canvas.create_image(width*1/2, height*1/2, image=image)
canvas.pack()
def SS_Part5():
image_file_ssp5 = "goat5.gif"
image = tk.PhotoImage(file=image_file_ssp5)
canvas = tk.Canvas(root, height=height*1, width=width*1, bg="black")
canvas.create_image(width*1/2, height*1/2, image=image)
canvas.pack()
def SS_Part6():
image_file_ssp6 = "goat6.gif"
image = tk.PhotoImage(file=image_file_ssp6)
canvas = tk.Canvas(root, height=height*1, width=width*1, bg="black")
canvas.create_image(width*1/2, height*1/2, image=image)
canvas.pack()
t_end = time.time() + 10
while time.time() < t_end:
SS_Part1()
time.sleep(0.05)
SS_Part2()
time.sleep(0.05)
SS_Part3()
time.sleep(0.05)
SS_Part4()
time.sleep(0.05)
SS_Part5()
time.sleep(0.05)
SS_Part6()
root.mainloop()
These are some changes in your code, It should work properly.
import tkinter as tk
from itertools import cycle
# foreign library, need to installed
from ImageTk import PhotoImage
images = ["first1.jpg", "first2.jpg", "first3.jpg", "first4.jpg"]
photos = cycle(PhotoImage(file=image) for image in images)
def slideShow():
img = next(photos)
displayCanvas.config(image=img)
root.after(50, slideShow) # 0.05 seconds
root = tk.Tk()
root.overrideredirect(True)
width = root.winfo_screenwidth()
height = root.winfo_screenwidth()
root.geometry('%dx%d' % (640, 480))
displayCanvas = tk.Label(root)
displayCanvas.pack()
root.after(10, lambda: slideShow())
root.mainloop()
This is the Object-Oriented version of the above code, Recommended. Below code will work perfectly for the full screen slideshow
from itertools import cycle
import tkinter as tk
# foreign library, need to installed
from ImageTk import PhotoImage
images = [ "first1.jpg", "first2.jpg", "first3.jpg", "first4.jpg"]
class Imagewindow(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.photos = cycle(
PhotoImage(file=image) for image in images
)
self.displayCanvas = tk.Label(self)
self.displayCanvas.pack()
def slideShow(self):
img = next(self.photos)
self.displayCanvas.config(image=img)
self.after(50, self.slideShow) # 0.05 seconds
def run(self):
self.mainloop()
root = Imagewindow()
width = root.winfo_screenwidth()
height = root.winfo_screenwidth()
root.overrideredirect(True)
root.geometry('%dx%d' % (width*1, height*1))
root.slideShow()
root.run()

Categories