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









Java JTable With Custom Columns

How to Create a JTable with Custom Columns In Java Netbeans

Create JTable With RadioButton, CheckBox, ComboBox, Spinner, TextField and Button Columns In Java Netbeans


In this Java Tutorial we will see How To Create a JTable with custom components in each cell. The table has six columns: RadioButton, CheckBox, ComboBox, Spinner, TextField, and Button.
For each column in the table, custom renderers and editors are set using the setColumnRendererAndEditor method. 
This method associates a TableCellRenderer (for rendering cell content) and a TableCellEditor (for editing cell content) with a specific column in the table.
The getJobList Method: Returns an array of job titles. This array is used to populate the ComboBox in the third column.

What We Are Gonna Use In This Project:

- Java Programming Language.
- NetBeans Editor.






Project Source Code:

RadioButtonRenderer Class:

public class RadioButtonRenderer extends JRadioButton implements TableCellRenderer{

    public RadioButtonRenderer(){
        setHorizontalAlignment(SwingConstants.CENTER);
        setOpaque(false);
    }
    
    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
     
        // Set the selected state based on the value
        setSelected(value != null && (boolean)value);
        return this;
    
    }

}


RadioButtonEditor Class:

public class RadioButtonEditor extends AbstractCellEditor implements TableCellEditor{

    private final JRadioButton button;
    
    public RadioButtonEditor(){
        button = new JRadioButton();
        button.setHorizontalAlignment(SwingConstants.CENTER);
    }
    
    
    @Override
    public Object getCellEditorValue() {
    
        // retun the value of the radiobutton
        return button.isSelected();
        
    }

    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
    
        // Set the selected state based on the value
        button.setSelected(value != null && (boolean)value);
        return button;
        
    }

    
}


JTable With RadioButton Column





CheckBoxRenderer Class:

public class CheckBoxRenderer extends DefaultTableCellRenderer{

    private final JCheckBox checkBox = new JCheckBox();
    
    public CheckBoxRenderer(){
        checkBox.setHorizontalAlignment(SwingConstants.CENTER);
    }
    
    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
     
        // Set the selected state based on the value
        checkBox.setSelected(value != null && (boolean)value);
        return checkBox;
    
    }
    
}


CheckBoxEditor Class:

public class CheckBoxEditor extends AbstractCellEditor implements TableCellEditor{

    private final JCheckBox checkBox = new JCheckBox();
    
    public CheckBoxEditor(){
        checkBox.setHorizontalAlignment(SwingConstants.CENTER);
    }
    
    @Override
    public Object getCellEditorValue() {
    
        // retun the value of the checkbox
        return checkBox.isSelected();
        
    }

    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
    
        // Set the selected state based on the value
        checkBox.setSelected((boolean)value);
        return checkBox;
        
    }
    
}


JTable With CheckBox Column





ComboboxRenderer Class:

public class ComboboxRenderer extends JComboBox<String> implements TableCellRenderer{

    public ComboboxRenderer(String[] items){ super(items); }
    
    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
     
        // Set the selected item in the JComboBox based on the cell value
        setSelectedItem(value);
        
        // Ensure the JComboBox is focused before rendering
        if(hasFocus){ requestFocusInWindow(); } 
        
        return this;
    }

}



ComboboxEditor Class:

public class ComboboxEditor extends DefaultCellEditor{

    public ComboboxEditor(String[] items){ 
        super(new JComboBox<>(items)); 
        // Set the number of clicks needed to start editing
        setClickCountToStart(0);
    }
    
    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
     
         // Set the selected item in the JComboBox based on the cell value
         ((JComboBox<?>) editorComponent).setSelectedItem(value);
         
         // Ensure the JComboBox is focused before editing
         SwingUtilities.invokeLater(() -> {
             ((JComboBox<?>) editorComponent).requestFocusInWindow();
         });
        
         return editorComponent;
    }
    
    
    @Override
    public Object getCellEditorValue(){
        // Return the selected item from the JComboBox
        return ((JComboBox<?>) editorComponent).getSelectedItem();
    }
  
}


JTable With ComboBox Column





SpinnerRenderer Class:

public class SpinnerRenderer extends JSpinner implements TableCellRenderer{
    
    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    
        // set value of the spinner
        setValue(value);
        return this;
    
    }

}



SpinnerEditor Class:

public class SpinnerEditor extends DefaultCellEditor{

    public SpinnerEditor(JSpinner spinner) {
        // Initialize the spinner editor
        super(new JCheckBox());
        editorComponent = spinner;
        delegate = new EditorDelegate() {
            
            // Set the value of the spinner
            @Override
            public void setValue(Object value){spinner.setValue(value);}
            
            // Get the value of the spinner
            @Override
            public Object getCellEditorValue(){ return spinner.getValue(); }
            
        };
    }
 
}



JTable With Spinner Column





TextFieldRenderer Class:

public class TextFieldRenderer extends JTextField implements TableCellRenderer{

    public TextFieldRenderer(){setHorizontalAlignment(JTextField.CENTER);}

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
      
        // Set the text of the text field
        setText(value != null ? value.toString() : "");
        return this;
        
    }
    
}



JTable With TextField Column





ButtonRenderer Class:

public class ButtonRenderer extends JButton implements TableCellRenderer{

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    
        // Set the text of the button
        setText(value != null ? value.toString() : "");
        return this;
        
    }

}




ButtonEditor Class:

public class ButtonEditor extends DefaultCellEditor{

    private JButton button;
    
    public ButtonEditor(JCheckBox checkBox) {
        // Initialize the button editor and add action listener for button click
        super(checkBox);
        button = new JButton();
        button.addActionListener((e) -> {
            JOptionPane.showMessageDialog(button, button.getText() + " Clicked");
        });
        
    }
    
    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        // Set the text of the button
        button.setText(value != null ? value.toString() : "");
        return button;        
    }
    
    // Get the text of the button
    @Override
    public Object getCellEditorValue(){ return button.getText(); }

}



JTable With Button Column





CustomTableModel Class:

public class CustomTableModel extends AbstractTableModel{
    private final Object[][] data;
    private final String[] columnNames;
    
    public CustomTableModel(Object[][] data, String[] columnNames){
        this.data = data;
        this.columnNames = columnNames;
    }
    

    @Override
    public int getRowCount() { return data.length; }

    @Override
    public int getColumnCount() { return columnNames.length; }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
    
        return data[rowIndex][columnIndex];
        
    }

    @Override
    public String getColumnName(int column){ return columnNames[column]; }
    
    @Override
    public Class<?> getColumnClass(int column){ return data[0][column].getClass(); }
    
    @Override
    public boolean isCellEditable(int row, int column){ return true; }
    
    @Override
    public void setValueAt(Object value, int row, int column){
        // Update the data and notify listeners of the change
        data[row][column] = value;
        fireTableCellUpdated(row, column);
    }
    
    
}






The MainClass Class:

public class MainClass extends JFrame{

    public MainClass(){
        setTitle("Table Custom Component");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        CustomTableModel model = new CustomTableModel(
                new Object[][]{
                        {false, false, "Developer", 1, "Text 1", "Button 1"},
                        {false, true, "Designer", 2, "Text 2", "Button 2"},
                        {true, false, "Manager", 3, "Text 3", "Button 3"},
                        {true, false, "Engineer", 4, "Text 4", "Button 4"}
                },
                new String[]{"RadioButton", "CheckBox", "ComboBox", "Spinner", "TextField", "Button"}
        );
        
        
        JTable table = new JTable(model);
        table.setRowHeight(40);
        
        setColumnRendererAndEditor(table, 0, new RadioButtonRenderer(), new RadioButtonEditor());
        setColumnRendererAndEditor(table, 1, new CheckBoxRenderer(), new CheckBoxEditor());
        setColumnRendererAndEditor(table, 2, new ComboboxRenderer(getJobList()), new ComboboxEditor(getJobList()));
        setColumnRendererAndEditor(table, 3, new SpinnerRenderer(), new SpinnerEditor(new JSpinner()));
        setColumnRendererAndEditor(table, 4, new TextFieldRenderer(), new DefaultCellEditor(new JTextField()));
        setColumnRendererAndEditor(table, 5, new ButtonRenderer(), new ButtonEditor(new JCheckBox()));
        
        
        JScrollPane scrollPanel = new JScrollPane(table);
        add(scrollPanel);
        setSize(600, 400);
        setLocationRelativeTo(null);
        
    }
    
    
    private void setColumnRendererAndEditor(JTable table, int columnIndex, TableCellRenderer renderer, TableCellEditor editor){
        // Set the renderer and editor for a specific column
        table.getColumnModel().getColumn(columnIndex).setCellRenderer(renderer);
        table.getColumnModel().getColumn(columnIndex).setCellEditor(editor);
    }
    
    
    private String[] getJobList(){
        // Return an array of job titles
        // we will use it to populate the combobox
        return new String[]{"Engineer", "Designer", "Manager", "Developer", "Analyst"};
        
    }
    
    
    public static void main(String[] args) {
        MainClass app = new MainClass();
        app.setVisible(true);
    }
    
}



The Final Result:

Java JTable With Custom Columns


if you want the full source code click on the download button below




disclaimer: you will get the source code, and to make it work in your machine is your responsibility and to debug any error/exception is your responsibility this project is for the students who want to see an example and read the code not to get and run.