How to use “command” in canvas_image just like in Button ? Tkinter - python

I have a code that is working perfectly, but I want a clickable functionality in my image so that it will redirect to frame.
from tkinter import *
def onObjectClick1(event):
print("1")
canv.itemconfig(obj1, image=my_pic2)
canv.tag_bind(obj1, '<Leave>', onObjectClick2)
def onObjectClick2(event):
print("2")
canv.itemconfig(obj1, image=my_pic1)
canv.tag_bind(obj1, '<Enter>', onObjectClick1)
root = Tk()
canv = Canvas(root, width=300, height=300)
my_pic1 = PhotoImage(file="start000-before.png")
my_pic2 = PhotoImage(file="start000-after.png")
obj1 = canv.create_image(50,50,image=my_pic1, anchor=NW)
canv.tag_bind(obj1, '<Enter>', onObjectClick1)
canv.tag_bind(obj1, '<Leave>', onObjectClick2)
canv.pack()
root.mainloop()
Please help me out, I'm new in Tkinter.

At the moment you are binding to the Enter and Leave events. To bind to the click event you need to use Button-1
canv.tag_bind(obj1, '<Button-1>', onMouseButton1Click)
The canvas and canvas widgets don't support the command property as other tkinter widgets.
You can create a window inside a tkinter canvas which can contain normal tkinter widgets. In the below example, I create a window which contains a button. This can then use command in the normal way
from tkinter import *
def PressMeCmd():
print("You pressed me")
root = Tk()
canv = Canvas(root, width=300, height=300)
button = Button(canv,text="Press Me",command=PressMeCmd)
window = canv.create_window(0,0,window=button)
canv.pack()
root.mainloop()

You can use create_window() to put a Button inside a Canvas:
from tkinter import *
def on_click():
print('button clicked')
root = Tk()
canv = Canvas(root, width=300, height=300)
canv.pack()
my_pic1 = PhotoImage(file="start000-before.png")
my_pic2 = PhotoImage(file="start000-after.png")
btn = Button(canv, image=my_pic1, command=on_click)
btn.bind('<Enter>', lambda e: btn.config(image=my_pic2))
btn.bind('<Leave>', lambda e: btn.config(image=my_pic1))
canv.create_window(50, 50, window=btn, anchor=NW)
root.mainloop()

Related

How do you get a second canvas to appear on a tkinter Toplevel window when inside a class?

I'm using Tkinter to create an application, and with this Dashboard class, I'm trying to get a pop out window to show another canvas, so I can use create_image and tag_bind on the pop out. The result I'm currently getting is that the second canvas appears over the first canvas instead of in the pop out window.
import tkinter as tk
from tkinter import *
class Dashboard(tk.Tk):
"""
Configures, and displays the Dashboard
"""
def __init__(self):
tk.Tk.__init__(self)
self.config(width=1440, height=1024)
canvas = tk.Canvas(self, bg="#343333", height=1024, width=1440, bd=0, highlightthickness=0, relief="ridge")
canvas.place(x=0, y=0)
# Captures the background image for the canvas
image_path = "dashboard_background.png"
self.background_img = tk.PhotoImage(file=image_path)
canvas.create_image(0, 0, anchor='nw', image=self.background_img)
def logoutbuttonClicker():
pop = Toplevel(self)
pop.geometry('537x273')
pop.config(height=273, width=537)
logout_canvas = tk.Canvas(canvas, bg="#ffffff", height=273, width=537, bd=0, highlightthickness=0, relief="ridge")
logout_canvas.place(x=0, y=0)
self.logout_background_img = PhotoImage(file=f"logout_background.png")
logout_canvas.create_image(268.5, 136.5, anchor='nw', image=self.logout_background_img)
self.logout_yes_img = PhotoImage(file=f"logout_yes.png")
self.logout_no_img = PhotoImage(file=f"logout_no.png")
logout_image_path = "dashboard_logout.png"
self.logout_image = tk.PhotoImage(file=logout_image_path)
logoutButton = canvas.create_image(45, 950, anchor='nw', image=self.logout_image)
canvas.tag_bind(logoutButton, "<ButtonRelease-1>", lambda event: logoutbuttonClicker())
def main():
app = Dashboard()
app.mainloop()
if __name__ == '__main__':
main()
This is how it currently appears in the UI

How to call Turtle window from a GUI

I'm trying to open a Turtle window from a GUI to select a position on the image with a mouse click. The x and y coordinates are then returned as an input to the GUI.
Here is a minimal working example:
from tkinter import *
from tkinter import font as tkFont
import turtle
xclick = 0
yclick = 0
def callback3():
getcoordinates()
def getcoordinates():
screen = turtle.Screen()
screen.setup(400, 400)
screen.bgpic("stunden.gif")
screen.onscreenclick(modifyglobalvariables)
def modifyglobalvariables(rawx,rawy):
global xclick
global yclick
xclick = int(rawx//1)
yclick = int(rawy//1)
print(xclick)
print(yclick)
turtle.bye()
root = Tk()
helv30 = tkFont.Font(family='Helvetica', size=30)
button1 = Button(root, text = "1", width=3, font=helv30, borderwidth=0, command=callback3)
button1.grid(row=0, column=0, padx=5, pady=0)
root.mainloop()
Then the error image "pyimage2" doesn't exist shows up. I found out, that it has something to do with two instances of Tk, as there is the root and the turtle window and that I should solve it with Toplevel(). However, after hours of research and try and error I still could not come up with the right solution to make my code work. Any help is greatly appreciated.
Here's how to implement it directly in tkinter — so no turtle module required — as I suggested earlier in a (now-deleted) comment:
from tkinter import *
from tkinter import font as tkFont
CLOCK_IMAGE_PATH = 'clock.png'
xclick, yclick = 0, 0
def callback3():
window = Toplevel()
window.title("Stunden")
img = PhotoImage(file=CLOCK_IMAGE_PATH)
img_width, img_height = img.width(), img.height()
window.minsize(width=img_width, height=img_height)
canvas = Canvas(window, width=img_width, height=img_height)
canvas.pack()
canvas.image = img # Keep reference to avoid image being garbage collected.
canvas.create_image(0, 0, anchor='nw', image=img)
canvas.bind("<Button-1>", get_coordinates) # Set up event-handler callback.
def get_coordinates(event):
global xclick, yclick
xclick = int(event.x // 1)
yclick = int(event.y // 1)
print(f'xclick={xclick}, yclick={yclick}')
root = Tk()
helv30 = tkFont.Font(family='Helvetica', size=30)
button1 = Button(root, text="1", width=3, font=helv30, borderwidth=0, command=callback3)
button1.grid(row=0, column=0, padx=5, pady=0)
root.mainloop()

Tkinter opens second GUI first

I'm trying to build a login screen for practice and I'm having trouble with it. The general idea is that pressing the Login button closes the current window and opens another in a separate file. However, when I run the main file it opens the GUI window created in the second file. I'm not sure what would be causing it to do this.
import tkinter as tk
import loginEntry
HEIGHT = 200
WIDTH = 500
def login_function():
root.destroy()
loginEntry.NewScreen()
def register_function():
print("Register!")
root = tk.Tk()
root.title("Login Screen")
root.resizable(False, False)
canvas = tk.Canvas(root, height = HEIGHT, width = WIDTH)
canvas.pack()
frame = tk.Frame(root, bg='grey')
frame.place(relx=0.1, rely=0.25, relwidth=0.8, relheight=0.5)
login = tk.Button(frame, text="Login", command=login_function)
login.place(relx=0.05, rely=0.25, relwidth=0.425, relheight=0.5,)
register = tk.Button(frame, text="Register", command=register_function)
register.place(relx=0.525, rely=0.25, relwidth=0.425, relheight=0.5,)
introduction = tk.Label(root, text="Hello and welcome to DogNet, please login below.", font='bold 12')
introduction.place(relx=0.5, anchor='center', rely=0.1)
root.mainloop()
and then the second file
import tkinter as tk
def NewScreen():
root = tk.Tk()
canvas = tk.Canvas(root, bg='black')
canvas.pack()
root.mainloop()
NewScreen()
This is because, in your second file, you are calling the definition when it is imported.
import tkinter as tk
def NewScreen():
root = tk.Tk()
canvas = tk.Canvas(root, bg='black')
canvas.pack()
root.mainloop()
NewScreen() #< here you call the definition
This means that the series of events that happen in your program are as follows.
First file starts
Second file is imported
Definition "NewScreen" is called
tkinter mainloop starts which puts your program into a loop and stops the program from going on to any new lines until the loop is closed

Scrollbar in python tkinter Toplevel() shows up but does not scroll

I have looked through all the answered questions available here but to no avail. I'm working on Mac OS X High Sierra and my Scrollbar widget shows up but doesn't scroll the window, any advice?
from tkinter import *
root = Tk()
root.geometry('400x500')
root.resizable(False, False)
def window():
popup = Toplevel()
vertScrollbar = Scrollbar(popup, orient='vertical')
vertScrollbar.pack(side='right', fill='y')
scrollCanvas = Canvas(popup, width='400', height='500', yscrollcommand=vertScrollbar.set)
vertScrollbar.config(command=scrollCanvas.yview)
scrollFrame = Frame(scrollCanvas, width='400', height='500')
scrollCanvas.create_window(0, 0, window=scrollFrame, anchor='n')
for words in range(150):
test = Label(scrollCanvas)
test.config(text='this is a test')
test.pack()
scrollCanvas.config(scrollregion=scrollCanvas.bbox('all'))
#scrollCanvas.config(scrollregion=(0,0,400,800)) doesn't work either
scrollCanvas.pack(side='top', fill='both')
scrollFrame.pack(side='top', fill='both')
openWindow = Button(root, text='Push Me', command=window)
openWindow.pack(ipadx='5', ipady='3', pady='10')
root.mainloop()
There is nothing inside scrollFrame.
The labels are packed in popup, not in scrollCanvas
The scrollCanvas.config(scrollregion=scrollCanvas.bbox('all')) doesn't seem to do the job, not clear as to why.
Here is an example that works for Python 3.6.5 on windows 10:
from tkinter import *
root = Tk()
root.geometry('200x200')
root.resizable(False, False)
vertScrollbar = Scrollbar(root, orient='vertical')
vertScrollbar.pack(side='right', fill='y')
scrollCanvas = Canvas(root, width='400', height='500',
scrollregion=(0, 0, 400, 500),
yscrollcommand=vertScrollbar.set)
vertScrollbar.config(command=scrollCanvas.yview)
scrollCanvas.pack(side='top', fill='both')
img = PhotoImage(file='test.gif')
scrollCanvas.create_image(2, 2, anchor='nw', image = img)
root.mainloop()

Lift and raise a Canvas over a Canvas in tkinter

I'm creating a game, and I am using tkinter to build the GUI.
In this game, I want the user to start with a window, filled by a Canvas, with an image as background, and some buttons in some sort of item windows. And this Canvas is the home Canvas of the game.
The problem is that I want the user to click on a Button to land on other Canvas, who will host other things like the map or others buttons for others actions. Actually, I would like to superimpose several canvas (as in the Z-index method), and put a canvas on the top of the list, when I want it (if I click on a button for example).
I already searched and I had to change my mind several times, and now I really don't know how to do it.
I find the following code here on Stack Overflow, but it is coded for Python 2 (I think), and I'm starting coding in Python 3, so I am not able to translate it to Python 3 and solve my problem.
import Tkinter as tk
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.frame = tk.Frame(self)
self.frame.pack(side="top", fill="both", expand=True)
self.label = tk.Label(self, text="Hello, world")
button1 = tk.Button(self, text="Click to hide label",
command=self.hide_label)
button2 = tk.Button(self, text="Click to show label",
command=self.show_label)
self.label.pack(in_=self.frame)
button1.pack(in_=self.frame)
button2.pack(in_=self.frame)
def show_label(self, event=None):
self.label.lift(self.frame)
def hide_label(self, event=None):
self.label.lower(self.frame)
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
My code using grid :
from tkinter import *
fenetre = Tk()
fenetre.title(my game)
# acceuil
# variable acceuil
largeur = 700
hauteur = 430
BG_acceuil = PhotoImage(file="BG_acceuil.gif")
acceuil = Canvas(fenetre, width=largeur, height=hauteur)
acceuil.create_image(0, 0, anchor=NW, image=BG_acceuil)
acceuil.grid(row=0)
acceuil.pack()
# fond
fond = PhotoImage(file="BG_acceuil.gif")
acceuil2 = Canvas(fenetre, width=largeur, height=hauteur)
acceuil2.create_image(0, 0, anchor=NW, image=fond)
acceuil2.pack()
# variable bt_jouer
x0 = 80
y0 = 230
class hide_me():
def hide_me(event, widget, pos):
widget.grid_forget()
def show_me(event, widget, pos):
widget.grid(row=pos)
# Boutton jouer
BT_jouer = Button(acceuil, text="Jouer", command=hide_me())
BT_jouer.configure(width=10, activebackground="#33B5E5", relief=GROOVE)
BT_jouer_window = acceuil.create_window(x0, y0, window=BT_jouer,)
BT_jouer.bind('<Button-1>', lambda event: hide_me(event, BT_jouer, 1))
BT_jouer.grid(row=1)
# Bouton règle
BT_regle = Button(acceuil2, text="Règles", command=fenetre.destroy)
BT_regle.configure(width=10, activebackground="#33B5E5", relief=FLAT, bd=0)
BT_regle_window = acceuil2.create_window(x0, y0 + 50, window=BT_regle)
# Boutton quitter
BT_quit = Button(acceuil, text="Quitter", command=fenetre.destroy)
BT_quit.configure(width=10, activebackground="#33B5E5", relief=FLAT)
BT_quit_window = acceuil.create_window(x0, y0 + 100, window=BT_quit)
fenetre.mainloop()
The answer is very easy: To convert to Python3, change Tkinter to tkinter, and it works!
import tkinter as tk
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.frame = tk.Frame(self)
self.frame.pack(side="top", fill="both", expand=True)
self.label = tk.Label(self, text="Hello, world")
button1 = tk.Button(self, text="Click to hide label",
command=self.hide_label)
button2 = tk.Button(self, text="Click to show label",
command=self.show_label)
self.label.pack(in_=self.frame)
button1.pack(in_=self.frame)
button2.pack(in_=self.frame)
def show_label(self, event=None):
self.label.lift(self.frame)
def hide_label(self, event=None):
self.label.lower(self.frame)
def main():
app = SampleApp()
app.mainloop()
return 0
if __name__ == '__main__':
main()
Note: You are not really hiding the label - it still occupies space on the canvas. The following code, from this entry, really removes the item. It can then be recalled with a pack() call:
from Tkinter import *
def hide_me(event):
event.widget.pack_forget()
root = Tk()
btn=Button(root, text="Click")
btn.bind('<Button-1>', hide_me)
btn.pack()
btn2=Button(root, text="Click too")
btn2.bind('<Button-1>', hide_me)
btn2.pack()
root.mainloop()
I did some testing, and made an equivalent program to yours... The only problem is that the unhidden widget is always packed at the end:
from tkinter import *
def hide_me(event, widget):
widget.pack_forget()
def show_me(event, widget):
widget.pack()
root = Tk()
lbl = Label(root, text="Victim")
btn = Button(root, text="Hide the victim")
btn.bind('<Button-1>', lambda event: hide_me(event, lbl))
btn.pack()
btn2 = Button(root, text="Show the victim")
btn2.bind('<Button-1>', lambda event: show_me(event, lbl))
btn2.pack()
lbl.pack()
root.mainloop()
A better version uses the grid() packer. Here you can actually restore the 'forgotten' widget to its original position. Only slightly more complicated :)
from tkinter import *
def hide_me(event, widget, pos):
widget.grid_forget()
def show_me(event, widget, pos):
widget.grid(row = pos)
root = Tk()
lbl = Label(root, text="Victim")
lbl.grid(row = 0)
btn = Button(root, text="Hide the victim")
btn.bind('<Button-1>', lambda event: hide_me(event, lbl, 0))
btn.grid(row = 1)
btn2 = Button(root, text="Show the victim")
btn2.bind('<Button-1>', lambda event: show_me(event, lbl, 0))
btn2.grid(row = 2)
root.mainloop()
EDIT: Another observation from the comments: Bryan Oakley commented that if you use .grid_remove() instead of .grid_forget(), then the coordinates will not be lost, and a simple .grid() will restore the widget at its location.

Categories