I'm trying to add a label to a Tkinter button. A Tkinter button has a 'text' attribute which is great. However I need another similar text field on the button, i.e 2 text fields per button. So I would like to add a label as a child to the button. The problem with this is that it creates unpredictable behaviour. Actuating the button or even just hovering the mouse over the label causes the label to vanish.
button_1 = tk.Button(canvas, text='Take',command='take',width='12')
button_1.pack()
label_1 = tk.Label(button_1, text='Stream 1',font=('calibre',8))
label_1.pack()
label_1.place(x=10, y=10)
I can avoid this unwanted behaviour by adding the label to the same parent as the button.
label_1 = tk.Label(canvas, text='Stream 1',font=('calibre',8))
But by doing this I loose the convenience of positioning the label with the button's geometry, e.g inset by 10 pixels from left and 10 pixels from top of button. I plan to make a convenience method for adding hundreds of such buttons, and do not wish to be attempting to calculate each label in the parents coordinates. And besides, as a sub-child of the button, it becomes part of the button hierarchy, i.e. will move with the button, will be hidden with the button etc.
You can display multiple lines of text on a Button by embedding newlines in the text.
Like this:
import tkinter as tk
root = tk.Tk()
root.geometry('100x100')
canvas = tk.Canvas(root)
canvas.pack()
button_1 = tk.Button(canvas, text='Take\nStream 1',command='take',width='12')
button_1.pack()
#label_1 = tk.Label(button_1, text='Stream 1',font=('calibre',8))
#label_1.pack()
#label_1.place(x=10, y=10)
root.mainloop()
Result:
You can use the anchor and justify options to change the positioning of the text on the Label:
button_1 = tk.Button(canvas, text='Take\nStream 1', command='take', width='12',
anchor='w', justify='left')
button_1.pack()
Result 2:
Related
from tkinter import *
from tkinter import messagebox, Tk, Button, Canvas, Frame, BOTH
master = Tk() #tkinter name
click = 0 #click variable
label1 = Label(master, textvariable = click, font=('Times 14'), width=20, height=5) #label itself with font and a width with height
label1.pack()
for i in range(6):
time.sleep(1) # sleeping time 1 second
master.update_idletasks() #updates the label every second in order to see the change of the variable click
I tried a lot of methods, but the label just stays empty and there are no numbers or letters on it. I also think about making a label transparent so I can see only numbers in there.
I am working on a project where I need to display information when a button is clicked, and hide information when that button is clicked again. The information can be several rows and extend beyond the window, so I am trying to add a scroll bar to get around this issue. The problem is that when the information is displayed, the scroll bar does not show. Scrolling is still possible but the actual bar is not there. Resizing the window fixes this issue for some reason. Also when the button is clicked again to hide the information, the size of the canvas and the scrollbar remain the same, so you can scroll far beyond the button into empty space. My theory is that the scroll region is not updating when the widgets in the canvas change size - but I'm not sure how to go about fixing that.
I realize this explanation may be a bit confusing, so I have provided a simplified example below. This example has a single button that when clicked reveals several lines of "other info". The scrollbar and/or canvas does not resize properly upon interacting with this button.
My strategy right now was to have a method called add_scrollbar that removes the current scrollbar and creates a new one every time the widgets change in hopes that the new one would be the right size; however this still is not working.
from tkinter import *
from tkinter import ttk
def add_scrollbar(outer_frame, canvas):
if len(outer_frame.winfo_children()) == 2:
# canvas is at index 0 of the outer frame, if a scrollbar has been added it will be at index 1
outer_frame.winfo_children()[1].destroy()
# my strategy here was to destroy the existing scroll bar
# and create a new one each time the widget changes size
scrollbar = ttk.Scrollbar(outer_frame, orient=VERTICAL, command=canvas.yview)
scrollbar.pack(side=RIGHT, fill=Y)
canvas.configure(yscrollcommand=scrollbar.set)
canvas.bind('<Configure>', lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
return
def create_example():
root = Tk()
root.geometry("1200x1200")
my_outer_frame = Frame(root)
my_outer_frame.pack(fill=BOTH, expand=1)
my_canvas = Canvas(my_outer_frame)
my_canvas.pack(side=LEFT, fill=BOTH, expand=1)
inner_frame = Frame(my_canvas)
my_canvas.create_window((0, 0), window=inner_frame)
# ^^^ Sets up the ability to have a scroll_bar
changing_frame = Frame(inner_frame, borderwidth=4) # this is the frame that will be changing its contents
changing_frame.pack(side=LEFT, anchor="n")
display_frame(changing_frame, my_outer_frame, my_canvas)
# this method re-displays the changing frame depending on the specified size ('big' or 'small'
root.mainloop()
return
def display_frame(frame, outer_frame, canvas, size='small'):
for widget in frame.winfo_children():
widget.destroy()
if size == 'small':
Button(frame, height=5, width=5, text="Show",
command=lambda this_frame=frame: display_frame(this_frame, outer_frame, canvas, size='big')).grid(row=0,
column=0)
elif size == 'big':
Button(frame, height=5, width=5, text="Hide",
command=lambda this_frame=frame: display_frame(this_frame, outer_frame, canvas, size='small')).grid(
row=0, column=0)
for n in range(1, 100):
Label(frame, text="Other Stuff!").grid(row=n, column=0)
frame.pack(side=LEFT)
add_scrollbar(outer_frame, canvas) # this method is supposed to destroy the existing scrollbar and make a new one
return
if __name__ == '__main__':
create_example()
So, I have 4 Entry Widgets on my window and I just wanted to add some internal left padding on the last Entry Widget. I did so using ttk.style(), which added the desired padding but it also added some additional styling like a black border, some hover effect, then the entry widget gets a blue border when selected.
This is my Code:
from tkinter import *
from tkinter import ttk
root = Tk()
root.configure(padx=50)
input1 = Entry(root)
input1.grid(row=1, column=0, pady=10)
input2 = Entry(root)
input2.grid(row=2, column=0, pady=10)
input3 = Entry(root)
input3.grid(row=3, column=0, pady=10)
style = ttk.Style(root)
style.configure('padded.TEntry', padding=[15, 0, 0, 0])
e = ttk.Entry(root, style='padded.TEntry')
e.grid(row=4,column=0, pady=10)
root.mainloop()
Look how the 4th Entry Widget has a Black Border around it
Look how a Blue Border appears when the widget is selected
The only styling that I was excepting is the little increase in width because of the left-padding, but how are these other styles being triggered.
It is because the fourth entry is a ttk.Entry widget but the other three are tkinter.Entry widgets. If you make all four ttk.Entry widgets you'll see that they all have the additional styles.
Even though the tkinter and ttk modules have widgets with the same name, they are completely different widgets with their own sets of defaults.
I was wondering how I would add some sort of background text in the input box defined in the code attached here under:
The box could say "Example: Joe Bloggs" but greyed out and then remove when the user clicks inside the box? Hope this isn't too tricky.
# ************ Retrieve user's Full name ************
tk.Label(self, text='First and last name:').grid(sticky='e') # Label
self.full_name_entry = tk.Entry(self, bg='white', width=30) # Entry box
self.full_name_entry.grid(row=1, column=1, pady=15, columnspan=2) # Entry box placement
You need to:
use tk.Entry.insert to add the default text to an Entry widget
set the foreground color to 'grey'
upon the entry getting focus, the default is deleted, and the foreground set to 'black'.
you type in the text.
upon pressing return, the value of the entry is extracted, then the entry is reset with the default text in grey.
exiting the focus also resets the entry to default grey (you may want to choose avoid this as a partial entry will then be deleted if you make the entry lose focus; by clicking outside the box, for instance)
Here is what the code look like
import tkinter as tk
def handle_focus_in(_):
full_name_entry.delete(0, tk.END)
full_name_entry.config(fg='black')
def handle_focus_out(_):
full_name_entry.delete(0, tk.END)
full_name_entry.config(fg='grey')
full_name_entry.insert(0, "Example: Joe Bloggs")
def handle_enter(txt):
print(full_name_entry.get())
handle_focus_out('dummy')
root = tk.Tk()
label = tk.Label(root, text='First and last name:')
label.grid(sticky='e')
full_name_entry = tk.Entry(root, bg='white', width=30, fg='grey')
full_name_entry.grid(row=1, column=1, pady=15, columnspan=2)
full_name_entry.insert(0, "Example: Joe Bloggs")
full_name_entry.bind("<FocusIn>", handle_focus_in)
full_name_entry.bind("<FocusOut>", handle_focus_out)
full_name_entry.bind("<Return>", handle_enter)
root.mainloop()
Here is what it looks upon opening the window:
Upon giving focus to the Entry widget, the example text is deleted, and the font color changed to black; after filling the entry, the aspect is:
I am doing a GUI using for my code and finding it hard to develop what i want.
First ...
on the window an image and label appear and disappear after couple of seconds. after that a frame should arrive, followed by a menu option, when the menu option is selected it should disappear from frame and another image should appear.
self.gui = Tk()
def configure_window(self):
self.gui.geometry('700x500')
self.gui.resizable(height=False, width=False)
self.gui.update()
self.welcome_label()
self.welcome_image()
def welcome__image(self):
image = Image.open(image path)
photo = ImageTk.PhotoImage(image)
welcome_image = Label(master=self.gui, image=photo, justify='center',relief='raised')
welcome_image.image = photo
welcome_image.pack(padx=100, pady=100)
welcome_image.place(bordermode='outside', x=200,y=100)
welcome_image.after(ms=1000, func=welcome_image.place_forget)
def welcome_label(self):
welcome_label = Label(master=self.gui, text=welcome_label_text,font=welcome_label_font, justify='center',
state='active', fg='blue', anchor='center', pady=10, relief='raised' )
welcome_label.place(x=100, y=350)
welcome_label.after(ms=1000, func=welcome_label.place_forget)
def first_frame(self):
self.first_frame = LabelFrame( master = self.gui,text='Select First File',font= 'arial 10 bold underline', bg=self.background_colour,
height=200,width=690, bd=1, padx=5, pady=5)
self.first_frame.pack()
self.first_frame.place(x=0, y=0)
def select_button1(self):
self.file_open_button1 = Button(master=self.first_frame,text='...',state='disabled',command=self.cmd_file_select_button1)
when i run the code, welcome_image and welcome_frame places and forgets places after 1000 ms, but, first_frame also loads with parent widget. i want frame to arrive after the welcome_label disappears.
and the same sequence continues for LabelFrame
i have widgets in LabelFrame in which i have OptionMenu and button, i want optionMenu to disappear when user selects an option and another button should appear, same sequence in the button, button returns some sting and a label should appear in the place of button etc.
how to generate the sequence e.g. if an widget has place_forget() a sequence will be generated and another widget should be bind on that sequence. please help.
apology, if i am unable to make you understand my problem.