Python Tkinter View Switcher - List And Grid View

How To Create a List And Grid View Switcher in Python Tkinter

How To Create a List And Grid View Switcher in Python Tkinter


In this Python Tutorial we will see How to Create a Dynamic Layout Switching between list and grid views in Python and Tkinter.

What We Are Gonna Use In This Project:

- Python Programming Language.
- Tkinter (GUI).
- VS Editor.






Project Source Code:




import tkinter as tk
from tkinter import ttk
import random

class ViewSwitcher(tk.Tk):
"""
This is our main application class window.
"""
def __init__(self):
"""
This method runs automatically when we create a new instance of our class.
"""
# Call the parent class (tk.Tk) setup method
super().__init__()
# Set up the basic window properties
self.title("Modern View Switcher") # Text shown in title bar
self.geometry("800x600") # Window size: width x height
self.configure(bg="#f0f0f0") # Background color (light gray)
# Create a style object to make our widgets look more modern
self.style = ttk.Style()
self.style.theme_use('clam') # Use the 'clam' theme
# Configure how different widget types should look
# Frames have gray background
self.style.configure('TFrame', background='#f0f0f0')
self.style.configure('TButton', font=('Arial', 10)) # Buttons use Arial font

# Create some fake data to display in our app
self.items = self._create_sample_data(20) # Create 20 sample items
# Keep track of which view mode we're currently using
self.view_mode = "list" # Start with list view (could be "list" or "grid")
# Build the user interface
self._setup_ui()
def _create_sample_data(self, count):
"""
This method creates fake data for our app to display.
Parameters:
count (int): How many items to create
Returns:
list:
"""
items = [] # Start with an empty list
# Define some categories to randomly choose from
categories = ["Technology", "Fashion", "Food", "Travel", "Sports"]
# Create the specified number of items
for i in range(1, count + 1):
# Each item is a dictionary (like a mini-database record)
item = {
"id": i, # Unique number for this item
"title": f"Item {i}", # Title (f-string puts the number in)
"category": random.choice(categories), # Pick a random category
"description": f"This is the description for item {i}."+
"It contains some details about the item.",
# Random color in hex format
"color": "#{:06x}".format(random.randint(0, 0xFFFFFF))
}
items.append(item) # Add this item to our list
return items # Return the complete list
def _setup_ui(self):
"""
This method creates all the visual elements (widgets) for our app.
"""
# Create the main container that holds everything
self.main_frame = ttk.Frame(self)
# Pack it to fill the entire window with some padding around the edges
self.main_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)
# Create the header section (top part with title and buttons)
self.header_frame = ttk.Frame(self.main_frame)
# Pack it at the top, make it stretch horizontally, add space below it
self.header_frame.pack(fill=tk.X, pady=(0, 20))
# Create the title label
title_label = ttk.Label(
self.header_frame, # Put it in the header frame
text="View Switcher", # The text to display
font=("Arial", 18, "bold"), # Font: Arial, size 18, bold
background="#f0f0f0" # Background color
)
title_label.pack(side=tk.LEFT) # Put it on the left side
# Create a frame to hold our view switcher buttons
switcher_frame = ttk.Frame(self.header_frame)
switcher_frame.pack(side=tk.RIGHT) # Put it on the right side
# Create the "List View" button
self.list_btn = tk.Button(
switcher_frame, # Parent frame
text="☰ List", # Button text with icon
width=8, # Button width
font=("Arial", 10), # Font settings
# Background: blue if active, gray if not
bg="#4a86e8" if self.view_mode == "list" else "#e0e0e0",
# Text: white if active, black if not
fg="white" if self.view_mode == "list" else "black",
relief=tk.FLAT, # Flat style (no 3D effect)
borderwidth=0, # No border
cursor="hand2", # Hand cursor when hovering
command=lambda: self.switch_view("list") # What to do when clicked
)
# Pack on left with small right margin
self.list_btn.pack(side=tk.LEFT, padx=(0, 2))
# Create the "Grid View" button (similar to list button but for grid view)
self.grid_btn = tk.Button(
switcher_frame,
text="▦ Grid", # Button text with grid icon
width=8,
font=("Arial", 10),
# Opposite colors from list button
bg="#e0e0e0" if self.view_mode == "list" else "#4a86e8",
fg="black" if self.view_mode == "list" else "white",
relief=tk.FLAT,
borderwidth=0,
cursor="hand2",
command=lambda: self.switch_view("grid") # Switch to grid view when clicked
)
self.grid_btn.pack(side=tk.LEFT)
# Create a frame to hold our scrollable content area
self.canvas_frame = ttk.Frame(self.main_frame)
self.canvas_frame.pack(fill=tk.BOTH, expand=True) # Fill remaining space
# Create a canvas (like a drawing surface) that can be scrolled
self.canvas = tk.Canvas(
self.canvas_frame,
bg="#f0f0f0", # Background color
highlightthickness=0 # Remove the border highlight
)
# Create a scrollbar for when content is too tall to fit
self.scrollbar = ttk.Scrollbar(
self.canvas_frame,
orient=tk.VERTICAL, # Vertical scrollbar
command=self.canvas.yview # Connect it to canvas vertical scrolling
)
# Place the canvas and scrollbar in the frame
# Canvas takes most space
self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) # Scrollbar on right edge
# Connect the canvas to the scrollbar
self.canvas.configure(yscrollcommand=self.scrollbar.set)
# Create a frame inside the canvas to hold our actual content
self.content_frame = ttk.Frame(self.canvas)
# Put the content frame inside the canvas
self.canvas_window = self.canvas.create_window((0, 0),
window=self.content_frame, anchor="nw")
# Set up event handlers
# When frame size changes
self.content_frame.bind("<Configure>", self._on_frame_configure)
# When canvas size changes
self.canvas.bind("<Configure>", self._on_canvas_configure)
# When mouse wheel is used
self.bind_all("<MouseWheel>", self._on_mousewheel)
# Show the initial view (list view by default)
self.render_view()
def _on_frame_configure(self, event):
"""
This method runs when the content frame changes size.
We need to update the scrollable area to match the new size.
"""
# Tell the canvas how big the scrollable area should be
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
def _on_canvas_configure(self, event):
"""
This method runs when the canvas changes size (like when window is resized).
We need to make sure the content frame matches the canvas width.
"""
width = event.width # Get the new width
# Update the content frame to match the canvas width
self.canvas.itemconfig(self.canvas_window, width=width)
def _on_mousewheel(self, event):
"""
This method runs when the user scrolls with their mouse wheel.
It makes the content scroll up or down.
"""
# Scroll the canvas up or down based on wheel direction
# event.delta is positive for up, negative for down
self.canvas.yview_scroll(int(-1*(event.delta/120)), "units")
def render_view(self):
"""
This method displays the content in the current view mode.
It decides whether to show list view or grid view.
"""
# First, remove any existing content (clear the screen)
for widget in self.content_frame.winfo_children():
widget.destroy() # Delete each widget
# Now show the content in the appropriate format
if self.view_mode == "list":
self._render_list_view() # Show items in a vertical list
else:
self._render_grid_view() # Show items in a grid layout

def _render_list_view(self):
"""
This method creates the list view - items shown one below another.
"""
# Go through each item in our data
for item in self.items:
# Create a frame to hold this one item
item_frame = ttk.Frame(self.content_frame)
# Pack it horizontally with vertical spacing
item_frame.pack(fill=tk.X, pady=5)
# Create a colored bar on the left side of each item
color_indicator = tk.Frame(
item_frame,
bg=item["color"], # Use the item's color
width=5 # Make it 5 pixels wide
)
# Put it on the left, full height
color_indicator.pack(side=tk.LEFT, fill=tk.Y)
# Create a container for the text content
content = ttk.Frame(item_frame)
content.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=10, pady=8)
# Create a container for the title and category (they go on the same line)
header = ttk.Frame(content)
header.pack(fill=tk.X)
# Create the title label
title = ttk.Label(
header,
text=item["title"], # The item's title
font=("Arial", 12, "bold"), # Bold font for emphasis
background="#f0f0f0"
)
title.pack(side=tk.LEFT) # Put it on the left side of the header
# Create the category label (like a colored tag)
category = tk.Label(
header,
text=item["category"], # The item's category
font=("Arial", 10), # Smaller font than title
bg=item["color"], # Background color matches item color
fg="white", # White text for contrast
padx=6, # Padding on left and right
pady=2, # Padding on top and bottom
borderwidth=0 # No border
)
category.pack(side=tk.RIGHT) # Put it on the right side of the header
# Create the description label
description = ttk.Label(
content,
text=item["description"], # The item's description
wraplength=650, # Wrap text if it gets too long
background="#f0f0f0"
)
description.pack(anchor=tk.W, pady=(5, 0)) # Left-align with top margin


def _render_grid_view(self):
"""
This method creates the grid view - items shown in a grid pattern.
"""
# Set up the grid: we want 3 columns
columns = 3
# Configure each column to expand equally
for i in range(columns):
self.content_frame.columnconfigure(i, weight=1)
# Place each item in the grid
for index, item in enumerate(self.items):
# Calculate which row and column this item should go in
row = index // columns # Integer division gives us the row
col = index % columns # Remainder gives us the column
# Create a card for this item
card = tk.Frame(
self.content_frame,
bg="white", # White background
relief=tk.RAISED, # Slightly raised appearance
bd=0, # No border width
highlightbackground=item["color"], # Colored border
highlightthickness=2 # Border thickness
)
# Place the card in the grid
card.grid(row=row, column=col, padx=10, pady=10, sticky="nsew")
# Create the title label inside the card
title = tk.Label(
card,
text=item["title"], # Item title
font=("Arial", 12, "bold"), # Bold font
bg="white", # White background
anchor="w" # Left-align the text
)
title.pack(fill=tk.X, padx=12, pady=(12, 5)) # Pack with padding
# Create the category label (colored tag)
category = tk.Label(
card,
text=item["category"], # Category text
font=("Arial", 10), # Smaller font
bg=item["color"], # Colored background
fg="white", # White text
padx=6, # Horizontal padding
pady=2 # Vertical padding
)
category.pack(anchor=tk.W, padx=12, pady=(0, 8)) # Left-align with padding
# Create the description (shortened for grid view to save space)
# Take first 50 characters and add "..."
description_text = item["description"][:50] + "..."
description = tk.Label(
card,
text=description_text, # Shortened description
wraplength=200, # Wrap text at 200 pixels
justify=tk.LEFT, # Left-justify the text
bg="white", # White background
anchor="w" # Left-align
)
description.pack(fill=tk.X, padx=12, pady=(0, 12)) # Pack with padding
def switch_view(self, mode):
"""
This method switches between list and grid views.
It's called when the user clicks the List or Grid buttons.
Parameters:
mode (str): Either "list" or "grid" - which view to switch to
"""
# If we're already in the requested mode, don't do anything
if mode == self.view_mode:
return
# Update our current view mode
self.view_mode = mode
# Update the button colors to show which one is active
if mode == "list":
# List is active: make list button blue, grid button gray
self.list_btn.configure(bg="#4a86e8", fg="white")
self.grid_btn.configure(bg="#e0e0e0", fg="black")
else:
# Grid is active: make grid button blue, list button gray
self.list_btn.configure(bg="#e0e0e0", fg="black")
self.grid_btn.configure(bg="#4a86e8", fg="white")
# Re-draw the content in the new view mode
self.render_view()




if __name__ == "__main__":
app = ViewSwitcher()
app.mainloop()




The Final Result:

Python Tkinter Grid View

Python Tkinter List View









Share this

Related Posts

Latest
Previous
Next Post »