How it looks right now
Can someone help me align the boxes horizontally and vertically? In the image, the message entry box and the other 4 boxes are out of align. The message entry box should be the same length as frame1 and frame2. And the boxes inside the frames have different lengths. They should be the same length and aligned with the red lines. For example, it should look like this image: How I want it to look
This is the exact code I have:
import tkinter as tk
from tkinter import ttk, filedialog
from PIL import Image, ImageTk
import sys
import os
root = tk.Tk(className="Chat APP")
root.title("Chat APP")
# Maximize the window
root.attributes('-zoomed', True)
# Get the screen width and height
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
new_note_icon = Image.open("new_note.jpg")
new_note_icon = new_note_icon.resize((25, 25))
new_note_icon = ImageTk.PhotoImage(new_note_icon)
# Proportional calculations
def proportion_width(p):
return int(screen_width * p)
def proportion_height(p):
return int(screen_height * p)
chat_frame = tk.Frame(root, bg='white')
chat_frame.pack(expand=True, fill=tk.BOTH)
chat_frame.grid_rowconfigure(0, weight=0)
chat_frame.grid_rowconfigure(1, weight=1)
chat_frame.grid_columnconfigure(0, weight=1)
chat_log = tk.Text(chat_frame, state='disabled', wrap='word', width=70, height=15,
font=('Helvetica', 14), bg="white", fg="black", highlightthickness=0, borderwidth=0)
chat_log.grid(row=1, column=0, sticky='NESW', padx=proportion_width(0.275), pady=proportion_height(0.01))
# Create a scrollbar for the chat log
scrollbar = tk.Scrollbar(chat_frame, command=chat_log.yview)
scrollbar.grid(row=1, column=1, sticky='NS')
chat_log['yscrollcommand'] = scrollbar.set
frame1 = tk.Frame(root, bg="white")
frame1.pack(side=tk.TOP, pady=(proportion_height(0.1), 1))
frame2 = tk.Frame(root, bg="white")
frame2.pack(side=tk.TOP, pady=(proportion_height(0.005), proportion_height(0.02)))
print("Width is",chat_frame.winfo_width())
chat_with_pdf_button = ttk.Button(frame1, width=proportion_width(0.02), text="Chat with PDF", style="def2.TButton",)
chat_with_pdf_button.pack(side=tk.LEFT, padx=(proportion_width(0.0843),0), ipady=proportion_height(0.01))
# Create a button to trigger the summarization process
summarize_button = ttk.Button(frame1, width=proportion_width(0.02), text="Chat with a YouTube video", style="def2.TButton")
summarize_button.pack(side=tk.LEFT, padx=(proportion_height(0.01), 0), ipady=proportion_height(0.01))
letter_button = ttk.Button(frame2, width=proportion_width(0.02), text="Write a letter", style="def2.TButton")
letter_button.pack(side=tk.LEFT, padx=(proportion_width(0.0843),0), ipady=proportion_height(0.01))
blog_button = ttk.Button(frame2, width=proportion_width(0.02), text="Chat with a Blog Post", style="def2.TButton")
blog_button.pack(side=tk.LEFT, padx=(proportion_height(0.01), 0), ipady=proportion_height(0.01))
new_note_button = ttk.Button(chat_frame, style="Toggle.TButton", image=new_note_icon)
new_note_button.grid(row=0, column=0, sticky='W', padx=(proportion_width(0.272), 0), pady=(proportion_height(0.01), 0))
# Frame to contain message_entry and buttons
frame_for_widgets = tk.Frame(root, bg="white")
frame_for_widgets.pack(side=tk.BOTTOM)
empty_space = tk.Text(
frame_for_widgets, # Use frame2 as the parent widget
width=proportion_width(0.001), # Adjusting padx proportionally
bg="white",
borderwidth=0,
# Removing fixed width and height, so it expands with the frame
height=proportion_width(0.000001),
# Set a fixed height if needed
spacing1=proportion_height(0.02), # Adjust spacing1 proportionally
spacing3=proportion_height(0.02), # Adjust spacing3 proportionally
font=('Helvetica', 14)
)
message_entry = tk.Text(
frame_for_widgets, # Use frame2 as the parent widget
width=proportion_width(0.0495), # Adjusting padx proportionally
bg="white",
insertbackground='white',
fg="white",
borderwidth=0,
# Removing fixed width and height, so it expands with the frame
height=proportion_width(0.000001),
# Set a fixed height if needed
spacing1=proportion_height(0.02), # Adjust spacing1 proportionally
spacing3=proportion_height(0.02), # Adjust spacing3 proportionally
font=('Helvetica', 14)
)
# Pack message_entry into frame2
message_entry.pack(
side=tk.LEFT,
padx=(proportion_width(0.208),0),
#fill=tk.X, # Fill horizontally
pady=(0, proportion_height(0.02))
#padx=(0),
# Adjusting padx proportionally
# Adjusting pady proportionally
)
message_entry.mark_set("insert", "%d.%d" % (0,0))
send_icon = Image.open("send_icon.png")
send_icon = send_icon.resize((55, 55))
send_icon = ImageTk.PhotoImage(send_icon)
# Send button
send_button = ttk.Button(frame_for_widgets, image=send_icon, style="Send.TButton")
send_button.image = send_icon
send_button.pack(side=tk.LEFT, pady=(0, proportion_height(0.02)), padx=(1,0),)
message_entry.focus_set()
root.mainloop()
The problem is that these alignments look different for different screen sizes. It should be aligned for all screen sizes; regardless of the screen size of computer.
How it looks right now
Can someone help me align the boxes horizontally and vertically? In the image, the message entry box and the other 4 boxes are out of align. The message entry box should be the same length as frame1 and frame2. And the boxes inside the frames have different lengths. They should be the same length and aligned with the red lines. For example, it should look like this image: How I want it to look
This is the exact code I have:
import tkinter as tk
from tkinter import ttk, filedialog
from PIL import Image, ImageTk
import sys
import os
root = tk.Tk(className="Chat APP")
root.title("Chat APP")
# Maximize the window
root.attributes('-zoomed', True)
# Get the screen width and height
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
new_note_icon = Image.open("new_note.jpg")
new_note_icon = new_note_icon.resize((25, 25))
new_note_icon = ImageTk.PhotoImage(new_note_icon)
# Proportional calculations
def proportion_width(p):
return int(screen_width * p)
def proportion_height(p):
return int(screen_height * p)
chat_frame = tk.Frame(root, bg='white')
chat_frame.pack(expand=True, fill=tk.BOTH)
chat_frame.grid_rowconfigure(0, weight=0)
chat_frame.grid_rowconfigure(1, weight=1)
chat_frame.grid_columnconfigure(0, weight=1)
chat_log = tk.Text(chat_frame, state='disabled', wrap='word', width=70, height=15,
font=('Helvetica', 14), bg="white", fg="black", highlightthickness=0, borderwidth=0)
chat_log.grid(row=1, column=0, sticky='NESW', padx=proportion_width(0.275), pady=proportion_height(0.01))
# Create a scrollbar for the chat log
scrollbar = tk.Scrollbar(chat_frame, command=chat_log.yview)
scrollbar.grid(row=1, column=1, sticky='NS')
chat_log['yscrollcommand'] = scrollbar.set
frame1 = tk.Frame(root, bg="white")
frame1.pack(side=tk.TOP, pady=(proportion_height(0.1), 1))
frame2 = tk.Frame(root, bg="white")
frame2.pack(side=tk.TOP, pady=(proportion_height(0.005), proportion_height(0.02)))
print("Width is",chat_frame.winfo_width())
chat_with_pdf_button = ttk.Button(frame1, width=proportion_width(0.02), text="Chat with PDF", style="def2.TButton",)
chat_with_pdf_button.pack(side=tk.LEFT, padx=(proportion_width(0.0843),0), ipady=proportion_height(0.01))
# Create a button to trigger the summarization process
summarize_button = ttk.Button(frame1, width=proportion_width(0.02), text="Chat with a YouTube video", style="def2.TButton")
summarize_button.pack(side=tk.LEFT, padx=(proportion_height(0.01), 0), ipady=proportion_height(0.01))
letter_button = ttk.Button(frame2, width=proportion_width(0.02), text="Write a letter", style="def2.TButton")
letter_button.pack(side=tk.LEFT, padx=(proportion_width(0.0843),0), ipady=proportion_height(0.01))
blog_button = ttk.Button(frame2, width=proportion_width(0.02), text="Chat with a Blog Post", style="def2.TButton")
blog_button.pack(side=tk.LEFT, padx=(proportion_height(0.01), 0), ipady=proportion_height(0.01))
new_note_button = ttk.Button(chat_frame, style="Toggle.TButton", image=new_note_icon)
new_note_button.grid(row=0, column=0, sticky='W', padx=(proportion_width(0.272), 0), pady=(proportion_height(0.01), 0))
# Frame to contain message_entry and buttons
frame_for_widgets = tk.Frame(root, bg="white")
frame_for_widgets.pack(side=tk.BOTTOM)
empty_space = tk.Text(
frame_for_widgets, # Use frame2 as the parent widget
width=proportion_width(0.001), # Adjusting padx proportionally
bg="white",
borderwidth=0,
# Removing fixed width and height, so it expands with the frame
height=proportion_width(0.000001),
# Set a fixed height if needed
spacing1=proportion_height(0.02), # Adjust spacing1 proportionally
spacing3=proportion_height(0.02), # Adjust spacing3 proportionally
font=('Helvetica', 14)
)
message_entry = tk.Text(
frame_for_widgets, # Use frame2 as the parent widget
width=proportion_width(0.0495), # Adjusting padx proportionally
bg="white",
insertbackground='white',
fg="white",
borderwidth=0,
# Removing fixed width and height, so it expands with the frame
height=proportion_width(0.000001),
# Set a fixed height if needed
spacing1=proportion_height(0.02), # Adjust spacing1 proportionally
spacing3=proportion_height(0.02), # Adjust spacing3 proportionally
font=('Helvetica', 14)
)
# Pack message_entry into frame2
message_entry.pack(
side=tk.LEFT,
padx=(proportion_width(0.208),0),
#fill=tk.X, # Fill horizontally
pady=(0, proportion_height(0.02))
#padx=(0),
# Adjusting padx proportionally
# Adjusting pady proportionally
)
message_entry.mark_set("insert", "%d.%d" % (0,0))
send_icon = Image.open("send_icon.png")
send_icon = send_icon.resize((55, 55))
send_icon = ImageTk.PhotoImage(send_icon)
# Send button
send_button = ttk.Button(frame_for_widgets, image=send_icon, style="Send.TButton")
send_button.image = send_icon
send_button.pack(side=tk.LEFT, pady=(0, proportion_height(0.02)), padx=(1,0),)
message_entry.focus_set()
root.mainloop()
The problem is that these alignments look different for different screen sizes. It should be aligned for all screen sizes; regardless of the screen size of computer.
Share Improve this question edited 2 days ago user29255210 asked 2 days ago user29255210user29255210 12 bronze badges 4- Please trim your code to make it easier to find your problem. Follow these guidelines to create a minimal reproducible example. – siruku6 Commented 2 days ago
- I've actually trimmed a lot of code and this is the code after trimming. – user29255210 Commented 2 days ago
- You could improve thingsd as a starter by setting all the numeric scale values as constants at the beginning of the source code. You can then easily adjust them to see what effect it has on the display. And while doing this you need to check that the values are all correct in terms of their relation to each other. – OldBoy Commented 2 days ago
- I’ve been trying to do that honestly. I’ve posted this on stackoverflow because I’m helpless. – user29255210 Commented 2 days ago
1 Answer
Reset to default 0Here's a very pared down example - most of the "functional" parts have been removed in order to focus on the layout.
You can achieve this result with grid
, like you've tried, but I find pack
to be more flexible in general so that's what I've used here.
The core idea is this: I've created container Frame
s for each effective "row" of widgets (i.e., any widgets that need to appear next to each other), then I've pack
ed those widgets to the 'left'
or 'right'
accordingly.
The bulk of the layout code is just focused on how widgets fill their respective Frame
s and how they're padded.
import tkinter as tk
from tkinter import ttk
class ChatApp(tk.Tk):
def __init__(self) -> None:
super().__init__()
self.geometry('800x600')
self.title('Chat App')
# create a frame for the main chat
self.chat_frame = ttk.Frame(self)
self.chat_frame.pack(expand=True, fill='both', padx=10, pady=10)
self.chat_log = tk.Text(self.chat_frame)
self.chat_log.pack(expand=True, fill='both', pady=4, side='left')
self.scrollbar = ttk.Scrollbar(
self.chat_frame,
command=self.chat_log.yview,
)
self.scrollbar.pack(fill='y', pady=4, side='right')
self.chat_log.config(yscrollcommand=self.scrollbar.set)
# create a Frame to contain each row of widgets
self.btns_row1 = ttk.Frame(self)
self.btns_row1.pack(fill='x', padx=8, side='bottom')
self.btns_row2 = ttk.Frame(self)
self.btns_row2.pack(
before=self.btns_row1,
fill='x',
padx=8,
side='bottom',
)
self.entry_row = ttk.Frame(self)
self.entry_row.pack(
before=self.btns_row2,
fill='x',
padx=8,
side='bottom',
)
# create the buttons
kwargs = { # common packing arguments for all widgets below
'expand': True,
'fill': 'x',
'padx': 2,
'pady': (0, 4),
}
self.btn_chat_pdf = ttk.Button(
self.btns_row1,
text='Chat with PDF',
width=50,
)
self.btn_chat_pdf.pack(side='left', **kwargs)
self.btn_chat_yt = ttk.Button(
self.btns_row1,
text='Chat with a YouTube Video',
width=50,
)
self.btn_chat_yt.pack(side='right', **kwargs)
self.btn_chat_letter = ttk.Button(
self.btns_row2,
text='Write a letter',
width=50,
)
self.btn_chat_letter.pack(side='left', **kwargs)
self.btn_chat_blog = ttk.Button(
self.btns_row2,
text='Chat with a Blog Post',
width=50,
)
self.btn_chat_blog.pack(side='right', **kwargs)
# create the entry and the send button
self.chat_entry = ttk.Entry(self.entry_row)
self.chat_entry.pack(side='left', **kwargs)
self.btn_send = ttk.Button(self.entry_row, text='>')
self.btn_send.pack(side='right', **kwargs)
self.btn_send.pack_configure(expand=False)
if __name__ == '__main__':
app = ChatApp()
app.mainloop()