[Tkinter] Horizontal extension of widgets + frame size adapted to content - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: GUI (https://python-forum.io/forum-10.html) +--- Thread: [Tkinter] Horizontal extension of widgets + frame size adapted to content (/thread-41641.html) |
Horizontal extension of widgets + frame size adapted to content - Fab117 - Feb-21-2024 Hi, I'm really beginner with TKinter/Python. I followed a TKinter training and I'm now trying to develop my 1st application. I'm facing 2 challenges where I would need some help. Some background: I'd like developing a form (2 windows) where user can either enter new information's or update those information's. Information are saved in a SQLite database. The 1st windows contains few widgets and present a summary of database content. User can either launch 2nd window for new entry or launch 2nd window to update a record. Here is the design I'm looking at for my master window: The 2 challenges I'm encountering: 1. Window resize If I resize my window, I'm able to extend all my content horizontally: 2. Navigation in the table presenting database extract I've no control on the frame height presenting the database extract (frame_summary) => if database content is big, I see only first results. I'd like this frame height to be adapted to record content (or to have its own vertical scrollbar) Here my code. import tkinter as tk from tkinter import ttk, messagebox import sqlite3 import re from datetime import datetime class FabApplication: def __init__(self, master): self.master = master self.master.title("Summary") #1 Canvas creation which will contains all children from master windows (required to add scrollbar) self.canvas_summary = tk.Canvas(self.master) self.canvas_summary.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) #1.1 Créer une barre de défilement vertical scrollbar_summary = tk.Scrollbar(self.master, orient=tk.VERTICAL, command=self.canvas_summary.yview) scrollbar_summary.pack(side=tk.RIGHT, fill=tk.Y) # Configurer le canvas pour utiliser la barre de défilement self.canvas_summary.config(yscrollcommand=scrollbar_summary.set) #1.2 Now that scrollbar is added to a canvas, creation of a global frame for all children self.frame_containermain = tk.Frame(self.canvas_summary) self.canvas_summary.create_window((0, 0), window=self.frame_containermain, anchor=tk.NW) #1.2.1 à 1.2.3. Creation of the 3 sub-frames into frame_containermain self.frame_logos = tk.Frame(self.frame_containermain, bg="light grey", relief=tk.GROOVE) self.frame_logos.pack(fill=tk.X, padx=10, pady=10) self.frame_user_selection = tk.Frame(self.frame_containermain, bg="light grey", relief=tk.GROOVE) self.frame_user_selection.pack(fill=tk.X, padx=10, pady=10) self.frame_summary = tk.Frame(self.frame_containermain, bg="light grey", relief=tk.GROOVE) self.frame_summary.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) #1.2.1 Here I add my Label widgets (pictures) in the frame: frame_logos #1.2.2 Here I add my widgets (Label, Combobox, Entry) in the frame:self.frame_user_selection #1.2.3 Creation ofthe "table" where data's from SQlite will be presented (into frame_summary) self.treeview_summary = ttk.Treeview(self.frame_summary, columns=("Initiative ID", "Owner", "Initiative name", "Total Score", "Decision")) self.treeview_summary.heading("#0", text="", anchor=tk.W) self.treeview_summary.heading("Initiative ID", text="Initiative ID", anchor=tk.W) self.treeview_summary.heading("Owner", text="Owner", anchor=tk.W) self.treeview_summary.heading("Initiative name", text="Initiative name", anchor=tk.W) self.treeview_summary.heading("Total Score", text="Total Score", anchor=tk.W) self.treeview_summary.heading("Decision", text="Decision", anchor=tk.W) self.treeview_summary.pack(fill=tk.BOTH, expand=True) #Load data's from SQLite self.load_data() # Link data loading function to event window resize self.master.bind("<Configure>", self.on_window_resize) # Config canvas canvas_summary to adapt size to content self.master.bind("<Configure>", self.on_configure2) # Link central mouse wheel event to vertical scroll self.master.bind_all("<MouseWheel>", self.on_mousewheel2) # Link lateral mouse wheel event to vertical scroll self.master.bind("<Shift-MouseWheel>", self.on_horizontal_scroll2) def load_data(self, event=None):# Method to load database info (including user filter) # Connexion to SQLite database conn = sqlite3.connect("F4G database.db") cursor = conn.cursor() # Retrieve user filter filter_value = self.combo_filter.get() # Retrieve datas based on user filter if filter_value == "": cursor.execute("SELECT InitiativeID, Owner, InitiativeName, TotalScore, Decision FROM DetailsTracker") else: cursor.execute("SELECT InitiativeID, Owner, InitiativeName, TotalScore, Decision FROM DetailsTracker WHERE Decision=?", (filter_value,)) # Delete old table entries for row in self.treeview_summary.get_children(): self.treeview_summary.delete(row) # Add new data's into table for row in cursor.fetchall(): self.treeview_summary.insert("", "end", values=row) # Close database connexion cursor.close() conn.close() def on_window_resize(self, event): # Redéfinir les largeurs des colonnes du tableau principal lors du redimensionnement de la fenêtre total_width = self.frame_summary.winfo_width() self.treeview_summary.column("#0", width=int(total_width * 0.01)) self.treeview_summary.column("Initiative ID", width=int(total_width * 0.09)) self.treeview_summary.column("Owner", width=int(total_width * 0.2)) self.treeview_summary.column("Initiative name", width=int(total_width * 0.5)) self.treeview_summary.column("Total Score", width=int(total_width * 0.1)) self.treeview_summary.column("Decision", width=int(total_width * 0.1)) # Configurer le canvas canvas_summary pour s'adapter à la taille de son contenu def on_configure2(self, event): self.canvas_summary.configure(scrollregion=self.canvas_summary.bbox("all")) # Fonction pour gérer le défilement dans canvas_summary avec la molette centrale def on_mousewheel2(self, event): # Récupérer la direction du défilement (1 pour vers le haut, -1 pour vers le bas) direction = -1 if event.delta < 0 else 1 # Effectuer le défilement self.canvas_summary.yview_scroll(direction, "units") # Fonction pour gérer le défilement horizontal avec la molette latérale dans canvas_summary def on_horizontal_scroll2(self, event): # Récupérer la direction du défilement (1 pour vers la gauche, -1 pour vers la droite) direction = 1 if event.delta > 0 else -1 # Effectuer le défilement self.canvas_summary.xview_scroll(direction, "units")Would someone see how to solve my issues? Regards, Fab RE: Horizontal extension of widgets + frame size adapted to content - Fab117 - Feb-21-2024 I found solutions to those challenges. For 1st one: #Issue was with line 23 self.canvas_summary.create_window((0, 0), window=self.frame_containermain, anchor=tk.NW) ## replaced by: self.frame_containermain.pack(fill=tk.BOTH, expand=True)For 2nd one, what I did was to introduce a vertical scrollbar related to my treeview self.treeview_summary = ttk.Treeview(self.frame_summary, columns=("Initiative ID", "Owner", "Initiative name", "Total Score", "Decision")) self.treeview_summary.heading("#0", text="", anchor=tk.W) self.treeview_summary.heading("Initiative ID", text="Initiative ID", anchor=tk.W) self.treeview_summary.heading("Owner", text="Owner", anchor=tk.W) self.treeview_summary.heading("Initiative name", text="Initiative name", anchor=tk.W) self.treeview_summary.heading("Total Score", text="Total Score", anchor=tk.W) self.treeview_summary.heading("Decision", text="Decision", anchor=tk.W) self.treeview_summary.pack(fill=tk.BOTH, expand=True) #Load data's from SQLite self.load_data() # Link data loading function to event window resize self.master.bind("<Configure>", self.on_window_resize) # Config canvas canvas_summary to adapt size to content self.master.bind("<Configure>", self.on_configure2) ## replaced by: self.treeview_summary = ttk.Treeview(self.frame_summary, columns=("Initiative ID", "Owner", "Initiative name", "Total Score", "Decision")) # +++++++ #self.treeview_summary.pack() # _______ self.treeview_summary.heading("#0", text="", anchor=tk.W) self.treeview_summary.heading("Initiative ID", text="Initiative ID", anchor=tk.W) self.treeview_summary.heading("Owner", text="Owner", anchor=tk.W) self.treeview_summary.heading("Initiative name", text="Initiative name", anchor=tk.W) self.treeview_summary.heading("Total Score", text="Total Score", anchor=tk.W) self.treeview_summary.heading("Decision", text="Decision", anchor=tk.W) self.treeview_summary.pack(fill="both", expand=True) # Utilisation de pack pour placer le tableau # Configurer le frame_summary pour s'étendre automatiquement en hauteur self.frame_summary.pack_propagate(False) # Charger les données initiales self.load_data() # +++++++ # Créer une barre de défilement vertical scrollbar_treeviewsummary = tk.Scrollbar(self.treeview_summary, orient=tk.VERTICAL, command=self.treeview_summary.yview) scrollbar_treeviewsummary.pack(side=tk.RIGHT, fill=tk.Y) # Configurer le treeview pour utiliser la barre de défilement self.treeview_summary.config(yscrollcommand=scrollbar_treeviewsummary.set) RE: Horizontal extension of widgets + frame size adapted to content - menator01 - Feb-21-2024 Although it doesn't use canvas here is a script I did in another post. Maybe it will help. https://python-forum.io/thread-37738-post-159704.html#pid159704 RE: Horizontal extension of widgets + frame size adapted to content - deanhystad - Feb-22-2024 You don't need, nor even want, to use a canvas to scroll the tree. This will have the undesired effect of scrolling the column headers so they are not always visible. The tree widget knows how to work with a scroll bar. When you hook the scrollbar directly to the tree widget, moving the scrollbar only moves the column values. The headers remain visible at the top. I think this is what happens in menator's program. |