can you insert a canvas inside a frame in tkinter? [duplicate] - python

This question already has answers here:
Why does Tkinter image not show up if created in a function?
(5 answers)
Closed 6 months ago.
I'm trying to display a frame with a canvas inside in order I'll be able to change of frame with a button, but when the code is executed it does not even display the button, I don't know if it happens because of all is on a function, if doing what I think is even possible or if I'm missing something
from tkinter import *
window = Tk()
window.geometry("1200x700")
window.configure(bg = "#ffffff")
def btn_clicked():
print("Button Clicked")
frame1 =Frame(window, width=1200, height=700)
frame1.grid(row=0, column=0)
def load_page():
frame1.tkraise()
frame1.pack_propagate(False)
canvas = Canvas(
frame1,
bg = "#263ff8",
height = 700,
width = 1200,
bd = 0,
highlightthickness = 0,
relief = "ridge")
canvas.place(x = 0, y = 0)
background_img = PhotoImage(file = f"background.png")
background = canvas.create_image(
601.0, 341.0,
image=background_img)
img0 = PhotoImage(file = f"img0.png")
boton = Button(
image = img0,
borderwidth = 0,
highlightthickness = 0,
command = btn_clicked,
relief = "flat")
boton.place(
x = 85, y = 71,
width = 430,
height = 99)
load_page()
window.resizable(False, False)
window.mainloop()

Rephrased the entire code and including image:
To see button display. I had to reduced height and width in Canvas. Also The button had to reduced. In line 21, I changed bd = 10. You can comment in , because I don't used PhotoImage. you can debug see in image.
from tkinter import *
window = Tk()
window.geometry("1200x700")
window.configure(bg = "#ffffff")
def btn_clicked():
print("Button Clicked")
frame1 =Frame(window, width=1200, height=700)
frame1.grid(row=0, column=0)
def load_page():
frame1.tkraise()
frame1.pack_propagate(False)
canvas = Canvas(
frame1,
bg = "#263ff8",
height = 100,
width = 200,
bd = 10,
highlightthickness = 0,
relief = "ridge")
canvas.place(x = 0, y = 0)
#background_img = PhotoImage(file = f"background.png")
#background = canvas.create_image(
#601.0, 341.0,
#image=background_img)
#img0 = PhotoImage(file = f"img0.png")
boton = Button(frame1,
#image = img0,
borderwidth = 0,
highlightthickness = 0,
command = btn_clicked,
relief = "flat")
boton.place(
x = 85, y = 71,
width = 30,
height =29)
load_page()
window.resizable(False, False)
window.mainloop()
Output result. you can see debug.

Related

tkinter Enter and Leave Bindings

So the problem I am facing is with the "Enter" and "Leave" bind things. It works for hovering which is great but it also fire when the button is clicked which messes up my system which I have.
My system is that when being hovered over the images move up to show they are being highlighted and then when you click them they are selected.
The trouble is that when you click them it fires the "Enter" bind which causes the whole system to mess up. This is not ideal and is even more strange since I have already set the buttons "command".
Scouting for some solutions to this troubling issue thanks!
from tkinter import *
Activated = None
def command(self):
global Activated
if not Activated:
Activated = self
else:
Activated = None
Leave(self)
return
def Enter(self, *args):
global Activated
if not Activated:
width = self.winfo_width()
x = self.winfo_x()
y = self.winfo_y() - 1 / 2 * width
self.place(x = x, y = y)
return
def Leave(self, *args):
global Activated
if not Activated:
width = self.winfo_width()
x = self.winfo_x()
y = self.winfo_y() + 1 / 2 * width
self.place(x = x, y = y)
return
window = Tk()
window.geometry("1024x768")
window.configure(bg = "#1e1e1e")
canvas = Canvas(
window,
bg = "#1e1e1e",
height = 768,
width = 1024,
bd = 0,
highlightthickness = 0,
relief = "ridge")
canvas.place(x = 0, y = 0)
Rockimg = PhotoImage(file = f"Rock.png")
Rock = Button(
command = lambda: command(Rock),
bg = "#1e1e1e",
image = Rockimg,
borderwidth = 0,
highlightthickness = 0,
activebackground = "#1e1e1e",
relief = "flat")
Rock.bind("<Enter>", lambda event: Enter(Rock))
Rock.bind("<Leave>", lambda event: Leave(Rock))
Rock.place(
x = 46, y = 441,
width = 286,
height = 490.5)
Paperimg = PhotoImage(file = f"Paper.png")
Paper = Button(
command = lambda: command(Paper),
bg = "#1e1e1e",
image = Paperimg,
borderwidth = 0,
highlightthickness = 0,
activebackground = "#1e1e1e",
relief = "flat")
Paper.bind("<Enter>", lambda event: Enter(Paper))
Paper.bind("<Leave>", lambda event: Leave(Paper))
Paper.place(
x = 363, y = 316,
width = 297,
height = 678)
Scissorsimg = PhotoImage(file = f"Scissors.png")
Scissors = Button(
command = lambda: command(Scissors),
bg = "#1e1e1e",
image = Scissorsimg,
borderwidth = 0,
highlightthickness = 0,
activebackground = "#1e1e1e",
relief = "flat")
Scissors.bind("<Enter>", lambda event: Enter(Scissors))
Scissors.bind("<Leave>", lambda event: Leave(Scissors))
Scissors.place(
x = 721, y = 300,
width = 256,
height = 702)
window.resizable(False, False)
window.mainloop()
If I reproduced your problem correctly, I guess it should be something like this:
You hover over a random image and it goes up when your mouse is on it and goes down when you leave it
When you click the image and leave the image doesn't go down which messes up things later
You might be thinking its the problem with the <Enter> binding here because you think clicking it executed it again and when you left the button it stays up but that's not the problem. The problem is that the Activated variable is changed to self in the command function. So if you go to the Leave function you'll see that moving widget stuff is under an if statement. So now that the Activated variable is something that "stuff" does NOT get executed. So the step here is to remove those if statements. However there's another problem and I don't know why you did it, but you have called the Leave function under else in the command function. This will obviously make the widget go down twice. This code below works:
from tkinter import *
from PIL import Image, ImageTk
Activated = None
def command(self):
global Activated
if not Activated:
Activated = self
else:
Activated = None
return
def Enter(self, *args):
global Activated
width = self.winfo_width()
x = self.winfo_x()
y = self.winfo_y() - 1 / 2 * width
self.place(x = x, y = y)
return
def Leave(self, *args):
global Activated
width = self.winfo_width()
x = self.winfo_x()
y = self.winfo_y() + 1 / 2 * width
self.place(x = x, y = y)
return
window = Tk()
window.geometry("1024x768")
window.configure(bg = "#1e1e1e")
canvas = Canvas(
window,
bg = "#1e1e1e",
height = 768,
width = 1024,
bd = 0,
highlightthickness = 0,
relief = "ridge")
canvas.place(x = 0, y = 0)
Rockimg = Image.open(f"Rock.png")
Rockimg = Rockimg.resize((200, 200))
Rock = Button(
command = lambda: command(Rock),
bg = "#1e1e1e",
image = ImageTk.PhotoImage(Rockimg),
borderwidth = 0,
highlightthickness = 0,
activebackground = "#1e1e1e",
relief = "flat")
Rock.bind("<Enter>", lambda event: Enter(Rock))
Rock.bind("<Leave>", lambda event: Leave(Rock))
Rock.place(
x = 46, y = 441,
width = 286,
height = 490.5)
Paperimg = PhotoImage(file = f"Paper.png")
Paper = Button(
command = lambda: command(Paper),
bg = "#1e1e1e",
image = Paperimg,
borderwidth = 0,
highlightthickness = 0,
activebackground = "#1e1e1e",
relief = "flat")
Paper.bind("<Enter>", lambda event: Enter(Paper))
Paper.bind("<Leave>", lambda event: Leave(Paper))
Paper.place(
x = 363, y = 316,
width = 297,
height = 678)
Scissorsimg = PhotoImage(file = f"Scissors.png")
Scissors = Button(
command = lambda: command(Scissors),
bg = "#1e1e1e",
image = Scissorsimg,
borderwidth = 0,
highlightthickness = 0,
activebackground = "#1e1e1e",
relief = "flat")
Scissors.bind("<Enter>", lambda event: Enter(Scissors))
Scissors.bind("<Leave>", lambda event: Leave(Scissors))
Scissors.place(
x = 721, y = 300,
width = 256,
height = 702)
#window.resizable(False, False)
window.mainloop()

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

How to make a button appear after a button click in tkinter?

I have this issue here that i want a button (b1 in code) to appear after the user click in the main button (b0).
from tkinter import *
from tkinter import filedialog
import tkinter.messagebox
import os
def openword():
my_program = filedialog.askopenfilename()
os.system('"%s"' % my_program)
def btn_clicked():
tkinter.messagebox.showinfo("Login","Login Success, Welcome!")
window = Tk()
window.geometry("1000x600")
window.configure(bg = "#293335")
canvas = Canvas(
window,
bg = "#293335",
height = 600,
width = 1000,
bd = 0,
highlightthickness = 0,
relief = "ridge")
canvas.place(x = 0, y = 0)
background_img = PhotoImage(file = f"background.png")
background = canvas.create_image(
508.5, 228.0,
image=background_img)
entry0_img = PhotoImage(file = f"img_textBox0.png")
entry0_bg = canvas.create_image(
166.0, 367.0,
image = entry0_img)
entry0 = Entry(
bd = 0,
bg = "#ffffff",
highlightthickness = 0)
entry0.place(
x = 22, y = 351,
width = 288,
height = 30)
entry1_img = PhotoImage(file = f"img_textBox1.png")
entry1_bg = canvas.create_image(
166.0, 456.0,
image = entry1_img)
entry1 = Entry(
bd = 0,
bg = "#ffffff",
highlightthickness = 0)
entry1.place(
x = 22, y = 440,
width = 288,
height = 30)
img0 = PhotoImage(file = f"img0.png")
b0 = Button(
image = img0,
borderwidth = 0,
highlightthickness = 0,
command = btn_clicked,
relief = "flat")
b0.place(
x = 28, y = 500,
width = 102,
height = 38)
img1 = PhotoImage(file = f"img1.png")
b1 = Button(
image = img1,
borderwidth = 0,
highlightthickness = 0,
command = openword,
relief = "flat")
b1.place(
x = 766, y = 505,
width = 213,
height = 72)
window.resizable(False, False)
window.mainloop()
The code works perfectly but the two buttons appear at the same time.
I need b1 to appear after the user presss b0.
Like acw1668 is suggesting, place your button inside your function that is called on clicking the other button. Here is an example:
import tkinter as tk
import tkinter.messagebox
def btn_clicked():
tkinter.messagebox.showinfo("Login","Login Success, Welcome!")
b2 = tk.Button(
borderwidth = 0,
highlightthickness = 0,
command = btn_clicked,
relief = "flat"
)
b2.place(
x = 200, y = 200,
width = 213,
height = 72
)
window = tk.Tk()
window.geometry("1000x600")
window.configure(bg = "#293335")
b1 = tk.Button(
borderwidth = 0,
highlightthickness = 0,
command = btn_clicked,
relief = "flat"
)
b1.place(
x = 5, y = 5,
width = 213,
height = 72
)
window.resizable(False, False)
window.mainloop()
You would want to place your button under the btn_clicked(): function. If you create a button under that function, I'm pretty sure that it creates a new button each time you click.

create a scrollbar on entry with cavnas, python tkinter

I'm trying to put a scrollbar on entry that created on canvas..
I've tried this code
from tkinter import *
root = Tk()
root.geometry('400x600')
root.resizable(0,0)
page = Canvas(root, width=400, height=600, bd=0, highlightthickness=0,scrollregion=(0,0,500,500))
MyImage1 = PhotoImage(file='Study With4.png')
CanvasImage = page.create_image(0,0,image= MyImage1, anchor='nw')
entry =Text(page,height=29,width =46,wrap=WORD,bg='#F8F8F8')
scroll = Scrollbar(entry, orient=VERTICAL)
scroll.pack(side=RIGHT, fill=Y)
scroll.config(command=page.yview)
page.config(yscrollcommand=scroll.set)
page.create_window(200,285, window=entry)
page.pack()
mainloop()
but it doesn't work and I don't know where is the problem.
I've made minimal changes to your code, the biggest is creating a Frame called "label"
to contain Text and Scrollbar then inserting that into Canvas window.
Your scroll object was not defined properly with confusion around page and entry objects.
from tkinter import *
root = Tk()
root.geometry('500x600')
root.resizable(0,0)
page = Canvas(
root, width = 500, height = 600, bd = 0,
highlightthickness = 0,scrollregion = (0,0,1000,1000))
page.pack(side = LEFT, fill = BOTH, expand = True)
MyImage1 = PhotoImage(file='Study With4.png')
CanvasImage = page.create_image(0, 0, image = MyImage1, anchor = NW)
label = Frame(root)
label.pack(fill = BOTH, expand = True)
entry = Text(label, height = 29, width = 46, wrap = NONE, bg = '#F8F8F8')
entry.pack(side = LEFT, fill = BOTH, expand = True)
scroll = Scrollbar(label, orient = VERTICAL)
scroll.pack(side=RIGHT, fill=Y)
scroll.config(command = entry.yview)
entry.config(yscrollcommand = scroll.set)
page.pack()
page.create_window(25, 25, window = label, anchor = NW)
mainloop()

Bind/event gives error 'int' object has no attribute 'bind'

I'm trying to understand how bind and events work in python. For example I've created 3 tiles and would like to be able to change the color of one of the tiles but cannot understand or figure out where I'm going wrong. I keep getting:
AttributeError: 'int' object has no attribute 'bind'.
Below is the code and thanks in advance:
import tkinter
def main():
root = tkinter.Tk()
title = tkinter.Label(root, text="Test Window")
title.pack()
canvas= tkinter.Canvas(root, background='green', width = 300, height = 300)
tile1=canvas.create_rectangle(0, 0, 100, 100, fill = 'magenta')
tile2=canvas.create_rectangle(100,0, 200,100, fill = 'blue')
tile3=canvas.create_rectangle(200,0, 300,100, fill = 'blue')
canvas.pack()
def change_square(event):
event.configure(background = 'blue')
tile1.bind("<Button-1>", change_square(tile1))
root.mainloop()
if __name__ == '__main__':
main()
itemconfigure will change the colour:
def main():
root = tkinter.Tk()
title = tkinter.Label(root, text="Test Window")
title.pack()
canvas = tkinter.Canvas(root, background='green', width=300, height=300)
s1 = canvas.create_rectangle(0, 0, 100, 100, fill='magenta')
s2 = canvas.create_rectangle(100, 0, 200, 100, fill='blue')
s3 = canvas.create_rectangle(200, 0, 300, 100, fill='blue')
canvas.pack()
def change_square(event):
canvas.itemconfigure(s1, fill="blue")
canvas.bind("<Button-1>", change_square)
root.mainloop()
If you want to change the middle to black you would use:
canvas.itemconfigure(s2, fill="black")`
And so on.
If you want to change colour based on which you click this should work:
def change_square(event):
x = canvas.canvasx(event.x)
y = canvas.canvasy(event.y)
sq = canvas.find_closest(x,y)[0]
canvas.itemconfigure(sq, fill="black")
canvas.bind("<Button-1>", change_square)
root.mainloop()

Categories