How ot center my form horizontaly?

Hi,

I tried everything, but I can’t center the form horizontally, do you have an idea please?

It is always center a left like you can see on picture.

Thanks in advance for your help.

This is a part of my code :

  import tkinter as tk
from tkinter import messagebox
from tkinter import ttk
from PIL import Image, ImageTk
import sqlite3
import datetime
import time

# Fonction pour se connecter à la base de données SQLite
def connect_to_database():
    try:
        conn = sqlite3.connect('C:/Users/David/projet_python/dist/manipulations.db')
        return conn
    except sqlite3.Error as e:
        messagebox.showerror("Erreur", f"Erreur lors de la connexion à la base de données: {e}")
        raise

# Fonction pour récupérer les utilisateurs de la base de données
def get_users():
    conn = connect_to_database()
    if conn is not None:
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM users")
        users = cursor.fetchall()
        conn.close()
        return users
    else:
        return []

# Fonction pour masquer tous les cadres sauf celui de la section "After finalizing the analysis"
def show_finalizing_section():
    for widget in scrollable_frame.winfo_children():
        widget.grid_remove()
    finalizing_frame.grid(row=0, column=0, columnspan=2, padx=10, pady=10, sticky="ew")
    button_frame.grid(row=1, column=0, columnspan=2, pady=20)

# Fonction pour revenir à l'application principale
def return_to_main(message_window):
    message_window.destroy()
    root.deiconify()
    show_finalizing_section()

# Fonction pour soumettre le formulaire
def submit_form():
    user_info = nom_entry.get()
    if not user_info:
        messagebox.showerror("Erreur", "Veuillez remplir le champ 'Firstname and surname of user'.")
        return

    root.iconify()
    message_window = tk.Toplevel(root)
    message_window.title("Appareil en cours d'utilisation")
    message_window.config(bg='red')

    message_window.protocol("WM_DELETE_WINDOW", lambda: None)
    message_window.resizable(False, False)
    message_window.attributes("-toolwindow", True)

    screen_width = message_window.winfo_screenwidth()
    screen_height = message_window.winfo_screenheight()
    window_width = 400
    window_height = 250  # Adjusted height to accommodate the additional labels

    # Conversion approximative de 8 cm en pixels
    offset = 304

    x_position = screen_width - window_width
    y_position = screen_height - window_height - offset
    message_window.geometry(f"{window_width}x{window_height}+{x_position}+{y_position}")

    frame = tk.Frame(message_window, bg='white', bd=10)
    frame.pack(fill='both', expand=True, padx=20, pady=20)

    message = f"Appareil actuellement utilisé par\n{user_info}"
    label = tk.Label(frame, text=message, font=('Helvetica', 16), bg='white', fg='black')
    label.pack(expand=True)

    # Afficher l'heure actuelle
    current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    time_label = tk.Label(frame, text=f"Submitted at: {current_time}", font=('Helvetica', 12), bg='white')
    time_label.pack(pady=5)

    # Initialiser le temps de départ pour le compteur
    start_time = time.time()

    # Fonction pour mettre à jour le compteur
    def update_timer():
        elapsed_time = time.time() - start_time
        minutes, seconds = divmod(int(elapsed_time), 60)
        timer_label.config(text=f"Elapsed time: {minutes:02}:{seconds:02}")
        frame.after(1000, update_timer)

    # Label pour afficher le temps écoulé
    timer_label = tk.Label(frame, text="Elapsed time: 00:00", font=('Helvetica', 12), bg='white')
    timer_label.pack(pady=5)

    # Démarrer le compteur
    update_timer()

    close_button = tk.Button(frame, text="Manipulations terminées", command=lambda: return_to_main(message_window))
    close_button.pack(pady=10)

root = tk.Tk()
root.title("Nom de la machine scientifique")
root.config(bg='#f0f0f0')
root.attributes('-fullscreen', True)
root.bind('<Escape>', lambda e: root.quit())

screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
large_font = ('Helvetica', 12)

main_frame = ttk.Frame(root, padding="20")
main_frame.pack(fill="both", expand=True)

canvas = tk.Canvas(main_frame)
scrollbar_y = ttk.Scrollbar(main_frame, orient="vertical", command=canvas.yview)
scrollbar_x = ttk.Scrollbar(main_frame, orient="horizontal", command=canvas.xview)
scrollbar_y.pack(side="right", fill="y")
scrollbar_x.pack(side="bottom", fill="x")

scrollable_frame = ttk.Frame(canvas)
scrollable_frame.bind(
    "<Configure>",
    lambda e: canvas.configure(
        scrollregion=canvas.bbox("all")
    )
)

canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
canvas.configure(yscrollcommand=scrollbar_y.set, xscrollcommand=scrollbar_x.set)
canvas.pack(side="left", fill="both", expand=True)

# Fonction pour ajouter le défilement avec la molette de la souris
def _on_mouse_wheel(event):
    canvas.yview_scroll(int(-1*(event.delta/120)), "units")

canvas.bind_all("<MouseWheel>", _on_mouse_wheel)

style = ttk.Style()
style.theme_use('clam')
style.configure('TLabel', font=('Helvetica', 12), background='#f0f0f0')
style.configure('TButton', font=('Helvetica', 12), padding=5)
style.configure('TEntry', font=('Helvetica', 12), padding=5)
style.configure('TCombobox', font=('Helvetica', 12))
style.configure('TLabelframe.Label', font=('Helvetica', 13, 'bold'), foreground='blue')
style.configure('TLabelframe', background='#f0f0f0')
style.configure('TFrame', background='#f0f0f0')

root.config(bg='#f0f0f0')
main_frame.config(style='TFrame')

# Ajouter un conteneur centré pour le formulaire
center_frame = ttk.Frame(scrollable_frame)
center_frame.grid(row=0, column=0, sticky="nsew")
scrollable_frame.columnconfigure(0, weight=1)
scrollable_frame.rowconfigure(0, weight=1)
center_frame.columnconfigure(0, weight=1)
center_frame.grid_columnconfigure(0, weight=1)  # Centrer le contenu dans center_frame

# Charger et afficher l'image
image_path = "C:/Users/David/projet_python/images/logo.png"
image = Image.open(image_path)
image = image.resize((600, 150), Image.Resampling.LANCZOS)  # Redimensionner l'image pour l'élargir
photo = ImageTk.PhotoImage(image)

image_label = tk.Label(center_frame, image=photo, bg='#f0f0f0')
image_label.image = photo  # Pour éviter que l'image soit garbage collected
image_label.grid(row=0, column=0, columnspan=2, pady=10)

label = ttk.Label(center_frame, text="Please complete this form during your manipulations", font=('Helvetica', 16, 'bold'))
label.grid(row=1, column=0, columnspan=2, pady=(0, 10))

personal_info_frame = ttk.Labelframe(center_frame, text="Personal informations", padding="10")
personal_info_frame.grid(row=2, column=0, padx=10, pady=10, sticky="ew")

users = get_users()
user_names = [user[1] for user in users]

user_combobox = ttk.Combobox(personal_info_frame, values=user_names)
user_combobox.grid(row=0, column=1, padx=10, pady=5, sticky="ew")

nom_label = ttk.Label(personal_info_frame, text="Firstname and surname of user:")
nom_label.grid(row=0, column=0, padx=10, pady=5, sticky="w")
nom_entry = ttk.Entry(personal_info_frame)
nom_entry.grid(row=0, column=1, padx=10, pady=5, sticky="ew")

matricula_label = ttk.Label(personal_info_frame, text="Enrolment number:")
matricula_label.grid(row=1, column=0, padx=10, pady=5, sticky="w")
matricula_entry = ttk.Entry(personal_info_frame)
matricula_entry.grid(row=1, column=1, padx=10, pady=5, sticky="ew")

manip_name_label = ttk.Label(personal_info_frame, text="Name of the manipulation/analysis/test:")
manip_name_label.grid(row=2, column=0, padx=10, pady=5, sticky="w")
manip_name_entry = ttk.Entry(personal_info_frame)
manip_name_entry.grid(row=2, column=1, padx=10, pady=5, sticky="ew")

lc_test_frame = ttk.Labelframe(center_frame, text="LC Test", padding="10")
lc_test_frame.grid(row=3, column=0, padx=10, pady=10, sticky="ew")

lc_test_label = ttk.Label(lc_test_frame, text="Have you passed the LC use test?")
lc_test_label.grid(row=0, column=0, padx=10, pady=5, sticky="w")

lc_test_var = tk.StringVar(value="")
def on_lc_test_change():
    if lc_test_var.get() == "Yes" and system_free_var.get() == "Yes":
        use_frame.grid()
        samples_frame.grid()
        finalizing_frame.grid()
        button_frame.grid()
        error_label.grid_remove()
    else:
        use_frame.grid_remove()
        samples_frame.grid_remove()
        finalizing_frame.grid_remove()
        button_frame.grid_remove()
        error_label.grid()

lc_test_yes = ttk.Radiobutton(lc_test_frame, text="Yes", variable=lc_test_var, value="Yes", command=on_lc_test_change)
lc_test_yes.grid(row=0, column=1, padx=10, pady=5, sticky="w")

lc_test_no = ttk.Radiobutton(lc_test_frame, text="No", variable=lc_test_var, value="No", command=on_lc_test_change)
lc_test_no.grid(row=0, column=2, padx=10, pady=5, sticky="w")

system_free_frame = ttk.Labelframe(center_frame, text="System free of issue?", padding="10")
system_free_frame.grid(row=4, column=0, padx=10, pady=10, sticky="ew")

system_free_label = ttk.Label(system_free_frame, text="Have you checked that the system is usable and free of issue?")
system_free_label.grid(row=0, column=0, padx=10, pady=5, sticky="w")

system_free_var = tk.StringVar(value="")
def on_system_free_change():
    if system_free_var.get() == "Yes" and lc_test_var.get() == "Yes":
        use_frame.grid()
        samples_frame.grid()
        finalizing_frame.grid()
        button_frame.grid()
        error_label.grid_remove()
    else:
        use_frame.grid_remove()
        samples_frame.grid_remove()
        finalizing_frame.grid_remove()
        button_frame.grid_remove()
        error_label.grid()

system_free_yes = ttk.Radiobutton(system_free_frame, text="Yes", variable=system_free_var, value="Yes", command=on_system_free_change)
system_free_yes.grid(row=0, column=1, padx=10, pady=5, sticky="w")

system_free_no = ttk.Radiobutton(system_free_frame, text="No", variable=system_free_var, value="No", command=on_system_free_change)
system_free_no.grid(row=0, column=2, padx=10, pady=5, sticky="w")

system_qualified_frame = ttk.Labelframe(center_frame, text="System qualified?", padding="10")
system_qualified_frame.grid(row=5, column=0, padx=10, pady=10, sticky="ew")

system_qualified_label = ttk.Label(system_qualified_frame, text="Has the system been qualified within less than one year (six months)?")
system_qualified_label.grid(row=0, column=0, padx=10, pady=5, sticky="w")

system_qualified_var = tk.StringVar(value="")
def on_system_qualified_change():
    if system_qualified_var.get() == "No":
        remarks_label.grid()
        remarks_entry.grid()
    else:
        remarks_label.grid_remove()
        remarks_entry.grid_remove()

system_qualified_yes = ttk.Radiobutton(system_qualified_frame, text="Yes", variable=system_qualified_var, value="Yes", command=on_system_qualified_change)
system_qualified_yes.grid(row=0, column=1, padx=10, pady=5, sticky="w")

system_qualified_no = ttk.Radiobutton(system_qualified_frame, text="No", variable=system_qualified_var, value="No", command=on_system_qualified_change)
system_qualified_no.grid(row=0, column=2, padx=10, pady=5, sticky="w")

remarks_label = ttk.Label(system_qualified_frame, text="Remarks:")
remarks_entry = ttk.Entry(system_qualified_frame)
remarks_label.grid_remove()
remarks_entry.grid_remove()

error_label = ttk.Label(center_frame, text="YOU MUST PASS THE LC TEST AND ENSURE THE SYSTEM IS FREE OF ISSUE BEFORE CONTINUING", font=('Helvetica', 12, 'bold'), foreground="red")
error_label.grid(row=6, column=0, padx=10, pady=5)
error_label.grid_remove()

use_frame = ttk.Labelframe(center_frame, text="Describe your use of:", padding="10")
use_frame.grid(row=7, column=0, padx=10, pady=10, sticky="ew")

solvents_label = ttk.Label(use_frame, text="Solvents:")
solvents_label.grid(row=0, column=0, padx=10, pady=5, sticky="w")
solvents_entry = ttk.Entry(use_frame)
solvents_entry.grid(row=0, column=1, padx=10, pady=5, sticky="ew")

channels_label = ttk.Label(use_frame, text="Channels (A1, B1, A2, B2):")
channels_label.grid(row=1, column=0, padx=10, pady=5, sticky="w")
channels_entry = ttk.Entry(use_frame)
channels_entry.grid(row=1, column=1, padx=10, pady=5, sticky="ew")

entries = [(solvents_label, solvents_entry, channels_label, channels_entry)]

def add_entry():
    row = len(entries) * 2 + 2
    new_solvent_label = ttk.Label(use_frame, text="Solvents:")
    new_solvent_label.grid(row=row, column=0, padx=10, pady=5, sticky="w")
    new_solvent_entry = ttk.Entry(use_frame)
    new_solvent_entry.grid(row=row, column=1, padx=10, pady=5, sticky="ew")
    
    new_channels_label = ttk.Label(use_frame, text="Channels (A1, B1, A2, B2):")
    new_channels_label.grid(row=row+1, column=0, padx=10, pady=5, sticky="w")
    new_channels_entry = ttk.Entry(use_frame)
    new_channels_entry.grid(row=row+1, column=1, padx=10, pady=5, sticky="ew")
    
    entries.append((new_solvent_label, new_solvent_entry, new_channels_label, new_channels_entry))
    if len(entries) > 1:
        remove_button.grid()
    update_column_position()

def remove_entry():
    if len(entries) > 1:
        labels_and_entries = entries.pop()
        for widget in labels_and_entries:
            widget.grid_forget()
        if len(entries) == 1:
            remove_button.grid_remove()
        update_column_position()

def update_column_position():
    row = len(entries) * 2 + 2
    column_desc_label.grid(row=row, column=0, padx=10, pady=5, sticky="w")
    column_desc_text.grid(row=row, column=1, padx=10, pady=5, sticky="ew")
    guard_column_desc_label.grid(row=row+1, column=0, padx=10, pady=5, sticky="w")
    guard_column_desc_text.grid(row=row+1, column=1, padx=10, pady=5, sticky="ew")
    column_label.grid(row=row+2, column=0, padx=10, pady=5, sticky="w")
    column_entry.grid(row=row+2, column=1, padx=10, pady=5, sticky="ew")

add_button = ttk.Button(use_frame, text="Add Solvent Entry", command=add_entry)
add_button.grid(row=0, column=2, padx=10, pady=5)

remove_button = ttk.Button(use_frame, text="Remove Last Solvent Entry", command=remove_entry)
remove_button.grid(row=1, column=2, padx=10, pady=5)
remove_button.grid_remove()

column_desc_label = ttk.Label(use_frame, text="Column description:")
column_desc_text = tk.Text(use_frame, height=3, width=40)
guard_column_desc_label = ttk.Label(use_frame, text="Guard column description:")
guard_column_desc_text = tk.Text(use_frame, height=3, width=40)
column_label = ttk.Label(use_frame, text="Column (+guard column) internal ID:")
column_entry = ttk.Entry(use_frame)

update_column_position()

samples_frame = ttk.Labelframe(center_frame, text="Type of samples", padding="10")
samples_frame.grid(row=8, column=0, columnspan=2, padx=10, pady=10, sticky="ew")

samples_label = ttk.Label(samples_frame, text="Type of samples:")
samples_label.grid(row=0, column=0, padx=10, pady=5, sticky="w")
samples_entry = ttk.Entry(samples_frame)
samples_entry.grid(row=0, column=1, padx=10, pady=5, sticky="ew")

finalizing_frame = ttk.Labelframe(center_frame, text="After finalizing the analysis", padding="10")
finalizing_frame.grid(row=9, column=0, columnspan=2, padx=10, pady=10, sticky="ew")

injections_label = ttk.Label(finalizing_frame, text="How many injections have you performed (including blank …) ?")
injections_label.grid(row=1, column=0, padx=10, pady=5, sticky="w")
injections_entry = ttk.Entry(finalizing_frame)
injections_entry.grid(row=1, column=1, padx=10, pady=5, sticky="ew")

finalizing_label = ttk.Label(finalizing_frame, text="How have you rinsed your column and the system ? :")
finalizing_label.grid(row=0, column=0, padx=10, pady=5, sticky="w")
finalizing_entry = ttk.Entry(finalizing_frame)
finalizing_entry.grid(row=0, column=1, padx=10, pady=5, sticky="ew")

issue_var = tk.StringVar(value="No")

def on_issue_change():
    if issue_var.get() == "Yes":
        problem_description_frame.grid()
        resolution_description_frame.grid()
        instrument_manager_label.grid()
    else:
        problem_description_frame.grid_remove()
        resolution_description_frame.grid_remove()
        instrument_manager_label.grid_remove()

issue_label = ttk.Label(finalizing_frame, text="Have you got any issue with the system:")
issue_label.grid(row=2, column=0, padx=10, pady=5, sticky="w")

issue_yes = ttk.Radiobutton(finalizing_frame, text="Yes", variable=issue_var, value="Yes", command=on_issue_change)
issue_yes.grid(row=2, column=1, sticky="w")

issue_no = ttk.Radiobutton(finalizing_frame, text="No", variable=issue_var, value="No", command=on_issue_change)
issue_no.grid(row=2, column=2, sticky="w")

problem_description_frame = ttk.Labelframe(finalizing_frame, text="If Yes, please describe fully the problem(s):", padding="10")
problem_description_frame.grid(row=3, column=0, columnspan=3, padx=10, pady=5, sticky="ew")
problem_description = tk.Text(problem_description_frame, height=3, width=50)
problem_description.pack(padx=5, pady=5)

resolution_description_frame = ttk.Labelframe(finalizing_frame, text="If Yes, could you resolve the problem and how have you resolved it ?", padding="10")
resolution_description_frame.grid(row=4, column=0, columnspan=3, padx=10, pady=5, sticky="ew")
resolution_description = tk.Text(resolution_description_frame, height=3, width=50)
resolution_description.pack(padx=5, pady=5)

instrument_manager_label = tk.Label(finalizing_frame, text="If you have not yet informed an instrument manager, please do it as soon as possible.", font=('Helvetica', 12, 'bold'), fg="red", bg="white")
instrument_manager_label.grid(row=5, column=0, columnspan=3, padx=10, pady=5, sticky="ew")
instrument_manager_label.grid_remove()

problem_description_frame.grid_remove()
resolution_description_frame.grid_remove()

additional_info_label = ttk.Label(finalizing_frame, text="Any other important information to record?")
additional_info_label.grid(row=6, column=0, padx=10, pady=5, sticky="w")
additional_info_text = tk.Text(finalizing_frame, height=4, width=50)
additional_info_text.grid(row=6, column=1, columnspan=2, padx=10, pady=5, sticky="ew")

button_frame = ttk.Frame(center_frame)
button_frame.grid(row=10, column=0, columnspan=2, pady=20)

quit_button = ttk.Button(button_frame, text="Quitter", command=root.quit)
quit_button.pack(side="left", padx=10)

submit_button = ttk.Button(button_frame, text="Soumettre", command=submit_form, style='TButton')
submit_button.pack(side="left", padx=10)

def save_responses():
    nom = nom_entry.get()
    matricula = matricula_entry.get()
    manipulation = manip_name_entry.get()
    now = datetime.datetime.now()
    formatted_date_time = now.strftime("%Y-%m-%d %H:%M:%S")

    with open("responses.txt", "a") as file:
        file.write(f"Time of record: {formatted_date_time}\n")
        file.write(f"Name: {nom}\n")
        file.write(f"Matricula: {matricula}\n")
        file.write(f"Name of the manipulation/analysis/test: {manipulation}\n")
        file.write("\n")

# Donner le focus à nom_entry une fois que la fenêtre est complètement chargée
root.after(100, lambda: nom_entry.focus_set())

root.mainloop()

Hi,

can you try not defining the size of the window in the submit_form function . I think that this will autosize the window according to the widget entry / label pairs that are defined in your script. Then you won’t have all of that empty space on the right.