Related
Somehow the buttons placed using grid method will be much bigger than the cell width defined by columnconfigure. I tried to place some test labels in the same way, and it worked as expected. Is there any way to get correct button width like these labels did?
Below is the simplified code to the question:
import tkinter as tk
from tkinter.ttk import *
root = tk.Tk()
style = Style()
style.theme_use('clam')
style.configure('TestLabel1.TLabel', background='red')
style.configure('TestLabel2.TLabel', background='green')
style.configure('TestLabel3.TLabel', background='blue')
style.configure('Buttons.TButton')
output_path = tk.StringVar()
output_path.set('test')
settings = Frame(root, width=500, height=200)
settings.pack_propagate(0)
settings.pack(side='top')
chart_preset_frame = LabelFrame(settings, text='Chart Parameter Preset', padding=(5, 5, 5, 5))
chart_preset_frame.pack(expand=True, fill='x', pady=10, side='top')
chart_preset_frame.columnconfigure(0, weight=6)
chart_preset_frame.columnconfigure(1, weight=2)
chart_preset_frame.columnconfigure(2, weight=2)
output_path_input = Entry(chart_preset_frame, textvariable=output_path, width=20)
output_path_input.grid(row=0, column=0, columnspan=3, sticky='EW', ipady=5)
output_load_btn = Button(chart_preset_frame, text='Load...', style='Buttons.TButton', command=None)
output_load_btn.grid(row=1, column=1, sticky='EW', padx=0, pady=5)
output_save_btn = Button(chart_preset_frame, text='Save As...', style='Buttons.TButton', command=None)
output_save_btn.grid(row=1, column=2, sticky='EW', padx=0, pady=5)
# for label test
# label_test_1 = Label(chart_preset_frame, text='test', style='TestLabel1.TLabel')
# label_test_1.grid(row=1, column=0, sticky='EW')
# label_test_2 = Label(chart_preset_frame, text='test', style='TestLabel2.TLabel')
# label_test_2.grid(row=1, column=1, sticky='EW')
# label_test_3 = Label(chart_preset_frame, text='test', style='TestLabel3.TLabel')
# label_test_3.grid(row=1, column=2, sticky='EW')
root.mainloop()
weight is just a guideline to the layout manager how to distribute available spaces. Since there is no widget in cell (row 1, column 0), it may not get the required space.
It can be enforced by adding uniform=1 to those columnconfigur(...):
chart_preset_frame.columnconfigure(0, weight=6, uniform=1)
chart_preset_frame.columnconfigure(1, weight=2, uniform=1)
chart_preset_frame.columnconfigure(2, weight=2, uniform=1)
Result:
there are some space between the result as you can see in the image that password entry and generate password aren't aligning together
*Result image
from tkinter import
window = Tk()
window.title("Password Manager")
window.config(padx=20, pady=20)
canvas = Canvas(width=200, height=200, highlightthickness=0)
password_image = PhotoImage(file="logo.png")
image = canvas.create_image(100, 100, image=password_image)
canvas.itemconfig(image)
canvas.grid(row=0, column=1)
website_label = Label(text="Website")
website_label.grid(row=1, column=0)
Email_username_label = Label(text="Email/Username")
Email_username_label.grid(row=2, column=0)
password_label = Label(text="Password")
password_label.grid(row=3, column=0)
website_input = Entry(width=35)
website_input.grid(row=1, column=1, columnspan=2)
Email_username_input = Entry(width=35)
Email_username_input.grid(row=2,column=1, columnspan=2)
password = Entry(width=21)
password.grid(row=3, column=1)
generate_button = Button(text="Generate Password")
generate_button.grid(row=3, column=2)
add_password_button = Button(text="Add", width=36)
add_password_button.grid(row=4, column=1, columnspan=2)
window.mainloop()
You can see that there is some space in password entry and generate password how to fix it
As noted in the comments, using the grid method allows you to just add sticky to align elements. In this case, I've removed all the width options in your entries and buttons with stick='EW' to expand East and West, or to the maximum left and right of the column the widget is in.
from tkinter import *
window = Tk()
window.title("Password Manager")
window.config(padx=20, pady=20)
# Canvas
canvas = Canvas(width=200, height=200, highlightthickness=0)
password_image = PhotoImage(file="logo.png")
image = canvas.create_image(100, 100, image=password_image)
canvas.itemconfig(image)
canvas.grid(row=0, column=1)
# Labels
website_label = Label(text="Website")
website_label.grid(row=1, column=0)
Email_username_label = Label(text="Email/Username")
Email_username_label.grid(row=2, column=0)
password_label = Label(text="Password")
password_label.grid(row=3, column=0)
# Entries
website_input = Entry()
website_input.grid(row=1, column=1, columnspan=2, sticky='EW') # sticky
Email_username_input = Entry()
Email_username_input.grid(row=2, column=1, columnspan=2, sticky='EW') # sticky
password = Entry()
password.grid(row=3, column=1, sticky='EW') # sticky
# Buttons
generate_button = Button(text="Generate Password")
generate_button.grid(row=3, column=2)
add_password_button = Button(text="Add")
add_password_button.grid(row=4, column=1, columnspan=2, sticky='EW') # sticky
window.mainloop()
You may also want to consider reading up on column and row weights using columnconfigure and rowconfigure if you want your GUI to resize dynamically.
l have to develop an interactive program which lets its users select from
several ranked HTML lists and using widgets to pick out certain HTML code to display the current 2nd position in each lists. Each widget is too show a differnet list from a different HTML website each time. I have set up all my widgets and my GUI but I am unsure on how to complete this task of each widget pulling HTML code and displaying it in a window.
The main things I am having problems with are, pulling HTML code from a live website and displaying this using my radiobutton widgets. Hopefully someone can point me in the right direction.
Here is the code that I have completed so far
root = Tk()
root.title("Runners Up")
root.config(background = "#f0f0f0")
test_status0 = BooleanVar()
test_status1 = BooleanVar()
test_status2 = BooleanVar()
test_status3 = BooleanVar()
test_status4 = BooleanVar()
#Label Frame for Radio Buttons
radiobuttonsframe = LabelFrame(root, relief = 'groove', font = 'Arial',
borderwidth = 5)
radiobuttonsframe.grid(row=0, column=1, padx=10, pady=2)
#Picture Label Frame
PicFrame = LabelFrame(root, relief = 'groove', borderwidth = 5)
PicFrame.grid(row=0, column=0, padx=10, pady=2)
#Display Frame (Runner Up)
RunnerFrame = LabelFrame(root, relief = 'groove', borderwidth = 5, font = 'Arial',
text = 'Runner Up')
RunnerFrame.grid(row=1, column=0, padx=10, pady=2)
#Display Frame (Full List)
ListFrame = LabelFrame(root, relief = 'groove', borderwidth = 5, font = 'Arial',
text = 'Full List')
ListFrame.grid(row=1, column=1, padx=10, pady=2)
#Importing Photo
Picture1 = PhotoImage(file="Secondplace.gif")
Label(PicFrame, image=Picture1).grid(row=0, column=0, padx=10, pady=2)
#Frames for each widget
btnFrame = LabelFrame(radiobuttonsframe, relief = 'groove',
font = 'Arial', borderwidth = 2, text = 'Current Runner Ups', background="#f0f0f0")
btnFrame.grid(row=1, column=0, padx=10, pady=2)
btnFramePrev = LabelFrame(radiobuttonsframe, relief = 'groove',
font = 'Arial', borderwidth = 2, text = 'Previous Runner Ups', background="#f0f0f0")
btnFramePrev.grid(row=2, column=0, padx=10, pady=50)
updaterBtn = LabelFrame(radiobuttonsframe, relief = 'groove',
font = 'Arial', borderwidth = 2, background="#f0f0f0")
updaterBtn.grid(row=3, column=0, padx=10, pady=2)
#Button Music Runner ups
MusicButton = Radiobutton(btnFrame, text="Top Album Charts [Title and Artist]",
height=2, width=50, value = test_status1, command = test1)
MusicButton.grid(row=0, column=0, padx=10, pady=2)
#Button for Movie Runner ups
MovieButton = Radiobutton(btnFrame, text="Movie Charts [Title and Production]",
height=2, width=50, value = test_status2, command = test1)
MovieButton.grid(row=1, column=0, padx=10, pady=2)
#Button for games runner ups
GamesButton = Radiobutton(btnFrame, text="Game Charts [Title and Players]",
height=2, width=50, value = test_status3, command = test1)
GamesButton.grid(row=2, column=0, padx=10, pady=2)
#Button for Medal runner ups
MedalButton = Radiobutton(btnFramePrev, text="Medal 2001 [Name and Votes]",
height=2, width=50, value = test_status4, command = test1)
MedalButton.grid(row=3, column=0, padx=10, pady=2)
#Scroll Bar for full list of winners
ListScroll = ScrolledText(ListFrame, width=40, height=10)
ListScroll.grid(row=0, column=0, padx=10, pady=2)
#Text Box for our main Runners Up
RunnersText = Text(RunnerFrame, width=50, height=10)
RunnersText.grid(row=0, column=0, padx=10, pady=2)
#Update and Show Source Buttons
Update = Button(updaterBtn, text="Update", height=2, width=10)
Update.grid(row=0, column=0, padx=10, pady=2)
ShowSource = Button(updaterBtn, text="Show Source", height=2, width=10)
ShowSource.grid(row=0, column=1, padx=10, pady=2)
root.mainloop()
\EDIT//
I've figured out to run the buttons but now I am having trouble actually getting the HTML text to display in my text box.
Here is my attempt at trying that:
def MusicRunner():
RunnersText.delete(0.0, END)
site = 'Official Charts'
feed_web = download('https://www.officialcharts.com/charts/singles-chart/')
items = findall(r'<body class="sticky-nav" style \b[^>]*>(.*?)<\/body>', feed_web, flags=MULTILINE|DOTALL)
num = findall(r'<span class= "position">"2"</span>',feed_web, flags=MULTILINE|DOTALL)
RunnersText.insert(INSERT, num)
The text is "This is too long text".
As you can see the view provides an option to expand horizontally but there is not indication that there are more characters.
I need some indication for the user that there are more characters in the cell.
i.e showing "...".
This is the code:
from tkinter import ttk
import tkinter as tk
win = tk.Tk()
win.resizable(width=0, height=0)
tree = ttk.Treeview(win, selectmode='browse')
tree.grid(row=0, column=0)
vsb = ttk.Scrollbar(win, orient="horizontal", command=tree.xview)
vsb.grid(row=1, column=0, sticky=tk.W + tk.E + tk.N + tk.S)
tree.configure(xscrollcommand=vsb.set)
vsb = ttk.Scrollbar(win, orient="vertical", command=tree.yview)
vsb.grid(row=0, column=1, sticky=tk.W + tk.E + tk.N + tk.S)
tree.configure(yscrollcommand=vsb.set)
tree["columns"] = ("1", "2")
tree['show'] = 'headings'
tree.column("1", anchor='c')
tree.column("2", width=100, anchor='c')
tree.heading("1", text="Col 1")
tree.heading("2", text="Col 2")
tree.insert("", 'end', text="L4", values=("This text is too long","Short text"))
win.mainloop()
Update:
Turns out we can bind '<ButtonRelease-1>' to the treeview as noted on this post: how-to-detect-resizing-of-ttk-treeview-column that #stovfl has pointed out in the comments. So I have updated my answer with less overhead :D.
I created a method that will check to see of the column width has changed and then if it has then calculate each row to see if we need to add ... to the end.
This is accomplished with ImageFont from PIL thought for some reason there seams to be a size difference between Treeview font and PIL font. After some testing it appears that any font size you set in the style for the Treeview just add 5 to the PIL font and it should calculate correctly.
import tkinter as tk
import tkinter.ttk as ttk
from PIL import ImageFont
track_data = [[('This text is too long', 'Short text'), 'This text is too long'],
[('This text is toooooooo long', 'Short text'), 'This text is toooooooo long'],
[('This text is longer than most others', 'Short text'), 'This text is longer than most others'],
[('This text is short', 'Short text'), 'This text is short']]
def add_to_tree_list(long_text, short_text, top):
track_data.append([(long_text.get(), short_text.get()), long_text.get()])
top.destroy()
update_text()
def pop_list(ndex):
track_data.pop(ndex)
def remove_row_from_list():
top = tk.Toplevel(win)
build_top_frame(top)
update_text()
def build_top_frame(top):
row_button_list = []
for child in top.winfo_children():
child.destroy()
frame = tk.Frame(top)
frame.pack()
for ndex, sub_list in enumerate(track_data):
row_button_list.append([tk.Button(frame, text='Remove',
command=lambda n=ndex: (pop_list(n), update_text(), build_top_frame(top))),
tk.Label(frame, text='Row {}: {}'.format(ndex + 1, sub_list[1]))])
row_button_list[-1][0].grid(row=ndex, column=0)
row_button_list[-1][1].grid(row=ndex, column=1, sticky='w')
def top_for_new_row():
top = tk.Toplevel(win)
tk.Label(top, text='Add long text: ').grid(row=0, column=0)
tk.Label(top, text='Add short text: ').grid(row=1, column=0)
e1 = tk.Entry(top)
e2 = tk.Entry(top)
e1.grid(row=0, column=1)
e2.grid(row=1, column=1)
tk.Button(top, text='Submit', command=lambda: add_to_tree_list(e1, e2, top)).grid(row=2, column=0)
tk.Button(top, text='Cancel', command=top.destroy).grid(row=2, column=1)
def clear_and_load(data):
tree.delete(*tree.get_children())
for sub_list in data:
tree.insert('''''', 'end', text='L4', values=sub_list[0])
def update_text(_=None):
global old_col_width, old_track_data_len
col_width = tree.column('1')['width']
if col_width != old_col_width or old_track_data_len != len(track_data):
old_col_width = col_width
new_track_data = []
for text in track_data:
font = ImageFont.truetype("arial.ttf", 17)
size = font.getsize(text[0][0])
previous_long_text = ''
new_long_text = ''
if size[0] > col_width:
for char in text[0][0]:
new_long_text = '{}{}'.format(new_long_text, char)
new_size = font.getsize('{}{}'.format(new_long_text, '...'))[0]
if new_size < col_width:
previous_long_text = new_long_text
else:
new_track_data.append([('{}{}'.format(previous_long_text, '...'), text[0][1]), ''])
break
else:
new_track_data.append(text)
clear_and_load(new_track_data)
old_track_data_len = len(track_data)
win = tk.Tk()
win.columnconfigure(0, weight=1)
old_col_width = 200
old_track_data_len = 0
win.resizable(width=0, height=0)
style = ttk.Style()
style.configure('Treeview', font=('arial', 12))
tree = ttk.Treeview(win)
tree.grid(row=0, column=0)
tree.bind('<ButtonRelease-1>', update_text)
vsb = ttk.Scrollbar(win, orient='horizontal', command=tree.xview)
vsb.grid(row=1, column=0, sticky='nsew')
tree.configure(xscrollcommand=vsb.set)
vsb = ttk.Scrollbar(win, orient='vertical', command=tree.yview)
vsb.grid(row=0, column=1, sticky='nsew')
tree.configure(yscrollcommand=vsb.set)
btn_frame = tk.Frame(win)
btn_frame.grid(row=2, column=0, columnspan=2, sticky='ew')
btn_frame.columnconfigure(0, weight=1)
btn_frame.columnconfigure(1, weight=1)
tk.Button(btn_frame, text='Add Row!', command=top_for_new_row).grid(row=0, column=0, sticky='ew')
tk.Button(btn_frame, text='Remove Row!', command=remove_row_from_list).grid(row=0, column=1, sticky='ew')
columns = ('1', '2')
tree['columns'] = columns
tree['show'] = 'headings'
tree.column('1', width=200, stretch=True, anchor='w')
tree.column('2', width=100, anchor='w')
tree.heading('1', text='Col 1')
tree.heading('2', text='Col 2')
clear_and_load(track_data)
update_text()
win.mainloop()
Results:
Adding new line:
Removing lines:
Dear StackOverflow community,
I am trying to get my head around programming with Python and I am having a hard time with the grid layout manager. I have been trying to find the answer myself and tried various options, but I just can't get my UI to look how I want it to.
I hope that you can help me. Unfortunately, I cannot post pictures because I am new here. But basically I wanted all the coloured buttons on the left hand side EVENLY spaced on top each other, in column 1. Then the Labels in column 2 and the text areas in column 3.
I also wanted to create a border at the bottom with the close button underneath, but this doesn't even show up at all.
Please could you give me some hints as to what I am doing wrong?
import Tkinter
from Tkinter import *
from ttk import Frame, Button, Style
class KarateSyllabus(Frame):
"""A program that displays karate grading syllabi"""
#define the constructor
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
#define the GUI
def initUI(self):
#define the basic parameters of the window
self.parent.title("Karate Syllabus")
self.style = Style()
self.style.theme_use("default")
#self.parent.geometry("500x500")
self.parent.config(background = "black")
self.parent.wm_iconbitmap("favicon.ico")
self.grid()
#create the buttons for the syllabus
button1 = Tkinter.Button(self, text = "White Belt", bg = "white", height=1, width =10).grid(row=0, column=0, pady=4, padx=10, sticky=N)
button2 = Tkinter.Button(self, text = "Red Belt", bg="red", height=1, width =10).grid(row=1,column=0, pady=4, padx=10, sticky=N )
button3 = Tkinter.Button(self, text = "Orange Belt",bg="orange", height=1, width =10).grid(row=2,column=0, pady=4, padx=10, sticky=N)
button4 = Tkinter.Button(self, text = "Yellow Belt",bg="yellow", height=1, width =10).grid(row=3, column=0, pady=4, padx=10, sticky=N)
button5 = Tkinter.Button(self, text = "Green Belt", bg="green", height=1, width =10).grid(row=4, column=0, pady=4, padx=10, sticky=N)
button6 = Tkinter.Button(self, text = "Purple Belt",bg="purple", height=1, width =10).grid(row=5, column=0, pady=4, padx=10, sticky=N)
button7 = Tkinter.Button(self, text = "Brown Belt", bg="brown", height=1, width =10).grid(row=6, column=0, pady=4, padx=10, sticky=N)
button8 = Tkinter.Button(self, text = "Black Belt", bg="black", foreground="white", height=1, width =10).grid(row=7, column=0, pady=2, padx=10, sticky=N)
#create the three text areas to display the text and according labels
BasicsLabel = Label(self, text="Basics:").grid(row =0, column =2)
BasicTextArea = Text(self, width=50, height=6, takefocus=0)
BasicTextArea.grid(row=0, column=3, padx=10, pady=2)
BasicTextArea.config(font =("Arial",10), bg="grey", wrap = WORD)
KataLabel = Label(self, text="Kata:").grid(row =2, column =2)
KataTextArea = Text(self, width=50, height=6, takefocus=0)
KataTextArea.grid(row=2, column=3, padx=30, pady=2)
KataTextArea.config(font =("Arial",10), bg="grey")
KumiteLabel = Label(self, text="Kumite:").grid(row =3, column =2)
KumiteTextArea = Text(self, width=50, height=6, takefocus=0)
KumiteTextArea.grid(row=3, column=3, padx=10, pady=2)
KumiteTextArea.config(font =("Arial",10), bg="grey")
#create the second frame for the bottom with the close button
frame = Frame(self, relief=RAISED, borderwidth=1)
frame.grid(row=8, column= 1)
closeButton = Button(self, text="Exit")
closeButton.grid(row = 8, column = 3)
def main():
root = Tk()
app = KarateSyllabus(root)
root.mainloop()
if __name__ == '__main__':
main()
It sounds like you don't need to be using grid, since you aren't creating a grid. It sounds like you want each column to be evenly spaced vertically, which precludes a grid-like layout.
You're creating three columns, so I would start with packing a frame along the bottom for your quit button, and then three vertical frames, packed left-to-right, all in the main window.
Next, pack the color buttons in the left-most frame, top to bottom. With the right options they will be evenly spaced (though you could also use grid if you want).
Finally, use the exact same technique for the other two columns - pack everything top-to-bottom, having each one expand to fill the area they are allotted.
You should use at least a Frame to group all the left buttons and another one for the Exit button, as in the following code:
import Tkinter
from ttk import Frame, Button, Style
class KarateSyllabus(Frame):
"""A program that displays karate grading syllabi"""
#define the constructor
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
#define the GUI
def initUI(self):
#define the basic parameters of the window
self.parent.title("Karate Syllabus")
self.style = Style()
self.style.theme_use("default")
#self.parent.geometry("500x500")
self.parent.config(background = "black")
self.parent.wm_iconbitmap("favicon.ico")
self.grid(sticky=Tkinter.NSEW)
button_panel = Frame(self)
#create the buttons for the syllabus
button1 = Tkinter.Button(button_panel, text="White Belt", bg="white", height=1, width =10).grid(row=0, column=0, pady=4, padx=10, sticky=Tkinter.N)
button2 = Tkinter.Button(button_panel, text="Red Belt", bg="red", height=1, width =10).grid(row=1, column=0, pady=4, padx=10, sticky=Tkinter.N)
button3 = Tkinter.Button(button_panel, text="Orange Belt", bg="orange", height=1, width =10).grid(row=2, column=0, pady=4, padx=10, sticky=Tkinter.N)
button4 = Tkinter.Button(button_panel, text="Yellow Belt", bg="yellow", height=1, width =10).grid(row=3, column=0, pady=4, padx=10, sticky=Tkinter.N)
button5 = Tkinter.Button(button_panel, text="Green Belt", bg="green", height=1, width =10).grid(row=4, column=0, pady=4, padx=10, sticky=Tkinter.N)
button6 = Tkinter.Button(button_panel, text="Purple Belt", bg="purple", height=1, width =10).grid(row=5, column=0, pady=4, padx=10, sticky=Tkinter.N)
button7 = Tkinter.Button(button_panel, text="Brown Belt", bg="brown", height=1, width =10).grid(row=6, column=0, pady=4, padx=10, sticky=Tkinter.N)
button8 = Tkinter.Button(button_panel, text="Black Belt", bg="black", height=1, width =10, foreground="white").grid(row=7, column=0, pady=2, padx=10, sticky=Tkinter.N)
button_panel.grid(row=0, column=0, rowspan=3, sticky=Tkinter.N)
#create the three text areas to display the text and according labels
BasicsLabel = Tkinter.Label(self, text="Basics:").grid(row=0, column=1, sticky=Tkinter.N)
BasicTextArea = Tkinter.Text(self, width=50, height=6, takefocus=0)
BasicTextArea.grid(row=0, column=2, padx=10, pady=2, sticky=Tkinter.NSEW)
BasicTextArea.config(font=("Arial",10), bg="grey", wrap=Tkinter.WORD)
KataLabel = Tkinter.Label(self, text="Kata:").grid(row=1, column=1, sticky=Tkinter.N)
KataTextArea = Tkinter.Text(self, width=50, height=6, takefocus=0)
KataTextArea.grid(row=1, column=2, padx=10, pady=2, sticky=Tkinter.NSEW)
KataTextArea.config(font =("Arial",10), bg="grey")
KumiteLabel = Tkinter.Label(self, text="Kumite:").grid(row=2, column=1, sticky=Tkinter.N)
KumiteTextArea = Tkinter.Text(self, width=50, height=6, takefocus=0)
KumiteTextArea.grid(row=2, column=2, padx=10, pady=2, sticky=Tkinter.NSEW)
KumiteTextArea.config(font=("Arial",10), bg="grey")
#create the second frame for the bottom with the close button
close_frame = Tkinter.Frame(self, relief=Tkinter.RAISED, borderwidth=2)
close_frame.grid(row=3, column=0, columnspan=3, sticky=Tkinter.EW)
close_frame.columnconfigure(0, weight=1)
closeButton = Tkinter.Button(close_frame, text="Exit", command=self.quit)
# Move 'Exit' to the right. Comment out next line to leave it centered.
closeButton.grid(sticky=Tkinter.E)
self.rowconfigure(0, weight=1)
self.rowconfigure(1, weight=1)
self.rowconfigure(2, weight=1)
# Leave row 3 (close_frame) non-expandable.
# Leave columns 1 and 2 (button_panel and labels) non-expandable.
self.columnconfigure(2, weight=1)
self.parent.rowconfigure(0, weight=1)
self.parent.columnconfigure(0, weight=1)
def main():
root = Tkinter.Tk()
app = KarateSyllabus(root)
root.mainloop()
if __name__ == '__main__':
main()