Python Forum
[Tkinter] Horizontal extension of widgets + frame size adapted to content
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tkinter] Horizontal extension of widgets + frame size adapted to content
#1
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:
[Image: uleh.png]

The 2 challenges I'm encountering:
1. Window resize
If I resize my window, I'm able to extend all my content horizontally:
[Image: k04h.png]

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)
[Image: 0otg.png]

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
Reply
#2
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)
Reply
#3
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-pos...#pid159704
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags


Reply
#4
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.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [Tkinter] using different frame for some widgets rwahdan 1 2,391 Jul-13-2021, 08:32 AM
Last Post: Yoriz
  [Tkinter] Trying to change font size w/o changing button size python63 3 9,892 Aug-05-2020, 01:04 AM
Last Post: Larz60+
  [PyQt] Help: check content of combobox in horizontal header of QTableWidget mart79 1 3,378 Jul-26-2020, 06:18 PM
Last Post: deanhystad
  [Tkinter] Scrollbar, Frame and size of Frame Maksim 2 9,037 Sep-30-2019, 07:30 AM
Last Post: Maksim
  Require scroll bars horizontal and vertical throughout the window tejgandhi 2 2,721 Jun-28-2019, 03:13 AM
Last Post: tejgandhi
  [Tkinter] create and insert a new frame on top of another frame atlass218 4 11,174 Apr-18-2019, 05:36 PM
Last Post: atlass218
  [Tkinter] Treeview automatically adjust it's size when pack inside frame Prince_Bhatia 1 27,906 Jul-25-2018, 03:24 AM
Last Post: Larz60+
  [Tkinter] Frame size only works if frame is empty(Solved) Tuck12173 7 6,480 Jan-29-2018, 10:44 PM
Last Post: Larz60+
  PyGtk3 why is Locale Folder Size Half of Module Size ? harun2525 1 3,636 Mar-09-2017, 03:46 AM
Last Post: Analyser

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020