How to make button using canvas in toplevel() Tkinter - python

I'm trying to make a button using canvas.create_window in toplevel() in Tkinter. Button is used to go back to main window. First "Start" button is displayed but second "Back" button is not. Code below.
from tkinter import *
win = Tk()
def play_button():
win.withdraw()
top = Toplevel()
top.geometry("300x300")
button_back = Button(top, text="Back", command=back_button)
canvas_two = Canvas(top, width = 300, height = 300)
canvas_two.pack(fill="both", expand=True)
Button_reverse = canvas_two.create_window(0, 0, anchor="nw", window=button_back)
top.resizable(False, False)
def back_button():
win.deiconify()
win.geometry("300x300")
canvas = Canvas(win, width = 300, height = 300)
canvas.pack(fill="both", expand=True)
button_play = Button(win, text="Play", command=play_button)
Play_button = canvas.create_window(0, 0, anchor="nw", window=button_play )
win.mainloop()

The problem is the ordering of creation of canvas_two and button_back. You need to create the Canvas first and then put the Button on top of it as shown below.
def play_button():
win.withdraw()
top = Toplevel()
top.geometry("300x300")
canvas_two = Canvas(top, width=300, height=300)
canvas_two.pack(fill="both", expand=True)
button_back = Button(top, text="Back", command=back_button)
Button_reverse = canvas_two.create_window(0, 0, anchor="nw", window=button_back)
top.resizable(False, False)

Related

Tkinter Scrollbar Does not work for objects inside canvas

I've made a canvas with two scrollbar and two buttons. But the scrollbar doesn't interact with the buttons inside the canvas.
What I want to make, is whenever I scrolls (for example, scroll down), all buttons in the canvas moves to the opposite direction (in this case, move up), but currently they won't move at all.
ws = Tk()
ws.title('PythonGuides')
frame = Frame(
ws,
width=500,
height=400
)
frame.pack(expand=True, fill=BOTH)
canvas = Canvas(
frame,
bg='#4A7A8C',
width=500,
height=400,
scrollregion=(0, 0, 700, 700)
)
vertibar = Scrollbar(
frame,
orient=VERTICAL
)
vertibar.pack(side=RIGHT, fill=Y)
vertibar.config(command=canvas.yview)
horibar = Scrollbar(
frame,
orient=HORIZONTAL
)
horibar.pack(side=BOTTOM, fill=X)
horibar.config(command=canvas.xview)
canvas.config(width=500, height=400)
canvas.config(
xscrollcommand=horibar.set,
yscrollcommand=vertibar.set
)
example=tkinter.Button(canvas, text="1")
example.grid(row=3, column=5)
example2 = tkinter.Button(canvas, text="2")
example2.grid(row=6, column=7)
canvas.pack(expand=True, side=LEFT, fill=BOTH)
ws.mainloop()
You cannot scroll items of canvas if they are put into the canvas using .grid()/.pack()/.place().
Use .create_window() instead:
...
example = tkinter.Button(canvas, text="1")
canvas.create_window(10, 10, window=example, anchor="nw")
example2 = tkinter.Button(canvas, text="2")
canvas.create_window(50, 50, window=example2, anchor="nw")
...

Python tkinker resitze Canvas

I have an Python3 Tkinter Programm. I have 3 Frames in the Main Window and in one Frame an canvas with scroll Option - now i want resitze the Canvas Area .
Now if i resize it moves the Scroll Bar for Y out the Window and the scrollbar for x works also not as expected (get bigger but slide area don't change)
How i Mange it to resize an Canvas in an grid Layout - The Window must be the same size , the Scrollbas must be updatet and the Canvas Plane must be bigger.
an excerpt from my code:
import tkinter as tk
def menu_build():
caninfo[0] += 10
cangui.configure(width = caninfo[0])
#cangui.configure(scrollregion=cangui.bbox("all"))
def gui():
master = tk.Tk()
master.title( "Easy Switch" )
master.geometry("480x320")
frametop = tk.Frame(master, bg="blue", bd=2)
frametop.grid(column=0,row=0)
frameex = tk.Frame(master, bg="yellow", bd=2)
frameex.grid(column=1,row=1)
framegui = tk.Frame(master, bg="red", bd=2)
framegui.grid(column=0, columnspan=2, row=1)
menu = tk.Menu(master)
master.config(menu=menu)
filemenu = tk.Menu(menu)
menu.add_cascade(label="Config", menu=filemenu)
filemenu.add_command(label="Resize",command=menu_build)
global cangui
cangui = tk.Canvas(framegui, width=385, height=250)
#caninfo = [385,250]
cangui.grid(row=1, column=2)
scroll_x = tk.Scrollbar(framegui, orient="horizontal", command=cangui.xview)
scroll_x.grid(row=2, column=2, sticky="ew")
scroll_y = tk.Scrollbar(framegui, orient="vertical", command=cangui.yview)
scroll_y.grid(row=1, column=3, sticky="ns")
cangui.configure(yscrollcommand=scroll_y.set,xscrollcommand=scroll_x.set)
cangui.configure(scrollregion=cangui.bbox("all"))
cwcb = tk.Checkbutton(framegui, text="ccw").grid(row=2,column=0)
cangui.create_arc(90,90,110,110,style=tk.PIESLICE,width=4,start=0,extent=300)
master.mainloop()
global caninfo
caninfo = [385,250]
if __name__ == "__main__":
gui()
no need to resize the canvas Area
wrote an extra funktion
win = [int(cangui.cget("width")),int(cangui.cget("height"))]
draw_xy = cangui.bbox("all")
swin = (min(0,draw_xy[0]),min(0,draw_xy[1]),max(draw_xy[2],win[0]),max(draw_xy[3],win[1]))
cangui.configure(scrollregion=swin)
reason: canvas.bbox("all") gives only the positon from most upper/left grafic and i want 0/0

How do I link a widget to a function in Tkinter [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
This is my current code. I am looking to link the buttons I made to open a new window. I want the old Window to then close. When the new Window opens, how do I go about creating a new interface for that Window.
Code:
import tkinter as tk
HEIGHT = 950
WIDTH = 650
root=tk.Tk()
canvas = tk.Canvas(root, height=HEIGHT, width=WIDTH)
canvas.pack()
frame = tk.Frame(root, bg='#80c1ff')
frame.place(relx=0.5, rely=0.1, relwidth=0.75, relheight=0.1, anchor='n')
button = tk.Button(frame, text="Credit Score Checker")
font = ("Helvetica",20,"bold")
button.place(relx=-0, relheight=1, relwidth=0.27)
button = tk.Button(frame, text="Financial Advisor")
font = ("Helvetica",20,"bold")
button.place(relx=0.25, relheight=1, relwidth=0.27)
button = tk.Button(frame, text="Insurance Planner")
font = ("Helvetica",20,"bold")
button.place(relx=0.5, relheight=1, relwidth=0.27)
button = tk.Button(frame, text="Goal Setter")
font = ("Helvetica",20,"bold")
button.place(relx=0.75, relheight=1, relwidth=0.26)
lower_frame = tk.Frame(root, bg='#80c1ff', bd=10)
lower_frame.place(relx=0.5, rely=0.25, relwidth=0.75, relheight=0.6, anchor='n')
label = tk.Label(lower_frame, text="Summary of finances", bg='grey')
label.place(relx=0.5, rely=0, anchor='n', relwidth=0.9, relheight=1)
root.mainloop()
Here is an example of a button that opens up a new window when clicked I hope this helps
from tkinter import *
main = Tk()
main.geometry("1000x1000")
main.title("Welcome")
canvas = Canvas(main, width = 1500, height = 1000, bg = "spring green")
canvas.place(relx = 0.5, rely = 0.5, anchor = CENTER)
frame = Frame(main)
frame = Frame(main, width = 500, height = 500, bg = "cyan")
frame.place(relx = 0.5, rely = 0.5, anchor = CENTER)
frame3 = Frame(main, width=300, height=300, bg="orange")
frame3.place(relx = 0.5, rely = 0.5, anchor = CENTER)
# LABEL:
lbl = Label(main, text = "Hi", fg = "deep pink", font = ("Fixedsys",30), bg = "spring green")
lbl.place(relx = 0.5, rely = 0.5, anchor = CENTER)
# FUNCTION FOR BUTTON:
def on_click():
root = Tk()
frame2 = Frame(root)
frame2 = Frame(root, width = 1000, height = 1000, bg = "cyan")
frame2.place(relx = 0.5, rely = 0.5, anchor = CENTER)
root.geometry("700x700")
root.title("SUP")
label_new = Label(root, text = "There you go :)", font = ("Fixedsys", 22), fg = "red", bg = "black")
label_new.place(relx = 0.5, rely = 0.5, anchor = CENTER)
# BUTTON:
btn = Button(main, text = "this is a button", fg = "blue", font = ("Fixedsys",20), bg = "dark turquoise", command=on_click)
btn.place(relx = 1.0, rely = 0.0, anchor = NE)
main.mainloop()
If you really want to create a new window every time the button is pressed and display the new widgets on this window, then the other answers provide an excellent solution. But rather than create a new window to display the new widgets, I would recommend simply destroying the old widgets on the current window and putting up the new ones on the same window. It has the same effect as "closing the old window and creating a new one".
To destroy all the widgets on the screen, simply write a function like this and call it whenever you want to remove all the old widgets and put up new ones.
def clear() :
for widget in root.winfo_children() :
widget.destroy()
The above function iterates through all the widgets that have been put up on the window and destroys them, one by one.
Here is an example code to illustrate how this works.
import tkinter as tk
root = tk.Tk()
root.config(bg="#424242")
def clear() :
for widget in root.winfo_children() :
widget.destroy()
def window1() :
clear()
lbl1 = tk.Label(root,text="Hey there! Im part of window1!!",fg="white",bg="#424242")
lbl1.pack()
lbl2 = tk.Label(root,text="Im also a part of window1!!",fg="white",bg="#424242")
lbl2.pack()
btn1 = tk.Button(root,text="Press me to display window2",command=window2,fg="white",bg="#424242")
btn1.pack()
def window2() :
clear()
lbl1 = tk.Label(root,text="Hey there! Im part of window2!!",fg="white",bg="#424242")
lbl1.pack()
lbl2 = tk.Label(root,text="Im also a part of window2!!",fg="white",bg="#424242")
lbl2.pack()
btn1 = tk.Button(root,text="Press me to display window1",command=window1,fg="white",bg="#424242")
btn1.pack()
window1()
root.mainloop()
Here, as Cool Cloud has already said, a command parameter is passed to the button with the next function to be called. Both the functions,window1 and window2 call the clear function first which effectively clears the screen ,and then the new widgets are put up on the window.

How to draw diagonal arrows in tkinter?

I need to draw two arrows from the blue and green box pointing to the yellow box. I tried drawing diagonal lines using create_line but it didn't work. can anyone please suggest any ways I could draw these arrows.
the error message when using create_line is: AttributeError: '_tkinter.tkapp' object has no attribute 'create_line'
from tkinter import *
import tkinter as tk
window = Tk()
window.geometry("900x500")
window.configure(background='red')
window.title("Theoretical")
label1 = Label(window, text="Hess' cycle of combustion", fg="black", bg="red", font=("Comic Sans MS", 20))
label1.pack()
text1 = Text(window, width=20, height = 1, bg= "blue")
text1.place(x=200, y=100)
window.create_line(0, 0, 200, 100)
window.create_line(0, 100, 200, 0, fill="white")
text2 = Text(window, width=20, height = 1, bg= "green")
text2.place(x=520, y=100)
text3 = Text(window, width=20, height = 1, bg= "yellow")
text3.place(x=370, y=250)
## arrow = Label(window, width=13,height = 1, text = "-------------->", bg= "lawn green", font=("Helvetica", 20))
## arrow.place(x= 330, y=90)
global textbox
textbox = Text(window, width=400, height=10)
textbox.place(x=0, y= 365)
tkinter lines have an arrow option; however, as pointed out in te comments,create_line is a Canvas method: you must therefore use a tk.Canvas object to draw lines:
This minimum example shows you how:
import tkinter as tk
window = tk.Tk()
canvas = tk.Canvas(window)
canvas.pack()
canvas.create_line(0, 0, 200, 100, arrow=tk.LAST)
window.mainloop()
Please note that to avoid "hard to fix" problems and unexpected behavior, it is usually recommended not to import modules in the main namespace (i/e do not from tkinter import *), and not to mix geometry managers ((i/e do not use .place and .pack in the same app)
Edit:
In order to place widgets on a canvas, you must use the Canvas.create_window() method:
import tkinter as tk
window = tk.Tk()
window.geometry("600x600")
canvas = tk.Canvas(window, width=600, height=600)
label_1 = tk.Label(window, text = "from here", anchor = tk.W)
label_1.configure(width = 10, activebackground = "#33B5E5", relief = tk.FLAT)
label_1_window = canvas.create_window(280, 0, anchor=tk.NW, window=label_1)
label_2 = tk.Label(window, text = "to there", anchor = tk.W)
label_2.configure(width = 10, activebackground = "#33B5E5", relief = tk.FLAT)
label_2_window = canvas.create_window(280, 310, anchor=tk.NW, window=label_2)
canvas.pack()
canvas.create_line(300, 40, 300, 300, arrow=tk.LAST)
window.mainloop()

Tkinter, I cannot get my slider to show all buttons

Here is a sample of what I am doing. I put 500 buttons on a sliding canvas, and I can only scroll to button 109. What am I doing wrong? I've tried adjusting the width on the widgets, as well as the scrollregion. I'm sure I'm overlooking something simple.
import Tkinter
from Tkinter import *
import os, signal
window1 = Tkinter.Tk()
window1.attributes('-fullscreen', True)
window1.bind("<Escape>", lambda e: e.widget.quit())
window2 = Tkinter.Label(window1)
window2.configure(bg = "blue")
window2.place(x=0, y=0, relwidth=1, relheight=1)
frame=Frame(window2, height=160)
frame.pack(anchor=Tkinter.SW,side=Tkinter.BOTTOM)
canvas=Canvas(frame,bg='black', width=5500, height=160, scrollregion=(0,0,5500,0))
hbar=Scrollbar(frame,orient=HORIZONTAL, bg='black', troughcolor='black')
hbar.pack(side=BOTTOM,fill=X)
hbar.config(command=canvas.xview)
canvas.config(xscrollcommand=hbar.set, xscrollincrement=4.5)
canvas.pack(side=LEFT,expand=True,fill=BOTH)
frm = Frame(canvas)
canvas.create_window(0, 0, window=frm, anchor='nw')
def quit():
window1.quit()
count = 0
while (count < 500):
X = Tkinter.Button(frm, text=str(count), height=6, width=5, padx=0, pady=0, highlightcolor="blue", highlightthickness=3, command=quit)
X.pack(side = "left")
count = count + 1
window1.mainloop()
The problem is that your scrollregion on the Canvas instance isn't wide enough. You can calculate how wide it needs to be based on the requested width of all the buttons, and then set the scrollregion after you've made all the buttons, like this:
import Tkinter
import os, signal
window1 = Tkinter.Tk()
window1.attributes('-fullscreen', True)
window1.bind("<Escape>", lambda e: e.widget.quit())
window2 = Tkinter.Label(window1)
window2.configure(bg = "blue")
window2.place(x=0, y=0, relwidth=1, relheight=1)
frame = Tkinter.Frame(window2, height=160)
frame.pack(anchor=Tkinter.SW,side=Tkinter.BOTTOM)
canvas=Tkinter.Canvas(frame,bg='black', width=5500, height=160)
hbar=Tkinter.Scrollbar(frame,orient=Tkinter.HORIZONTAL, bg='black', troughcolor='black')
hbar.pack(side=Tkinter.BOTTOM,fill=Tkinter.X)
hbar.config(command=canvas.xview)
canvas.config(xscrollcommand=hbar.set, xscrollincrement=4.5)
canvas.pack(side=Tkinter.LEFT, expand=True, fill=Tkinter.BOTH)
frm = Tkinter.Frame(canvas)
canvas.create_window(0, 0, window=frm, anchor='nw')
def quit():
window1.quit()
count = 0
width = 0
while (count < 500):
X = Tkinter.Button(frm, text=str(count), height=6, width=5, padx=0, pady=0, highlightcolor="blue", highlightthickness=3, command=quit)
X.pack(side = "left")
width += X.winfo_reqwidth()
count = count + 1
canvas.config(scrollregion=(0, 0, width, 0))
window1.mainloop()
As a side note, your first two import statements are redundant. In this example, I dropped the second one to avoid polluting the global namespace.

Categories