Reputation: 3
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.
Upvotes: 0
Views: 62
Reputation: 6810
Here'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()
Upvotes: 0