TomSchimansky / CustomTkinter

A modern and customizable python UI-library based on Tkinter
MIT License
11.64k stars 1.09k forks source link

Layout changes on a different screen resolution problem #2489

Open redoine32 opened 5 months ago

redoine32 commented 5 months ago

Hi Devs! Iam very new to coding and i have a problem with my UI layout changes on defrent screen sizes even when i change the resolution of my screen here is my code i hope some one can help me with this Problem thanks in advance

import customtkinter as ctk
from tkinter import filedialog, Menu
from PIL import Image, ImageTk
import pandas as pd
import os

COLUMN_WIDTH = 20

def read_excel_file(file_path):
    try:
        df = pd.read_excel(file_path, header=None)
        return df.dropna()
    except FileNotFoundError:
        print("File not found. Please provide a valid file path.")
        return None
    except Exception as e:
        print("An error occurred:", e)
        return None

def extract_number(lines):
    extracted_numbers = []
    for line in lines:
        parts = line.strip().split('-')
        if len(parts) >= 3:
            extracted_numbers.append(parts[2])
    return extracted_numbers

def find_unique_codes(excel_df, text_numbers):
    try:
        unique_excel = excel_df[~excel_df.iloc[:, 0].astype(str).isin(text_numbers)]
        return unique_excel
    except KeyError:
        print("Error: The Excel file does not contain a column named 'Code'.")
        return None

def format_table(data, column_width):
    formatted_lines = []

    column_start_positions = [0] * len(data[0])

    for row in data:
        for idx, item in enumerate(row):
            column_start_positions[idx] = max(column_start_positions[idx], len(str(item)) + 2)

    border_line = "+" + "+".join(["-" * (width + 2) for width in column_start_positions]) + "+"
    formatted_lines.append(border_line)

    for row in data:
        formatted_row = []
        for idx, item in enumerate(row):
            formatted_item = str(item).ljust(column_start_positions[idx] - 1)[:column_start_positions[idx] - 1]
            formatted_row.append(formatted_item + " " * (column_start_positions[idx] - len(formatted_item)))
        formatted_lines.append("| " + " | ".join(formatted_row) + " |")
        formatted_lines.append(border_line)

    return "\n".join(formatted_lines)

def center_text(text_widget, text):
    text_widget.delete('1.0', ctk.END)
    lines = text.split('\n')
    for line in lines:
        line = line.strip()
        spaces_to_add = (text_widget.winfo_width() // 10 - len(line)) // 2
        centered_line = ' ' * spaces_to_add + line
        text_widget.insert(ctk.END, centered_line + '\n')

def compare_files():
    excel_file_paths = excel_file_entry.get().strip().split(';')
    text_file_path = text_file_entry.get().strip()

    print(f"Comparing files. Excel files: {excel_file_paths}")
    print(f"Text file: {text_file_path}")

    if all(excel_file_paths) and text_file_path:
        excel_dfs = []
        for excel_file_path in excel_file_paths:
            excel_df = read_excel_file(excel_file_path)
            if excel_df is not None:
                excel_dfs.append(excel_df)

        if excel_dfs:
            combined_excel_df = pd.concat(excel_dfs, ignore_index=True)
            with open(text_file_path, 'r') as file:
                lines = [line.strip() for line in file]

                text_numbers = extract_number(lines)
                unique_excel = find_unique_codes(combined_excel_df, text_numbers)

                excel_result_text.delete('1.0', ctk.END)
                text_result_text.delete('1.0', ctk.END)

                if unique_excel is not None:
                    if len(excel_file_paths) > 1:
                        unique_excel_count_value = len(unique_excel) - 2
                    else:
                        unique_excel_count_value = len(unique_excel) - 1
                    unique_excel_count.set(f"Nombre de colis à justifier: {max(unique_excel_count_value, 0)}")
                    unique_text_count.set(f"Nombre de colis dans le dépot à vérifier : {len(set(text_numbers) - set(combined_excel_df.iloc[:, 0].astype(str)))}")

                    if not unique_excel.empty:
                        formatted_table = format_table(unique_excel.values.tolist(), COLUMN_WIDTH)
                        center_text(excel_result_text, formatted_table)
                    else:
                        center_text(excel_result_text, "No unique rows found in Excel file.\n")

                    unique_text = set(text_numbers) - set(combined_excel_df.iloc[:, 0].astype(str))
                    if unique_text:
                        for code in unique_text:
                            text_result_text.insert(ctk.END, code + '\n')
                    else:
                        text_result_text.insert(ctk.END, "No unique codes found in Text file.\n")
                else:
                    center_text(excel_result_text, "Error occurred while finding unique codes in Excel file.\n")
        else:
            center_text(excel_result_text, "Error reading Excel file(s).\n")
            text_result_text.delete('1.0', ctk.END)
    else:
        if not all(excel_file_paths):
            center_text(excel_result_text, "No Arrivé selected.\n")
        if not text_file_path:
            text_result_text.delete('1.0', ctk.END)
            text_result_text.insert(ctk.END, "No Dépot selected.\n")

def export_results():
    file_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files", "*.txt")])
    if file_path:
        with open(file_path, 'w', encoding='utf-8') as file:
            file.write("Unique Excel File Rows:\n")
            file.write(excel_result_text.get("1.0", ctk.END))
            file.write("\nUnique Text File Codes:\n")
            file.write(text_result_text.get("1.0", ctk.END))
        print(f"Results exported to {file_path}")

def copy_text(widget):
    widget.event_generate('<Control-c>')

def bind_right_click(widget):
    menu = Menu(widget, tearoff=0)
    menu.add_command(label="Copy", command=lambda: copy_text(widget))
    widget.bind("<Button-3>", lambda event: menu.post(event.x_root, event.y_root))

def browse_excel_file():
    excel_file_entry.delete(0, ctk.END)
    file_paths = filedialog.askopenfilenames(filetypes=[("Excel files", "*.xlsx;*.xls")])
    if file_paths:
        excel_file_entry.insert(ctk.END, ";".join(file_paths))

def browse_text_file():
    text_file_entry.delete(0, ctk.END)
    file_path = filedialog.askopenfilename(filetypes=[("Text files", "*.txt")])
    text_file_entry.insert(ctk.END, file_path)

def main():
    global excel_file_entry, text_file_entry, excel_result_text, text_result_text, unique_excel_count, unique_text_count

    ctk.set_default_color_theme("dark-blue")

    root = ctk.CTk()
    root.title("KAZI TOUR")

    current_path = os.path.dirname(os.path.realpath(__file__))
    current_path = os.path.dirname(os.path.realpath(__file__))
    bg_image = Image.open(current_path + "/test_images/bg_gradient.jpg")
    bg_image = bg_image.resize((root.winfo_screenwidth(), root.winfo_screenheight()), Image.LANCZOS)
    bg_image = ImageTk.PhotoImage(bg_image)
    bg_label = ctk.CTkLabel(root, image=bg_image)
    bg_label.grid(row=0, column=0, sticky="nsew")
    bg_label.lower()

    root.geometry(f"{root.winfo_screenwidth()}x{root.winfo_screenheight()}")

    selection_frame = ctk.CTkFrame(root, width=300, corner_radius=20)
    selection_frame.grid(row=0, column=0, padx=100, pady=50, sticky="n")

    excel_file_label = ctk.CTkLabel(selection_frame, text="Arrivé:", font=("Arial", 18, "bold"))
    excel_file_label.grid(row=0, column=0, padx=(20, 10), pady=10)

    excel_file_entry = ctk.CTkEntry(selection_frame, width=300)
    excel_file_entry.grid(row=0, column=1, padx=(10, 20), pady=10)

    excel_file_button = ctk.CTkButton(selection_frame, text="Parcourir", font=("Arial", 16, "bold"), command=browse_excel_file)
    excel_file_button.grid(row=0, column=2, padx=(10, 20), pady=10)

    text_file_label = ctk.CTkLabel(selection_frame, text="Dépot:", font=("Arial", 18, "bold"))
    text_file_label.grid(row=1, column=0, padx=(20, 10), pady=10)

    text_file_entry = ctk.CTkEntry(selection_frame, width=300)
    text_file_entry.grid(row=1, column=1, padx=(10, 20), pady=10)

    text_file_button = ctk.CTkButton(selection_frame, text="Parcourir", font=("Arial", 16, "bold"), command=browse_text_file)
    text_file_button.grid(row=1, column=2, padx=(10, 20), pady=10)

    compare_button = ctk.CTkButton(selection_frame, text="Comparer", font=("Arial", 16, "bold"), command=compare_files)
    compare_button.grid(row=2, column=1, pady=20)

    export_button = ctk.CTkButton(selection_frame, text="Exporter", font=("Arial", 16, "bold"), command=export_results)
    export_button.grid(row=2, column=2, padx=(10, 20), pady=10)

    result_frame = ctk.CTkFrame(root, corner_radius=20)
    result_frame.grid(row=0, column=0, padx=500, pady=30, sticky="ew")
    excel_result_label = ctk.CTkLabel(result_frame, text="Les colis non scannés ou avec erreur de scanning :", font=("Arial", 20, "bold"))
    excel_result_label.pack(anchor=ctk.CENTER)

    unique_excel_count = ctk.StringVar()
    unique_excel_count_label = ctk.CTkLabel(result_frame, textvariable=unique_excel_count, font=("Arial", 16, "bold"))
    unique_excel_count_label.pack(anchor=ctk.CENTER)

    excel_result_frame = ctk.CTkFrame(result_frame, corner_radius=5)
    excel_result_frame.pack(expand=True, fill=ctk.BOTH, padx=4, pady=4)

    excel_result_text = ctk.CTkTextbox(excel_result_frame, wrap=ctk.NONE, width=100, font=("Calibri", 16, "bold"))
    excel_result_text.pack(expand=True, fill=ctk.BOTH, padx=5, pady=5)
    bind_right_click(excel_result_text)

    text_result_label = ctk.CTkLabel(result_frame, text="Les colis non arrivés dans le système :", font=("Arial", 20, "bold"))
    text_result_label.pack(anchor=ctk.CENTER)

    unique_text_count = ctk.StringVar()
    unique_text_count_label = ctk.CTkLabel(result_frame, textvariable=unique_text_count, font=("Arial", 16, "bold"))
    unique_text_count_label.pack(anchor=ctk.CENTER)

    text_result_frame = ctk.CTkFrame(result_frame, corner_radius=5)
    text_result_frame.pack(expand=True, fill=ctk.BOTH, padx=5, pady=5)

    text_result_text = ctk.CTkTextbox(text_result_frame, wrap=ctk.NONE, width=10, font=("Calibri", 18, "bold"))
    text_result_text.pack(expand=True, fill=ctk.BOTH, padx=5, pady=5)
    bind_right_click(text_result_text)

    root.mainloop()

if __name__ == "__main__":
    main()

here is the problem that i have the widget doesn’t fit on the screen when viewing it on a smaller screen resolution Screenshot 2024-06-24 221214 it should be like this on every screen resolution Screenshot 2024-06-24v 221413

mate02102003 commented 5 months ago

You have your widgets width set to constant values, if you want to fit them like in 2nd picture, you need to implement something so it scales with the window size.

redoine32 commented 5 months ago

You have your widgets width set to constant values, if you want to fit them like in 2nd picture, you need to implement something so it scales with the window size.

Thanks a lot mate02102003 for the reply now the widgets scales perfectly after removing the width Values but the background image still have the same problem

mate02102003 commented 5 months ago

Thanks a lot mate02102003 for the reply now the widgets scales perfectly after removing the width Values but the background image still have the same problem

Just a question do you change your resoulution after you started the app?

The PhotoImage has an option size and also accepts relative path, so inted of this:

bg_image = Image.open(current_path + "/test_images/bg_gradient.jpg")
bg_image = bg_image.resize((root.winfo_screenwidth(), root.winfo_screenheight()), Image.LANCZOS)
bg_image = ImageTk.PhotoImage(bg_image)

You can do this:

bg_image = ImageTk.PhotoImage("/test_images/bg_gradient.jpg", (root.winfo_screenwidth(), root.winfo_screenheight())

But you migth have to divide the width and height by 2, in my project that I am working on it gave me correct size like that.

mate02102003 commented 5 months ago

Also next time open a Discussion not an Issue about this

PS: You can also have python syntax highligthing in the code snippet by doing this:

```python
code...

You can replace python with any other programming language
redoine32 commented 5 months ago

thnaks for the replay Mate still have the problem here is a screenshot so can understand the situation better note that this one is opend zith the resolution set at 720p but on 1080 works fine 0000

mate02102003 commented 5 months ago

thnaks for the replay Mate still have the problem here is a screenshot so can understand the situation better note that this one is opend zith the resolution set at 720p but on 1080 works fine

I see what the problem is, you put both selction_frame and result_frame on row=0, you have to put selection_frame on row=0 and result_frame row=1.