Python Tkinter Hamburger Menu

How To Create a Hamburger Menu Dashboard In Python Tkinter



In this Python Tutorial we will see How to Create a dashboard with a smooth sliding hamburger menu using Python  and Tkinter library.

What We Are Gonna Use In This Project:

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






Project Source Code:




import math
import tkinter as tk
from tkinter import ttk
import time

class HamburgerMenu:
def __init__(self, master):
"""Initialize the Dashboard application
Args:
master: The tkinter root window
"""
self.master = master
self.master.title("Dashboard")
# Configure the main window size and background color
self.master.geometry("1000x700")
self.master.configure(bg='#1a1a1a') # Dark background for modern look
# Initialize menu state variables
self.menu_expanded = False # Track if side menu is expanded
self.menu_width = 0 # Current width of the menu (for animation)
self.target_width = 280 # Target width when menu is fully expanded
self.animation_speed = 15 # Controls how fast the menu slides
self.animation_running = False # Flag to prevent multiple animations
self.active_menu = "Home" # Track which menu item is currently active
# Build the UI components
self.setup_frames()
self.create_title()
self.create_hamburger_button()
self.create_menu_items()
self.create_content()

def setup_frames(self):
"""Create and configure the main frame structure of the application"""
# Create the header bar at the top
self.header_frame = tk.Frame(self.master, bg='#121212', height=70)
self.header_frame.pack(fill='x', side='top')
self.header_frame.pack_propagate(False) # Prevent the frame from shrinking
# Add a thin separator line below the header
self.separator_frame = tk.Frame(self.master, height=2, bg='#2a2a2a')
self.separator_frame.pack(fill='x')
# Main container that will hold both menu and content
self.container = tk.Frame(self.master, bg='#121212')
self.container.pack(fill='both', expand=True)
# This is the sliding menu panel container (starts with zero width)
self.menu_container = tk.Frame(self.container, bg='#121212', width=0)
self.menu_container.pack(side='left', fill='y')
# Important to maintain controlled width
self.menu_container.pack_propagate(False)
# Inner menu frame with padding for a polished look
self.menu_frame = tk.Frame(self.menu_container, bg='#1e1e1e', bd=0)
self.menu_frame.pack(fill='both', expand=True, padx=(10, 5), pady=10)
# Main content area where dashboards will be displayed
self.content_frame = tk.Frame(self.container, bg='#121212')
self.content_frame.pack(side='left', fill='both', expand=True,
padx=20, pady=10)

def create_title(self):
"""Create the title/logo area in the header"""
# Frame to hold the title elements
title_frame = tk.Frame(self.header_frame, bg='#121212')
title_frame.pack(side='left', padx=(70, 0))
# Create a small colored vertical bar as a design accent
accent = tk.Frame(title_frame, width=4, height=24, bg='#4a9eff')
accent.pack(side='left', padx=(0, 10))
# The actual title text
title_label = tk.Label(
title_frame,
text="DASHBOARD",
font=("Helvetica", 16, "bold"),
bg='#121212',
fg='#ffffff'
)
title_label.pack(side='left')
# Add current time display to header
self.time_label = tk.Label(
self.header_frame,
text="",
font=("Helvetica", 12),
bg='#121212',
fg='#888888'
)
self.time_label.pack(side='right', padx=20)
self.update_time() # Start the time update loop

def update_time(self):
"""Update the time display in the header (called every second)"""
current_time = time.strftime("%H:%M:%S")
self.time_label.config(text=current_time)
self.master.after(1000, self.update_time) # Schedule the next update


def create_hamburger_button(self):
"""Create the hamburger menu button with hover effects"""
# Use a canvas to create a circular button
self.button_canvas = tk.Canvas(
self.header_frame,
width=40,
height=40,
bg='#121212',
highlightthickness=0 # Remove the default canvas border
)
self.button_canvas.place(x=15, y=15)
# Draw the circular background
self.button_bg = self.button_canvas.create_oval(0, 0, 40, 40,
fill='#1e1e1e', outline='')
# Add the hamburger icon (☰) text
self.button_text = self.button_canvas.create_text(
20, 20, # Center of the circle
text="☰",
font=("Helvetica", 18),
fill='#ffffff'
)
# Bind mouse events for interactivity
self.button_canvas.bind('<Button-1>', self.toggle_menu) # Click event
self.button_canvas.bind('<Enter>', self.hamburger_hover_in) # Mouse enter
self.button_canvas.bind('<Leave>', self.hamburger_hover_out) # Mouse leave
self.button_canvas.configure(cursor="hand2") # Change cursor to hand on hover

def hamburger_hover_in(self, event):
"""Handle mouse enter event on hamburger button"""
# Darken background
self.button_canvas.itemconfig(self.button_bg, fill='#252525')
# Change icon color
self.button_canvas.itemconfig(self.button_text, fill='#4a9eff')

def hamburger_hover_out(self, event):
"""Handle mouse leave event on hamburger button"""
# Restore background
self.button_canvas.itemconfig(self.button_bg, fill='#1e1e1e')
# Restore icon color
self.button_canvas.itemconfig(self.button_text, fill='#ffffff')

def create_menu_items(self):
"""Create the sliding menu with all menu items"""
# Define menu items with their icons, labels and accent colors
menu_items = [
("⌂", "Home", "#4a9eff"),
("◉", "Profile", "#4ecdc4"),
("⚙", "Settings", "#9b59b6"),
("△", "Analytics", "#3498db"),
("✉", "Messages", "#e74c3c"),
("?", "Support", "#f1c40f"),
]
# Create profile section at the top of menu
self.create_profile_section()
# Create menu header with "MENU" text
menu_header = tk.Frame(self.menu_frame, bg='#1e1e1e', height=30)
menu_header.pack(fill='x', pady=(20, 15))
menu_header.pack_propagate(False)
tk.Label(
menu_header,
text="MENU",
font=("Helvetica", 10, "bold"),
bg='#1e1e1e',
fg='#555555'
).pack(side='left', padx=15, pady=10)
# Container frame for all menu items with some padding
menu_items_container = tk.Frame(self.menu_frame, bg='#1e1e1e')
menu_items_container.pack(fill='x', padx=5)

# Store references to all menu buttons for later access
self.menu_buttons = []
# Create each menu item
for icon, text, color in menu_items:
# Create a frame for each menu item
item_frame = tk.Frame(menu_items_container, bg='#1e1e1e', height=50)
item_frame.pack(fill='x', pady=3)
item_frame.pack_propagate(False)
# Use canvas for better visual control
item_canvas = tk.Canvas(
item_frame,
bg='#1e1e1e',
highlightthickness=0,
height=50
)
item_canvas.pack(fill='x')
# Store references for the canvas and its rectangle for hover effects
item_frame.canvas = item_canvas
item_frame.bg_rect = item_canvas.create_rectangle(
0, 0, 280, 50,
fill='#1e1e1e',
outline='',
width=0
)
# Create left accent bar with the item's color
accent_rect = item_canvas.create_rectangle(
8, 10, 12, 40,
fill=color,
outline='',
width=0
)
# Hide accent initially (only shown on hover/active)
item_canvas.itemconfig(accent_rect, state='hidden')
item_frame.accent_rect = accent_rect
# Add icon with subtle background in a circular shape
icon_x, icon_y = 30, 25
# Draw circular background for icon
icon_bg = item_canvas.create_oval(
icon_x-15, icon_y-15,
icon_x+15, icon_y+15,
fill='#252525',
outline=''
)
# Draw the icon text
icon_text = item_canvas.create_text(
icon_x, icon_y,
text=icon,
font=("Helvetica", 14),
fill='#ffffff'
)
# Add menu text
text_label = item_canvas.create_text(
80, 25,
text=text,
font=("Helvetica", 12),
fill='#ffffff',
anchor='w'
)
# Check if this is the active menu and style it accordingly
if text == self.active_menu:
# Highlight the active menu
item_canvas.itemconfig(item_frame.bg_rect, fill='#252525')
item_canvas.itemconfig(accent_rect, state='normal')
# Store the active state
item_frame.active = True
else:
item_frame.active = False
# Store color references for hover effects
item_frame.original_bg = '#1e1e1e' # Default background
item_frame.hover_bg = '#252525' # Background on hover
item_frame.active_bg = '#2a2a2a' # Background when active
item_frame.accent_color = color # Accent color for this item
item_frame.text = text # Menu item text for reference
# Bind hover and click events
item_canvas.bind('<Enter>', lambda e,
f=item_frame: self.menu_item_hover_in(f))
item_canvas.bind('<Leave>', lambda e,
f=item_frame: self.menu_item_hover_out(f))
item_canvas.bind('<Button-1>', lambda e,
f=item_frame: self.menu_item_click(f))
# Change cursor on hover
item_canvas.configure(cursor="hand2")
# Add to list of menu buttons for later reference
self.menu_buttons.append(item_frame)

# Add a divider below menu items
divider = tk.Frame(self.menu_frame, height=1, bg='#2a2a2a')
divider.pack(fill='x', pady=15, padx=15)
# Add logout button at the bottom
self.create_logout_button()


def create_profile_section(self):
"""Create the user profile section at the top of the menu"""
# Profile section container
profile_frame = tk.Frame(self.menu_frame, bg='#1e1e1e', height=90)
profile_frame.pack(fill='x', pady=(15, 0))
profile_frame.pack_propagate(False)
# Create a canvas for the profile circle
profile_canvas = tk.Canvas(
profile_frame,
width=70,
height=70,
bg='#1e1e1e',
highlightthickness=0
)
profile_canvas.place(relx=0.5, y=10, anchor='n') # Center horizontally
# Draw circular profile background
profile_bg = profile_canvas.create_oval(5, 5, 65, 65,
fill='#252525', outline='')
# Draw profile placeholder with user initials
profile_text = profile_canvas.create_text(
35, 35, # Center of the circle
text="JD", # User initials (John Doe)
font=("Helvetica", 22, "bold"),
fill='#4a9eff'
)
# Add user name below profile image
tk.Label(
profile_frame,
text="John Doe",
font=("Helvetica", 12, "bold"),
bg='#1e1e1e',
fg='#ffffff'
).place(relx=0.5, y=90, anchor='s') # Center horizontally

def create_logout_button(self):
"""Create the logout button at the bottom of the menu"""
# Create a frame for logout button
logout_frame = tk.Frame(self.menu_frame, bg='#1e1e1e', height=50)
logout_frame.pack(fill='x', side='bottom', padx=15, pady=10)
# Create a canvas for the logout button to add rounded corners effect
logout_canvas = tk.Canvas(
logout_frame,
bg='#1e1e1e',
highlightthickness=0,
height=45
)
logout_canvas.pack(fill='x')
# Draw rectangle background
logout_bg = logout_canvas.create_rectangle(
0, 0, 280, 45,
fill='#252525',
outline='',
width=0
)
# Add icon and text
logout_icon = logout_canvas.create_text(
25, 23,
text="→", # Right arrow icon
font=("Helvetica", 14),
fill='#e74c3c',
anchor='w'
)
logout_text = logout_canvas.create_text(
55, 23,
text="Logout",
font=("Helvetica", 12, "bold"),
fill='#ffffff',
anchor='w'
)
# Add hover effects
def on_enter(e):
"""Mouse enter effect for logout button"""
logout_canvas.itemconfig(logout_bg, fill='#2c2c2c')
logout_canvas.itemconfig(logout_text, fill='#e74c3c')
def on_leave(e):
"""Mouse leave effect for logout button"""
logout_canvas.itemconfig(logout_bg, fill='#252525')
logout_canvas.itemconfig(logout_text, fill='#ffffff')
# Bind events
logout_canvas.bind('<Enter>', on_enter)
logout_canvas.bind('<Leave>', on_leave)
logout_canvas.bind('<Button-1>', lambda e: print("Logout clicked"))
logout_canvas.configure(cursor="hand2")
def menu_item_hover_in(self, frame):
"""Handle mouse enter event on menu items
Args:
frame: The menu item frame being hovered
"""
# Only change appearance if this isn't the active menu item
if not frame.active:
frame.canvas.itemconfig(frame.bg_rect, fill=frame.hover_bg)
frame.canvas.itemconfig(frame.accent_rect, state='normal')
def menu_item_hover_out(self, frame):
"""Handle mouse leave event on menu items
Args:
frame: The menu item frame being left
"""
# Only change appearance if this isn't the active menu item
if not frame.active:
frame.canvas.itemconfig(frame.bg_rect, fill=frame.original_bg)
frame.canvas.itemconfig(frame.accent_rect, state='hidden')

def menu_item_click(self, frame):
"""Handle click event on menu items
Args:
frame: The menu item frame being clicked
"""
# Deactivate all menu items first
for btn in self.menu_buttons:
btn.active = False
btn.canvas.itemconfig(btn.bg_rect, fill=btn.original_bg)
btn.canvas.itemconfig(btn.accent_rect, state='hidden')
# Activate the clicked item
frame.active = True
frame.canvas.itemconfig(frame.bg_rect, fill=frame.active_bg)
frame.canvas.itemconfig(frame.accent_rect, state='normal')
# Update the active menu
self.active_menu = frame.text
print(f"Clicked on {frame.text}")




def create_content(self):
"""Create the main content area with welcome panel and info cards"""
# Create welcome panel at the top
self.welcome_frame = tk.Frame(self.content_frame, bg='#181818', height=200)
self.welcome_frame.pack(fill='x', pady=(0, 20))
self.welcome_frame.pack_propagate(False)
# Add decorative accent line
accent_line = tk.Frame(self.welcome_frame, bg='#4a9eff', width=80, height=3)
accent_line.place(x=40, y=40)
# Welcome text
tk.Label(
self.welcome_frame,
text="Welcome Back!",
font=("Helvetica", 28, "bold"),
bg='#181818',
fg='#ffffff'
).place(x=40, y=55)
tk.Label(
self.welcome_frame,
text="Explore your dashboard and manage your content",
font=("Helvetica", 12),
bg='#181818',
fg='#888888'
).place(x=40, y=100)
# Create a status indicator with green dot
status_frame = tk.Frame(self.welcome_frame, bg='#181818')
status_frame.place(x=40, y=140)
status_dot = tk.Canvas(status_frame, width=12, height=12,
bg='#181818', highlightthickness=0)
status_dot.pack(side='left')
status_dot.create_oval(0, 0, 10, 10, fill='#2ecc71', outline='') # Green dot
tk.Label(
status_frame,
text="All systems operational",
font=("Helvetica", 11),
bg='#181818',
fg='#2ecc71'
).pack(side='left', padx=5)
# Create three info cards section
self.card_container = tk.Frame(self.content_frame, bg='#121212')
self.card_container.pack(fill='x')
# Define data for the three cards
cards_data = [
("Statistics", "#2980b9", "128", "Active Users"),
("Performance", "#27ae60", "94%", "System Uptime"),
("Activity", "#8e44ad", "37", "New Events")
]
# Store card widgets for animation
self.content_cards = []
# Create each info card
for title, color, number, subtitle in cards_data:
card = tk.Frame(self.card_container, bg='#181818', width=200, height=150)
card.pack(side='left', padx=10, fill='both', expand=True)
card.pack_propagate(False)
# Add colored top border as accent
top_border = tk.Frame(card, height=3, bg=color)
top_border.pack(fill='x', side='top')
# Add card content - title, number, and subtitle
tk.Label(
card,
text=title,
font=("Helvetica", 14, "bold"),
bg='#181818',
fg='#ffffff'
).pack(anchor='w', padx=15, pady=(20, 5))
tk.Label(
card,
text=number,
font=("Helvetica", 28, "bold"),
bg='#181818',
fg=color
).pack(anchor='w', padx=15, pady=(5, 0))
tk.Label(
card,
text=subtitle,
font=("Helvetica", 12),
bg='#181818',
fg='#888888'
).pack(anchor='w', padx=15, pady=(0, 15))
# Add card to list for animation
self.content_cards.append(card)




def toggle_menu(self, event=None):
"""Toggle the side menu open/closed when hamburger button is clicked"""
# Prevent multiple animations from running at once
if self.animation_running:
return
# Toggle the menu state
if not self.menu_expanded:
self.expand_menu()
else:
self.collapse_menu()
# Change hamburger button to X or back
if self.menu_expanded:
self.button_canvas.itemconfig(self.button_text, text="✕") # X icon
else:
self.button_canvas.itemconfig(self.button_text, text="☰") # Hamburger icon


def expand_menu(self):
"""Start animation to expand the side menu"""
self.menu_expanded = True
self.animation_running = True
self.animate_menu()


def collapse_menu(self):
"""Start animation to collapse the side menu"""
self.menu_expanded = False
self.animation_running = True
self.animate_menu()



def animate_menu(self):
"""Handle the smooth animation of the side menu sliding in/out"""
# Target width is either full width or zero
# depending on if expanding/collapsing
target = self.target_width if self.menu_expanded else 0
def update():
"""Update function called repeatedly during animation"""
current_width = self.menu_container.winfo_width()
# Calculate the step size for smooth easing effect
if self.menu_expanded:
# When expanding, move faster when further from target
distance = target - current_width
step = max(1, int(distance * 0.2)) # At least 1 pixel
new_width = min(current_width + step, target)
else:
# When collapsing, move faster when further from zero
distance = current_width
step = max(1, int(distance * 0.2)) # At least 1 pixel
new_width = max(current_width - step, target)
# Update the menu width
self.menu_container.configure(width=new_width)
# Continue animation if not reached target
if new_width != target:
self.master.after(8, update) # Schedule next update
else:
self.animation_running = False # Animation complete

# Start the animation
update()




def main():
"""Main entry point of the application"""
root = tk.Tk()
app = HamburgerMenu(root)
root.mainloop()

if __name__ == "__main__":
main()



The Final Result:












Java - JTable inside a JTable Cell

How to Create a JTable Inside Another JTable In Java Netbeans





In this Java Tutorial we will see How To Create a JTable With a column containing nested tables representing sons and their ages In Netbeans.

What We Are Gonna Use In This Project:

- Java Programming Language.
- NetBeans Editor.
- FlatLaf (optional - a modern open-source cross-platform Look and Feel for Java Swing).

What This Project Do:

To visualize the nested tables within the main table, custom cell renderers (NestedTableRenderer) and editors (NestedTableEditor) are implemented. 
The NestedTableRenderer renders the cell with a JScrollPane containing a nested JTable when applicable, while the NestedTableEditor provides a JScrollPane with an editable nested JTable when editing is initiated.





Project Source Code:





package new_tutorials;

import java.awt.Component;
import javax.swing.AbstractCellEditor;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableModel;
import com.formdev.flatlaf.FlatDarculaLaf;
import javax.swing.UIManager;

/**
 *
 * @author 1BestCsharp
 */
public class Nested_JTable_Form extends JFrame {

    public Nested_JTable_Form(){
        setTitle("Nested JTable");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(600,600);
        setLocationRelativeTo(null);
        /*
        try{ UIManager.setLookAndFeel(new FlatDarculaLaf()); }
        catch(Exception ex){ System.err.println(ex.getMessage()); }
        */
        initializeGUI();
    }
    
    private void initializeGUI(){
        
        JTable table = new JTable(new ParentTableModel());
        table.setRowHeight(100);
        table.setShowHorizontalLines(true);
        table.setShowVerticalLines(true);
        table.getColumnModel().getColumn(2).setCellRenderer(new NestedTableRenderer());
        table.getColumnModel().getColumn(2).setCellEditor(new NestedTableEditor());
        
        JScrollPane scrollPane = new JScrollPane(table);
        add(scrollPane);
    }
    
    public static void main(String[] args) {
        new Nested_JTable_Form().setVisible(true);
    }
    
    
    // Define the main table model
    private class ParentTableModel extends AbstractTableModel{

        private final String[] columnNames = {"Name","Age","Sons"};
        private final Object[][] data = {
                {"John", 30, createSonTableModel("Son1", "Son2")},
                {"Jane", 25, createSonTableModel("Son3", "Son4", "Son5")},
                {"Michael", 35, createSonTableModel("Son6")},
                {"Emily", 28, createSonTableModel("Son7", "Son8")},
                {"Robert", 42, createSonTableModel("Son9", "Son10", "Son11","Son9", "Son10", "Son11","Son9", "Son10", "Son11")},
                {"John", 30, createSonTableModel("Son1", "Son2")},
                {"Jane", 25, createSonTableModel("Son3", "Son4", "Son5")},
                {"Michael", 35, createSonTableModel("Son6")},
                {"Emily", 28, createSonTableModel("Son7", "Son8")},
                {"Robert", 42, createSonTableModel("Son9", "Son10", "Son11","Son9", "Son10", "Son11","Son9", "Son10", "Son11")}
        };
        
        
        @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 columnIndex){
            
            return columnNames[columnIndex];
        }
        
        
        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex){
            return columnIndex == 2;
        }


        @Override
        public void setValueAt(Object value, int rowIndex, int columnIndex){
            
            data[rowIndex][columnIndex] = value;
            fireTableCellUpdated(rowIndex, columnIndex);
        }
        
       private SonTableModel createSonTableModel(String... sons){
       
           return new SonTableModel(sons);
       }
        
    }
    
    
    // Define the nested table model for sons
    private class SonTableModel extends AbstractTableModel{

        private final String[] columnNames = {"Name","Age"};
        private final Object[][] data;
        
        // The String... sons parameter allows you to pass an array of String arguments
        // or simply a comma-separated list of String values. 
        public SonTableModel(String... sons){
            // Populate the nested table with son data
            data = new Object[sons.length][columnNames.length];
            for(int i = 0; i < sons.length; i++){
                data[i][0] = sons[i];
                data[i][1] = (int)(Math.random() * 10 + 1);// Random age
            }
        }
        
        @Override
        public int getRowCount() { return data.length; }

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

        @Override
        public String getColumnName(int columnIndex){
            
            return columnNames[columnIndex];
        }
        
        
        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            
            return data[rowIndex][columnIndex];
        }
        
        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex)
        {
            return false;
        }
        
    }
    
    
    // Define the cell renderer for the nested table
    private class NestedTableRenderer extends DefaultTableCellRenderer{
        
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column){
        
            // Create and format the nested table
            if(value instanceof TableModel tableModel)
            {
                JTable nestedJTable = new JTable(tableModel);
                nestedJTable.setRowHeight(20);
                nestedJTable.setShowHorizontalLines(true);
                nestedJTable.setShowVerticalLines(true);
                return new JScrollPane(nestedJTable);
            }
            else
            {
                // Return the default cell renderer component
                return  super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            }
            
        }
        
    }
    
    
    // Define the cell editor for the nested table
    private class NestedTableEditor extends AbstractCellEditor implements TableCellEditor{

        private final JScrollPane scrollPane;
        private final JTable nestedJTable;
        
        public NestedTableEditor()
        {
            // Create the initial nested table and scroll pane
            nestedJTable = new JTable(new SonTableModel());
            nestedJTable.setRowHeight(20);
            nestedJTable.setShowHorizontalLines(true);
            nestedJTable.setShowVerticalLines(true);
            scrollPane = new JScrollPane(nestedJTable);
        }
        
        @Override // Return the model of the nested table
        public Object getCellEditorValue() { return  nestedJTable.getModel(); }

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
         // Update the nested table model with the current value
            if(value instanceof TableModel){
                nestedJTable.setModel((SonTableModel)value);
            }
            return scrollPane;
        }
        
    }
    
    
    
}


The Final Result: