multiple buttons on a tkinter canvas - python

I need multiple buttons on a canvas in Python Tkinter. The purpose is to draw connection lines among the buttons. My code:
from tkinter import *
root=Tk()
convas = Canvas(root)
convas.pack()
button1 = Button(text = "button 1")
button1.configure(width = 0, activebackground = "#D2D2D2", relief = GROOVE)
button1_window = convas.create_window(10, 10, anchor=NW, window=button1)
button1.update()
print (button1.winfo_geometry())
button2 = Button(text = "button 2")
button2.configure(width = 0, activebackground = "#D2D2D2", relief = GROOVE)
button2_window = convas.create_window(10, 50, anchor=NW, window=button1)
button2.update()
print (button2.winfo_geometry())
root.mainloop()
running this code, I always just got button 1 in the canvas although I tried to adjust the location in the create_window function, and the anchor=. the button 2 does not show in the canvas at all.
The two prints return:
62x26+10+10
1x1+0+0.
Based on the output 1x1+0+0, the button 2 seems not being rendered. what I am doing wrong?
EDIT:
My mistake:
button2_window = convas.create_window(10, 50, anchor=NW, window=button1)
should be
button2_window = convas.create_window(10, 50, anchor=NW, window=button2)

Your second button code in line 14 says window=button1. Change it to:
button2_window = convas.create_window(10, 50, anchor=NW, window=button2)
So that button2 shows up on its window like this:

Related

White blink when creating new window?

I'm creating this program that it's not complete yet, a small detail that annoys me, when you run the program and click "OPEN" it creates a new Toplevel window inside the def click_selettore function in the beginning, and i notice that the black screen on the left "blinks" for a split second, for a split second is white and then it become black i hope you notice this, the photo attached it's a frame of the Toplevel opening window and i notice the white frames that are loading i think, and they are white for a split second. How to solve this and not making the new window white for the split second? Thanks, here is the code it's a bit long but the probelm is only the white blinks when creating the window inside the "click selettore" function, if you help me i would really appreciate it
from tkinter import *
import customtkinter
from ctypes import windll
windll.shcore.SetProcessDpiAwareness(1)
def click_selettore(event):
bg = "#414141"
win.attributes('-topmost', 0)
win2 = Toplevel(win)
win2.focus()
win2.resizable(False,False)
win2.grab_set()
win2.configure(bg=bg)
win2.title("Selettore colori")
frame_schermo = Frame(win2)
frame_schermo.grid(row=0,column=0,padx=(20,0),pady=(20,0))
schermo = Label(frame_schermo, bg="#000000", width=45, height=9, relief="solid", borderwidth=3)
schermo.grid(row=0,column=0)
frame_slider = Frame(win2,bg=bg)
frame_slider.grid(row=0,column=1,sticky=N,pady=(20,0),padx=(50,0))
etc_rosso = Label(frame_slider, text="Rosso", bg=bg, fg="#C70000", font=("Ink Free", 20, "bold"))
etc_rosso.grid(row=0,column=0,pady=(11,0))
slider_rosso = customtkinter.CTkSlider(frame_slider, from_=0, to=255,width=230,progress_color='#C70000',fg_color='#a34949',button_hover_color='#3f9feb',button_color='#1f82d1')
slider_rosso.grid(row=0,column=1,sticky=N,padx=(10,0),pady=(23,0))
slider_rosso.set(0)
casella_rosso = customtkinter.CTkEntry(master=frame_slider,text_font=('Courier',15,'bold'),width=55)
casella_rosso.grid(row=0,column=2,pady=(11,0),padx=(7,20))
casella_rosso.insert(0,0)
etc_verde = Label(frame_slider, text="Verde", bg=bg, fg="#3fc441", font=("Ink Free", 20, "bold"))
etc_verde.grid(row=1,column=0,pady=(11,0))
slider_verde = customtkinter.CTkSlider(frame_slider, from_=0, to=255, width=230, progress_color='#3fc441', fg_color='#3d803e', button_hover_color='#3f9feb', button_color='#1f82d1')
slider_verde.grid(row=1, column=1, sticky=N,padx=(10,0),pady=(23,0))
slider_verde.set(0)
casella_verde = customtkinter.CTkEntry(master=frame_slider, text_font=('Courier', 15, 'bold'), width=55)
casella_verde.grid(row=1, column=2,pady=(11,0),padx=(7,20))
casella_verde.insert(0, 0)
etc_blu = Label(frame_slider, text="Blu", bg=bg, fg="#010178", font=("Ink Free", 20, "bold"))
etc_blu.grid(row=2,column=0,pady=(11,0))
slider_blu = customtkinter.CTkSlider(frame_slider, from_=0, to=255, width=230, progress_color='#010178',fg_color='#222275', button_hover_color='#3f9feb', button_color='#1f82d1')
slider_blu.grid(row=2, column=1, sticky=N,padx=(10,0),pady=(23,0))
slider_blu.set(0)
casella_blu = customtkinter.CTkEntry(master=frame_slider, text_font=('Courier', 15, 'bold'), width=55)
casella_blu.grid(row=2, column=2,pady=(11,0),padx=(7,20))
casella_blu.insert(0, 0)
frame_sotto_slider = Frame(win2,bg=bg)
frame_sotto_slider.grid(row=1,column=0,pady=(45,0),padx=(35,0))
etc_esadecimale_titolo= Label(frame_sotto_slider,text='Esadecimale -> ',font=('Courier',16),fg='white',bg=bg)
etc_esadecimale_titolo.grid(row=0,column=0)
campo_esadecimale = customtkinter.CTkEntry(master=frame_sotto_slider,text_font=('Courier',16),width=105)
campo_esadecimale.grid(row=0,column=1,padx=(6,0))
btn_ok = customtkinter.CTkButton(win2,text='Ok',text_font=('Courier',16),width=50,corner_radius=10,hover_color='#3a76a6')
btn_ok.grid(row=3,column=1,sticky=E,pady=(50,10),padx=(0,10))
win.eval(f'tk::PlaceWindow {str(win2)} center')
win2.mainloop()
win = Tk()
win.configure(bg="#2b2b2b")
etichetta_selettore_colori = Label(win,text='OPEN',relief="solid",borderwidth=4,font=('Helvetica',17))
etichetta_selettore_colori.grid(row=0,column=0,padx=(20,0),pady=20)
etichetta_selettore_colori.bind("<Button-1>",click_selettore)
win.eval('tk::PlaceWindow . center')
win.mainloop()

How do I make a tkinter button destroy itself?

I made this program in Tkinter in python where a small window pops up when the code is run and a start button would pop up and make the window full screen and show the content after. I want to make the button destroy itself after I press it so it makes a fullscreen and removes the button. I am still a beginner and would like the answer to be simple. The solution I am looking for is to maybe destroy the button completely(preferred) or move it way out of sight in the fullscreen window. Here is the code:
import Tkinter as w
from Tkinter import *
w = Tk()
w.geometry("150x50+680+350")
def w1():
w.attributes("-fullscreen", True)
l1 = Label(w, text = "Loaded!", height = 6, width = 8).pack()
global b1
b1.place(x = -10000, y = -10000)
b1 = Button(w, text = "Start", height = 3, width = 20, command = w1).place(x = 0, y = 10)
b2 = Button(w, text = "Exit", command = w.destroy).place(x = 1506, y = 0)
w.mainloop()
As you can see I want to make button one destroy itself.
Try this:
import tkinter as tk # Use `import Tkinter as tk` for Python 2
root = tk.Tk()
root.geometry("150x50+680+350")
def function():
global button_start
root.attributes("-fullscreen", True)
label = tk.Label(root, text="Loaded!", height=6, width=8)
label.pack()
button_start.place_forget() # You can also use `button_start.destroy()`
button_start = tk.Button(root, text="Start", height=3, width=20, command=function)
button_start.place(x = 0, y = 10)
button_exit = tk.Button(root, text="Exit", command=root.destroy)
button_exit.place(x=1506, y=0)
root.mainloop()
PS: Please read this.
Try:
b1.place_forget()
This will essentially "forget" about the button and hide it from view.
Edit:
If you are getting the error that b1 is None try:
b1 = Button(w, text = "Start", height = 3, width = 20, command = w1)
b1.place(x = 0, y = 10)
You need to add the b1.place() option at the bottom for this to work

Update text widget in tkinter from function

The problem:
I am trying to update the same text widget box from a function that contains some text. Instead a whole new text window appears every time.
Here is my code:
from tkinter import *
import os
#Tkinter graphics
homepage = Tk()
homepage.title("My first GUI")
# set size of window
homepage.geometry('1200x400')
# Add image file
bg = PhotoImage(file = "maxresdefault.png")
# Show image using label
label1 = Label( homepage, image = bg)
label1.place(x = 0, y = 0)
label2 = Label( homepage, text = "Test App")
label2.pack()
# Create Frame
frame1 = Frame(homepage)
frame1.pack()
#button initatiors
def buttonupdate():
S = Scrollbar(homepage)
T = Text(homepage, height=100, width=30)
T.pack()
T.pack(side=RIGHT, fill= Y)
S.pack(side = RIGHT, fill = Y)
S.config(command=T.yview)
T.insert(END, "test")
T.config(yscrollcommand=S.set, state=DISABLED)
# Static buttons
tickets30button = Button(text = "This is button 1", command=buttonupdate)
tickets30button.place(x=0, y=26)
mcibutton = Button(text = "This is button 2")
mcibutton.place(x=0, y=52)
hdebutton = Button(text = "This is button 3")
hdebutton.place(x=0, y=78)
homepage.mainloop()
Here is the result if I click on the first button three times:
Let me know if you have any suggestions that I can try.
Thank you for your time,
I was able to update my text window instead of create a new one, upon each click of a button, thanks to #TheLizzard.
He mentioned to move the section of code that creates the text window outside of the function and keep the section of code that creates the text, inside the function.
Before:
#button initiators
def buttonupdate():
S = Scrollbar(homepage)
T = Text(homepage, height=100, width=30)
T.pack()
T.pack(side=RIGHT, fill= Y)
S.pack(side = RIGHT, fill = Y)
S.config(command=T.yview)
T.insert(END, "test")
T.config(yscrollcommand=S.set, state=DISABLED)
After: (UPDATED)
S = Scrollbar(homepage)
T = Text(homepage, height=100, width=30)
T.pack(side=RIGHT, fill= Y)
S.pack(side = RIGHT, fill = Y)
S.config(command=T.yview)
T.config(yscrollcommand=S.set, state=DISABLED)
#button initatiors
def myTicketstatusbutton():
T.delete(1.0,END)
T.insert(END, "test")

Changing the colour of tkinter rectangles using Entry and button

Super new to coding, I have a tkinter GUI with 5 rectangles, an entry box, and a button labelled go. I want to be able to change the color of the rectangles based on the number I enter into the entry box after I hit go. I don't think i'm close? but i have no idea how to proceed. Help would be appreciated. Thanks
from tkinter import *
the_window = Tk()
the_window.title('Show Text Count')
def changelbl():
number=(numberx.get())
if (numberx == 1):
label1.config(fill='green')
numberx=StringVar()
canvas = Canvas(the_window, width=270, height=20)
canvas.pack()
label1 = canvas.create_rectangle(0, 0, 50, 20, fill='grey')
label2 = canvas.create_rectangle(55, 0, 105, 20, fill='grey')
label3 = canvas.create_rectangle(110, 0, 160, 20, fill='grey')
label4 = canvas.create_rectangle(165, 0, 215, 20, fill='grey')
label5 = canvas.create_rectangle(220, 0, 270, 20, fill='grey')
Entrybox = Entry(the_window, bg='grey', width=15, textvariable=numberx)
Entrybox.pack(padx=(60,0), side=LEFT)
Gobutton = Button(the_window, text='Go',command=changelbl)
Gobutton.config(height=1, width=5)
Gobutton.pack(padx=(15,0), side=LEFT)
Here is a corrected version that changes the rectangle colors upon entry of a number in the entrybox, and pressing the Go button:
from tkinter import *
the_window = Tk()
the_window.title('Show Text Count')
def on_Go_button():
try:
num = int(entrybox.get())
except:
num = 3
num = num % 5
canvas.itemconfig(num, fill='green')
numberx=StringVar()
canvas = Canvas(the_window, width=270, height=20)
canvas.pack()
pos = [(0, 0, 50, 20), (55, 0, 105, 20), (110, 0, 160, 20), (165, 0, 215, 20), (220, 0, 270, 20)]
rectangles = [None for _ in range(5)]
for idx in range(5):
rectangles[idx] = canvas.create_rectangle(*pos[idx], fill='grey')
entrybox = Entry(the_window, bg='grey', width=15, textvariable=numberx)
entrybox.pack(padx=(60,0), side=LEFT)
gobutton = Button(the_window, text='Go',command=on_Go_button)
gobutton.config(height=1, width=5)
gobutton.pack(padx=(15,0), side=LEFT)
the_window.mainloop()
This may not be as simple of an answer as you were looking for, but hopefully it will be of some help.
I thought that creating a class would be a better approach for getting your desired result. I also changed changelbl to allow for multiple color options to be retrieved from a dictionary.
In your code, you were missing the line, the_window.mainloop() which will start start running your tkinter window.
from tkinter import *
class ColorBoxes:
def __init__(self, the_window):
self.root = the_window
self.root.title('Show Text Count')
self.canvas = Canvas(self.root, width=270, height=20)
self.canvas.pack()
self.label1 = self.canvas.create_rectangle(0, 0, 50, 20, fill='grey')
self.label2 = self.canvas.create_rectangle(55, 0, 105, 20, fill='grey')
self.label3 = self.canvas.create_rectangle(110, 0, 160, 20, fill='grey')
self.label4 = self.canvas.create_rectangle(165, 0, 215, 20, fill='grey')
self.label5 = self.canvas.create_rectangle(220, 0, 270, 20, fill='grey')
self.entry_box = Entry(self.root, bg='grey', width=15,)
self.entry_box.pack(padx=60, side=LEFT)
self.go_button = Button(self.root, text='Go', command=self.changelbl)
self.go_button.config(height=1, width=5)
self.go_button.pack(padx=15, side=LEFT)
def changelbl(self):
number = self.entry_box.get()
fill_colors = {
'1': 'green',
'2': 'yellow',
'3': 'red'
# can add more colors to this dictionary if needed
}
self.canvas.itemconfig(self.label1, fill=fill_colors.get(number))
self.canvas.itemconfig(self.label2, fill=fill_colors.get(number))
self.canvas.itemconfig(self.label3, fill=fill_colors.get(number))
self.canvas.itemconfig(self.label4, fill=fill_colors.get(number))
self.canvas.itemconfig(self.label5, fill=fill_colors.get(number))
the_window = Tk()
ColorBoxes(the_window)
the_window.mainloop()
Again, this may be more than you were looking for, but hopefully you can pick up on what is going on and learn a bit! Good luck!

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.

Categories