user29255210
user29255210

Reputation: 3

Need to align the boxes horizontally and vertically in python tkinter

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.

Upvotes: 0

Views: 62

Answers (1)

JRiggles
JRiggles

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 Frames for each effective "row" of widgets (i.e., any widgets that need to appear next to each other), then I've packed those widgets to the 'left' or 'right' accordingly.

The bulk of the layout code is just focused on how widgets fill their respective Frames 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

Related Questions