Python To-Do List Project Source Code

How to Create To Do List Project In Python Tkinter


How to Create To Do List Project In Python Tkinter



In this Python Tutorial we will see How To Create a To Do List Project in Python using Tkinter.
This application provides a modern interface for managing tasks, allowing users to add, view, delete tasks, and Complete/Completed toggle button .

What We Are Gonna Use In This Project:

- Python Tkinter: GUI framework.
- Visual Studio Editor.





Project Source Code:



     - Build the user interface

Calculates screen dimensions and positions the application window at the center of the user's display.


def center_window(self):
"""Center the window on the screen."""
# Get screen dimensions
screen_width = self.root.winfo_screenwidth()
screen_height = self.root.winfo_screenheight()

# Calculate position
x = (screen_width - 900) // 2
y = (screen_height - 600) // 2

# Set window position
self.root.geometry(f"900x600+{x}+{y}")



     - Custom Window

Creates a custom title bar with application branding and window controls, replacing the default system title bar.


def setup_title_bar(self):
"""Create custom title bar with controls."""
self.title_bar = tk.Frame(self.root, bg=self.special_color, height=40)
self.title_bar.pack(fill=tk.X)

# Application title
title = tk.Label(self.title_bar, text="Tasks Manager",
font=self.title_font,
bg=self.special_color, fg="white")
title.pack(side=tk.LEFT, padx=15)

# Window controls container
controls = tk.Frame(self.title_bar, bg=self.special_color)
controls.pack(side=tk.RIGHT, padx=5)

# Control buttons
buttons = [
("□", lambda: self.toggle_maximize(), "#64748b"),
("x", lambda: self.root.destroy(), "#ef4444")
]

for symbol, command, hover_color, in buttons:
btn = tk.Label(controls, text=symbol, bg=self.special_color,
fg="white", font=self.title_font, padx=10)
btn.pack(side=tk.LEFT)
# Hover effects
btn.bind("<Enter>", lambda e,
color=hover_color: e.widget.configure(bg=color))
btn.bind("<Leave>", lambda e: e.widget.configure(bg=self.special_color))
btn.bind("<Button-1>", lambda e, cmd=command: cmd())



     - Window State Management

Toggles between maximized and normal window states when users click the maximize button.


def toggle_maximize(self):
"""Toggle between maximized and normal window state."""
if self.root.state() == 'zoomed':
self.root.state('normal')

else:
self.root.state('zoomed')



     - Bottom Control Panel

Creates the bottom action bar containing the primary "Add New Task" button with hover animations.


def setup_action_bar(self):
"""Create the bottom action bar with controls."""
action_bar = tk.Frame(self.root, bg=self.bg_color, height=60)
action_bar.pack(fill=tk.X, padx=20, pady=(0, 20))

# Add task button
add_btn = tk.Button(action_bar, text="+ Add New Task",
font=self.button_font, bg=self.special_color,
fg="white", border=0, padx=20, pady=10,
command=self.add_task, cursor="hand2")
add_btn.pack(side=tk.LEFT)

# Hover effect
add_btn.bind("<Enter>", lambda e: e.widget.configure(bg="#1d4ed8"))
add_btn.bind("<Leave>", lambda e: e.widget.configure(bg=self.special_color))



     - Drag Functionality Setup

Configures mouse event bindings to enable window dragging from the title bar.


def setup_window_drag(self):
"""Configure window dragging functionality."""
self.title_bar.bind("<Button-1>", self.on_drag_start)
self.title_bar.bind("<B1-Motion>", self.on_drag_motion)



     - Drag Initialization

Captures initial mouse coordinates when the user starts dragging the window.


def on_drag_start(self, event):
"""Store initial coordinates when starting drag."""
self.drag_data = (event.x_root - self.root.winfo_x(),
event.y_root - self.root.winfo_y())



     - Drag Position Updates

Continuously updates window position as the user drags the mouse across the screen.


def on_drag_motion(self, event):
"""Update window position during drag."""
x = event.x_root - self.drag_data[0]
y = event.y_root - self.drag_data[1]
self.root.geometry(f"+{x}+{y}")



     - Scrollable Content Area

Creates a scrollable canvas system for displaying task cards when content exceeds window height.


def setup_scrollable_canvas(self):
"""Create a scrollable canvas for task cards."""
# Create canvas with scrollbar
self.canvas =tk.Canvas(self.content_frame, bg=self.bg_color,
highlightthickness=0)
scrollbar = ttk.Scrollbar(self.content_frame, orient="vertical",
command=self.canvas.yview)
# Configure canvas scroll region
self.canvas.configure(yscrollcommand=scrollbar.set)
# Create frame for task cards
self.dashboard_panel = tk.Frame(self.canvas, bg=self.bg_color)

# Pack elements
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

# Create window in canvas for dashboard
self.canvas_window = self.canvas.create_window((0,0),
window=self.dashboard_panel, anchor="nw")

# Configure canvas scrolling
self.canvas.bind("<Configure>", self.on_canvas_configure)
self.dashboard_panel.bind("<Configure>", self.on_frame_configure)
self.canvas.bind_all("<MouseWheel>", self.on_mousewheel)



     - Canvas Resize Handler

Updates the canvas scroll region and content width when the canvas is resized.


def on_canvas_configure(self, event):
"""Update canvas scroll region when canvas is configured."""
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
width = event.width
self.canvas.itemconfig(self.canvas_window, width=width)



     - Frame Resize Handler

Recalculates scroll boundaries when the inner frame content changes size.


def on_frame_configure(self, event):
"""Update canvas scroll region when frame is configured."""
self.canvas.configure(scrollregion=self.canvas.bbox("all"))



     - Mouse Wheel Scrolling

Enables mouse wheel scrolling through the task list.


def on_mousewheel(self, event):
"""Handle mouse wheel scrolling."""
self.canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")



     - Task Creation

Handles new task creation with validation, modal dialog presentation, and task limit enforcement (12-task maximum limit).


def add_task(self):
"""Add a new task with modern dialog."""
if len(self.tasks) >= 12:
self.show_error("Maximum Tasks Reached",
                            "Please Complete Tasks Before Adding New Ones")
return
dialog = ModernInputDialog(self.root, "Add New Task", "Enter task details")
self.root.wait_window(dialog)

if dialog.result:
task = {
'text': dialog.result,
'date': datetime.now().strftime("%b %d, %Y"),
'status':'pending'
}
self.tasks.append(task)
self.update_task_panel()


     - UI Refresh

Rebuilds the entire task display panel, organizing tasks into horizontal tiers with proper spacing.


def update_task_panel(self):
"""Refresh the task display with styling."""
for widget in self.dashboard_panel.winfo_children():
widget.destroy()

for i, task in enumerate(self.tasks):
if i % self.tasks_per_tier == 0:
tier_frame = tk.Frame(self.dashboard_panel, bg = self.bg_color)
tier_frame.pack(fill = tk.X, pady = (10, 0))
self.create_task_card(tier_frame, task)



     - Individual Task UI

Generates individual task cards with completion status, action buttons, and custom styling.


def create_task_card(self, parent, task):
"""Create a task card with completion status."""
card = tk.Frame(parent, bg=self.card_bg, padx = 15, pady = 15,
highlightthickness = 1,
highlightbackground = "#e2eff0")
card.pack(side=tk.LEFT, padx = 10, pady = 10,
fill=tk.BOTH, expand=True)

header = tk.Frame(card, bg = self.card_bg)
header.pack(fill=tk.X, pady=(0, 10))

# Use completed font if task is marked as completed
task_font = self.completed_font if task.get('completed', False)
else self.text_font
task_label = tk.Label(header, text = task['text'],
font = task_font, bg = self.card_bg,
fg = self.text_color, wraplength = 200,
justify = tk.LEFT)
task_label.pack(side = tk.LEFT, anchor = "w")

tk.Label(card, text = task['date'], font = ("Helvatica", 9),
bg = self.card_bg, fg = "#64748b").pack(anchor="w")

btn_frame = tk.Frame(card, bg = self.card_bg)
btn_frame.pack(fill = tk.X, pady = (10, 0))

# Change complete button text based on completion status
complete_text = "✓ Completed" if task.get('completed', False)
else "✓ Complete"

complete_btn = tk.Button(btn_frame, text = complete_text,
font = self.button_font,
bg = "#22c55e" if not task.get('completed', False)
else "#64748b",
fg="white", border = 0, padx = 10, pady = 5,
command = lambda: self.toggle_complete_task(
task, task_label, complete_btn))

complete_btn.pack(side = tk.LEFT, padx = (0, 5))

delete_btn = tk.Button(btn_frame, text = "Delete",
font = self.button_font, bg = "#ef4444",
fg="white", border= 0, padx = 10, pady = 5,
command = lambda: self.delete_task(task))

delete_btn.pack(side = tk.LEFT)

for btn, hover_color in [(complete_btn, "#16a34a"), (delete_btn, "#dc2626")]:
btn.bind("<Enter>", lambda e,
color = hover_color: e.widget.configure(bg=color))
btn.bind("<Leave>", lambda e, btn = btn: self.reset_button_color(e, btn))



     - Task Status Management

Handles task completion toggling with success notifications.


def toggle_complete_task(self, task, label, button):
"""Toggle task completion status."""
task['completed'] = not task.get('completed', False)

if task['completed']:
label.configure(font = self.completed_font)
button.configure(text = "✓ Completed", bg="#64748b")
self.show_success("Task Completed", "Grate job completing your task !")
else:
label.configure(font = self.text_font)
button.configure(text = "✓ Complete", bg="#22c55e")



     - Hover State Management

Manages button color states after hover events end.


def reset_button_color(self, event, button):
"""Reset button color after hover."""
if "Complete" in button['text']:
if "Completed" in button['text']:
button.configure(bg = "#64748b")
else:
button.configure(bg = "#22c55e")
else:
button.configure(bg = "#ef4444")



     - Task Removal

Removes tasks from the data structure and triggers UI refresh.


def delete_task(self, task):
"""Remove a task and update display."""
self.tasks.remove(task)
self.update_task_panel()



     - User Notifications

Display system notifications for errors and successful actions using standard message boxes.


def show_error(self, title, message):
"""Display error message"""
messagebox.showerror(title, message)

def show_success(self, title, message):
"""Display error message"""
messagebox.showinfo(title, message)


     - ModernInputDialog Class - Custom Modal Dialog

Display system notifications for errors and successful actions using standard message boxes.


class ModernInputDialog(tk.Toplevel):
"""Custom modern dialog for task input."""
def __init__(self, parent, title, prompt):
super().__init__(parent)

self.result = None

# Configure dialog window
self.title(title)
self.geometry("400x250")
self.configure(bg="#ffffff")
self.resizable(False, False)
self.overrideredirect(True)
self.attributes('-alpha', 0.0)

self.center_on_parent(parent)

self.container = tk.Frame(self, bg="#ffffff",
highlightthickness=1,
highlightbackground="#e2e8f0",
padx=20, pady=20)
self.container.pack(fill=tk.BOTH, expand=True)

title_bar = tk.Frame(self.container, bg="#ffffff")
title_bar.pack(fill=tk.X, pady=(0, 15))

tk.Label(title_bar, text = title, font=("Helvatica", 14, "bold"),
bg="#ffffff",
fg="#1e293b").pack(side=tk.LEFT)

close_btn = tk.Label(title_bar, text = "×", font=("Helvetica", 14),
bg="#ffffff", fg="#64748b", cursor="hand2")
close_btn.pack(side=tk.RIGHT)
close_btn.bind("<Button-1>", lambda e: self.cancel())

tk.Label(self.container, text = prompt, font=("Helvetica", 11),
bg="#ffffff", fg="#1e293b").pack(fill=tk.X)
entry_frame = tk.Frame(self.container, bg="#f1f5f9",
highlightthickness=1,
highlightbackground="#e2e8f0")
entry_frame.pack(fill=tk.X, pady=(10, 20))

self.entry = tk.Entry(entry_frame, font=("Helvetica", 12),
bd=0, bg="#f1f5f9", fg="#1e2936",
insertbackground="#2563eb")
self.entry.pack(fill=tk.X, padx=10, pady=8)
self.entry.focus_set()

btn_frame = tk.Frame(self.container, bg="#ffffff")
btn_frame.pack(fill=tk.X, pady=(0, 10))

# Create modern styled buttons
buttons = [
("Cancel", "#f1f2f9", "#64748b", self.cancel),
("Add Task", "#2563eb", "#ffffff", self.submit)
]

for text, bg, fg, command in buttons:
btn = tk.Button(btn_frame, text=text, font=("Helvetica", 12),
bg=bg, fg=fg, bd=0, padx=20, pady=8, cursor="hand2",
command=command)
btn.pack(side=tk.RIGHT, padx=5)

# Add hover effects
if text == "cancel":
btn.bind("<Enter>", lambda e: e.widget.configure(bg="#e2e8f0"))
btn.bind("<Leave>", lambda e: e.widget.configure(bg="#f1f5f9"))
else:
btn.bind("<Enter>", lambda e: e.widget.configure(bg="#1d4ed8"))
btn.bind("<Leave>", lambda e: e.widget.configure(bg="#2563eb"))

# Add key bindings
self.bind("<Return>", lambda e: self.submit())
self.bind("<Escape>", lambda e: self.cancel())


# Make dialog draggable
title_bar.bind("<Button-1>", self.start_drag)
title_bar.bind("<B1-Motion>", self.drag)

# Fade in animation
self.fade_in()


def fade_in(self):
"""Animate the dialog fading in."""
alpha = self.attributes("-alpha")
if alpha < 1.0:
alpha += 0.1
self.attributes("-alpha", alpha)
self.after(20, self.fade_in)

def fade_out(self):
"""Animate the dialog fading out."""
alpha = self.attributes("-alpha")
if alpha > 0:
alpha -= 0.1
self.attributes("-alpha", alpha)
self.after(20, self.fade_out)
else:
self.destroy()

def submit(self):
"""Handle dialog submission with fade out animation."""
self.result = self.entry.get()
self.fade_out()

def cancel(self):
"""Handle dialog cancellation with fade out animation."""
self.fade_out()

def center_on_parent(self, parent):
"""Center the dialog window on its parent."""
# Get parent window position and size
parent_x = parent.winfo_x()
parent_y = parent.winfo_y()
parent_width = parent.winfo_width()
parent_height = parent.winfo_height()

# Calculate center position
x = parent_x + (parent_width - 400) // 2
y = parent_y + (parent_height - 250) // 2

# Set dialog position
self.geometry(f"400x250+{x}+{y}")


def start_drag(self, event):
"""Store initial coordinates for window dragging."""
self.drag_data = (event.x_root - self.winfo_x(), event.y_root - self.winfo_y())

def drag(self, event):
"""Update window position during drag."""
x = event.x_root - self.drag_data[0]
y = event.y_root - self.drag_data[1]
self.geometry(f"+{x}+{y}")






The Final Result:

Python To-Do List Project Source Code

Python To-Do List Project

Python To-Do List Project In Tkinter

To-Do List Project In Python Tkinter

To-Do List App In Python Tkinter

Tasks Project In Python Tkinter



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











3D Domino in Java Swing

How to Create a 3D Domino in Java Netbeans

How to Create a 3D Domino in Java Netbeans


In this Java Tutorial we will see How To Create a 3D Dominp Piece that rotates, floats, and responds to user input In Java Using Netbeans.

What We Are Gonna Use In This Project:

- Java Programming Language.
- NetBeans Editor.





Project Source Code:



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

    // Rotation angles for the 3D domino
    private double currentRotationX = -30;   // Current X-axis rotation in degrees
    private double currentRotationY = 45;    // Current Y-axis rotation in degrees
        
    // Target angles that the domino will animate towards
    private double targetRotationX = -30;    // Target X-axis rotation
    private double targetRotationY = 45;     // Target Y-axis rotation
    
    // Animation properties
    private final double ROTATION_SPEED = 0.15;  // Speed of rotation animation
    private boolean isAnimating = false;         // Flag to track if animation is in progress
    
    // Mouse handling properties
    private boolean isDragging = false;      // Flag to track if user is dragging the domino
    private Point previousPoint;             // Previous mouse position for drag calculations
        
    // Domino properties
    private int topValue = 6;                // Number on top half of domino (1-6)
    private int bottomValue = 3;             // Number on bottom half of domino (1-6)
    private Color dominoColor = new Color(250, 250, 250);  // Main domino color
    private Color dotColor = new Color(20, 20, 20);        // Color of dots on domino
    private Color dividerColor = new Color(40, 40, 40);    // Color of center dividing line
        
    // Domino dimensions
    private static final double DOMINO_WIDTH = 120;    // Width of domino
    private static final double DOMINO_HEIGHT = 240;   // Height of domino
    private static final double DOMINO_DEPTH = 25;     // Depth of domino
        
    // Floating animation properties
    private Timer animationTimer;            // Timer for animation updates
    private double floatOffset = 0;          // Current vertical offset for floating effect
    private boolean floatingUp = true;       // Direction of floating animation

    // Drawing panel
    private DominoPanel dominoPanel;         // Panel where the domino is drawn
    
     /**
     * Constructor: Sets up the application window and initializes components
     */
     public Domino3D(){
         
            // Set up the main window
            setTitle("Modern Domino");
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setLayout(new BorderLayout());
        
            // Create the panel where domino will be drawn
            dominoPanel = new DominoPanel();
            dominoPanel.setPreferredSize(new Dimension(800, 600));
            dominoPanel.setBackground(new Color(15, 15, 15));
            add(dominoPanel, BorderLayout.CENTER);

            // Create and add control buttons
            JPanel controlPanel = createControlPanel();
            add(controlPanel, BorderLayout.SOUTH);

            // Set up mouse event handlers
            setupMouseListeners();

            // Start animation timer
            startAnimation();

            // Finalize window setup
            pack();
            setLocationRelativeTo(null);  // Center on screen
     }
    
     
     
    /**
     * Creates the control panel with buttons
     */
    private JPanel createControlPanel() {
        // Create panel with dark background and padding
        JPanel panel = new JPanel();
        panel.setBackground(new Color(30, 30, 30));
        panel.setBorder(new EmptyBorder(15, 15, 15, 15));
        panel.setLayout(new FlowLayout(FlowLayout.CENTER, 15, 0));
        
        // Create buttons for rotation
        JButton rotateXButton = createControlButton("Rotate X");
        JButton rotateYButton = createControlButton("Rotate Y");
        
        // Add action to rotate around X axis
        rotateXButton.addActionListener(e -> {
            targetRotationX += 90;  // Rotate 90 degrees around X axis
            isAnimating = true;
        });
        
        // Add action to rotate around Y axis
        rotateYButton.addActionListener(e -> {
            targetRotationY += 90;  // Rotate 90 degrees around Y axis
            isAnimating = true;
        });
        
        // Add buttons to panel
        panel.add(rotateXButton);
        panel.add(rotateYButton);
        
        return panel;
        
    }
     
     
     
    /**
     * Creates a styled button with hover effects
     */
    private JButton createControlButton(String text) {
        // Create button with text
        JButton button = new JButton(text);
        
        // Style the button
        button.setForeground(Color.WHITE);
        button.setBackground(new Color(60, 60, 60));
        button.setFocusPainted(false);
        button.setBorderPainted(false);
        button.setFont(new Font("SansSerif", Font.BOLD, 14));
        button.setPreferredSize(new Dimension(120, 40));
        
        // Add hover and click effects
        button.addMouseListener(new MouseAdapter() {
            // Change appearance when mouse enters button area
            @Override
            public void mouseEntered(MouseEvent e) {
                button.setBackground(new Color(80, 80, 80));
                button.setCursor(new Cursor(Cursor.HAND_CURSOR));
            }
            
            // Restore appearance when mouse leaves button area
            @Override
            public void mouseExited(MouseEvent e) {
                button.setBackground(new Color(60, 60, 60));
                button.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
            }
             
            // Pressed
            @Override
            public void mousePressed(MouseEvent e) {
                button.setBackground(new Color(100, 100, 100));
            }
            
            // Released
            @Override
            public void mouseReleased(MouseEvent e) {
                button.setBackground(new Color(80, 80, 80));
            }
            
        });
        
        return button;
        
    }
     
    
        
    /**
     * Sets up mouse listeners for rotating the domino with drag actions
     */
    private void setupMouseListeners() {
        // Handle mouse press and release
        dominoPanel.addMouseListener(new MouseAdapter() {
            // Start tracking drag when mouse is pressed
            @Override
            public void mousePressed(MouseEvent e) {
                isDragging = true;
                previousPoint = e.getPoint();  // Store initial mouse position
                dominoPanel.setCursor(new Cursor(Cursor.MOVE_CURSOR));
            }
            
            // Stop tracking drag when mouse is released
            @Override
            public void mouseReleased(MouseEvent e) {
                isDragging = false;
                dominoPanel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
            }
            
        });
        
        // Handle mouse drag motion
        dominoPanel.addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                if (isDragging) {
                    
                    Point currentPoint = e.getPoint();
                    
                    // Calculate how far mouse has moved since last position
                    double deltaX = currentPoint.x - previousPoint.x;
                    double deltaY = currentPoint.y - previousPoint.y;
                    
                    // Apply rotations based on mouse movement
                    targetRotationY += deltaX * 0.5;  // Horizontal motion rotates Y
                    targetRotationX += deltaY * 0.5;  // Vertical motion rotates X
                    
                    previousPoint = currentPoint;  // Update previous position
                    dominoPanel.repaint();  // Redraw with new rotation
                }
                
            }
            
        });
        
    }
    
    
    /**
     * Starts the animation timer for continuous updates
     */
    private void startAnimation() {
        // Create timer that updates every 16ms
        animationTimer = new Timer(16, e -> {
            // Handle floating animation (gentle up and down movement)
            if (floatingUp) {
                floatOffset += 0.15;  // Move up
                if (floatOffset >= 8) floatingUp = false;  // Change direction at peak
            } else {
                floatOffset -= 0.15;  // Move down
                if (floatOffset <= -8) floatingUp = true;  // Change direction at bottom
            }
            
            // Handle rotation animation
            boolean needsUpdate = false;
            
            // Smoothly animate X rotation toward target
            if (Math.abs(targetRotationX - currentRotationX) > 0.1) {
                currentRotationX += (targetRotationX - currentRotationX) * ROTATION_SPEED;
                needsUpdate = true;
            } else {
                currentRotationX = targetRotationX;  // Snap to exact target when close
            }
            
            // Smoothly animate Y rotation toward target
            if (Math.abs(targetRotationY - currentRotationY) > 0.1) {
                currentRotationY += (targetRotationY - currentRotationY) * ROTATION_SPEED;
                needsUpdate = true;
            } else {
                currentRotationY = targetRotationY;  // Snap to exact target when close
            }
            
            // Repaint if anything changed
            if (needsUpdate || floatingUp || !floatingUp) {
                dominoPanel.repaint();
            } else if (isAnimating) {
                isAnimating = false;  // Animation complete
            }
            
        });
        
        animationTimer.start();  // Start the timer
        
    }
    
     
    
     /**
     * Inner class for drawing the 3D domino
     * This handles all the 3D rendering of the domino
     */
    class DominoPanel extends JPanel {
        // 3D coordinates of domino vertices for each face
        private double[][][] faceVertices;
        
        // Constants for face indices
        private static final int FRONT = 0;
        private static final int BACK = 1;
        private static final int RIGHT = 2;
        private static final int LEFT = 3;
        private static final int TOP = 4;
        private static final int BOTTOM = 5;
        
        // Array of dot positions for each domino value (1-6)
        private final Point2D.Double[][] dotPositions = {
            {}, // 0 (not used)
            {new Point2D.Double(0.5, 0.5)}, // 1: center dot
            {new Point2D.Double(0.25, 0.25), new Point2D.Double(0.75, 0.75)}, // 2: diagonal dots
            {new Point2D.Double(0.25, 0.25), new Point2D.Double(0.5, 0.5), new Point2D.Double(0.75, 0.75)}, // 3: diagonal + center
            {new Point2D.Double(0.25, 0.25), new Point2D.Double(0.25, 0.75), 
             new Point2D.Double(0.75, 0.25), new Point2D.Double(0.75, 0.75)}, // 4: corners
            {new Point2D.Double(0.25, 0.25), new Point2D.Double(0.25, 0.75), new Point2D.Double(0.5, 0.5), 
             new Point2D.Double(0.75, 0.25), new Point2D.Double(0.75, 0.75)}, // 5: corners + center
            {new Point2D.Double(0.25, 0.25), new Point2D.Double(0.25, 0.5), new Point2D.Double(0.25, 0.75), 
             new Point2D.Double(0.75, 0.25), new Point2D.Double(0.75, 0.5), new Point2D.Double(0.75, 0.75)} // 6: 2 columns of 3
        };
        
        /**
         * Constructor: Initialize the panel and vertex coordinates
         */
        public DominoPanel() {
                initFaceVertices();  // Set up 3D coordinates
                setCursor(new Cursor(Cursor.HAND_CURSOR));  // Show hand cursor by default
          }
        
        /**
         * Initialize the 3D coordinates for each face of the domino
         * This sets up the positions of all vertices in 3D space
         */
        private void initFaceVertices() {
            
            // Create 3D array: [face][vertex][coordinate]
            faceVertices = new double[6][4][3];
            
            // Calculate half dimensions for easier positioning
            double w = DOMINO_WIDTH / 2.0;
            double h = DOMINO_HEIGHT / 2.0;
            double d = DOMINO_DEPTH / 2.0;
            
            // FRONT face vertices (clockwise from top-left)
            faceVertices[FRONT][0] = new double[]{-w, -h, d};  // Top-left
            faceVertices[FRONT][1] = new double[]{w, -h, d};   // Top-right
            faceVertices[FRONT][2] = new double[]{w, h, d};    // Bottom-right
            faceVertices[FRONT][3] = new double[]{-w, h, d};   // Bottom-left
            
            // BACK face vertices (clockwise from top-left)
            faceVertices[BACK][0] = new double[]{w, -h, -d};    // Top-left
            faceVertices[BACK][1] = new double[]{-w, -h, -d};   // Top-right
            faceVertices[BACK][2] = new double[]{-w, h, -d};    // Bottom-right
            faceVertices[BACK][3] = new double[]{w, h, -d};     // Bottom-left
            
            // RIGHT face vertices
            faceVertices[RIGHT][0] = new double[]{w, -h, d};    // Top-front
            faceVertices[RIGHT][1] = new double[]{w, -h, -d};   // Top-back
            faceVertices[RIGHT][2] = new double[]{w, h, -d};    // Bottom-back
            faceVertices[RIGHT][3] = new double[]{w, h, d};     // Bottom-front
            
            // LEFT face vertices
            faceVertices[LEFT][0] = new double[]{-w, -h, -d};   // Top-back
            faceVertices[LEFT][1] = new double[]{-w, -h, d};    // Top-front
            faceVertices[LEFT][2] = new double[]{-w, h, d};     // Bottom-front
            faceVertices[LEFT][3] = new double[]{-w, h, -d};    // Bottom-back
            
            // TOP face vertices
            faceVertices[TOP][0] = new double[]{-w, -h, -d};    // Left-back
            faceVertices[TOP][1] = new double[]{w, -h, -d};     // Right-back
            faceVertices[TOP][2] = new double[]{w, -h, d};      // Right-front
            faceVertices[TOP][3] = new double[]{-w, -h, d};     // Left-front
            
            // BOTTOM face vertices
            faceVertices[BOTTOM][0] = new double[]{-w, h, d};    // Left-front
            faceVertices[BOTTOM][1] = new double[]{w, h, d};     // Right-front
            faceVertices[BOTTOM][2] = new double[]{w, h, -d};    // Right-back
            faceVertices[BOTTOM][3] = new double[]{-w, h, -d};   // Left-back
        }
        
        
        /**
         * Paint the domino on the panel
         * This is called automatically whenever the panel needs to be redrawn
         */
        @Override
        protected void paintComponent(Graphics g) {
            
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g;
                
                // Enable antialiasing for smoother edges
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
                        RenderingHints.VALUE_ANTIALIAS_ON);
                g2d.setRenderingHint(RenderingHints.KEY_RENDERING, 
                        RenderingHints.VALUE_RENDER_QUALITY);
                
                // Draw background gradient
                GradientPaint bgGradient = new GradientPaint(
                    0, 0, new Color(25, 25, 30),  // Start color (top)
                    getWidth(), getHeight(), new Color(10, 10, 15)  // End color (bottom)
                );
                g2d.setPaint(bgGradient);
                g2d.fillRect(0, 0, getWidth(), getHeight());  // Fill entire panel

                // Find center of panel
                int centerX = getWidth() / 2;
                int centerY = getHeight() / 2;

                // Apply floating animation effect
                double scaleFloat = 1.0 + Math.abs(floatOffset) / 100.0;  // Subtle scale change

                // Move to center and apply floating offset
                g2d.translate(centerX, centerY + floatOffset);
                g2d.scale(scaleFloat, scaleFloat);  // Scale slightly based on float position

                // Calculate which faces are visible from current angle
                int[] faceVisibility = calculateFaceVisibility();

                // Draw faces in back-to-front order
                for (int i = 0; i < 6; i++) {
                    drawFace(g2d, faceVisibility[i]);
                }

        }
        
        
        
        /**
         * Calculate which order to draw faces based on current rotation
         * This is important for correct depth perception (back faces drawn first)
         */
        
        private int[] calculateFaceVisibility() {
            // Calculate center point of each face after rotation
            double[][] faceCenters = new double[6][3];
            for (int face = 0; face < 6; face++) {
                double[] center = {0, 0, 0};
                // Average the 4 corners to find center
                for (int i = 0; i < 4; i++) {
                    center[0] += faceVertices[face][i][0];  // x
                    center[1] += faceVertices[face][i][1];  // y
                    center[2] += faceVertices[face][i][2];  // z
                }
                // Divide by 4 to get average
                center[0] /= 4;
                center[1] /= 4;
                center[2] /= 4;
                
                // Apply current rotation to center point
                faceCenters[face] = rotatePoint(center);
                
            }
            
            // Sort faces by z-coordinate (back to front)
            int[] faceOrder = {0, 1, 2, 3, 4, 5};
            for (int i = 0; i < 5; i++) {
                for (int j = i + 1; j < 6; j++) {
                    if (faceCenters[faceOrder[i]][2] > faceCenters[faceOrder[j]][2]) {
                        // Swap if wrong order
                        int temp = faceOrder[i];
                        faceOrder[i] = faceOrder[j];
                        faceOrder[j] = temp;
                    }
                    
                }
                
            }
            
            return faceOrder;
        }
        
        
        /**
         * Draw a single face of the domino
         * This handles the drawing of one complete face with all its details
         */
        private void drawFace(Graphics2D g2d, int face) {
            // Project 3D points to 2D for drawing
            Point2D.Double[] projectedPoints = new Point2D.Double[4];
            for (int i = 0; i < 4; i++) {
                // Apply rotation to each point
                double[] rotated = rotatePoint(faceVertices[face][i]);
                
                // Apply perspective scale (farther = smaller)
                double scale = 1.2 + rotated[2] / 1000.0;
                
                // Convert to 2D coordinates
                projectedPoints[i] = new Point2D.Double(
                        rotated[0] * scale,
                        rotated[1] * scale
                );
                
            }
            
            // Create path for the face
            Path2D.Double facePath = new Path2D.Double();
            facePath.moveTo(projectedPoints[0].x, projectedPoints[0].y);
            for (int i = 1; i < 4; i++) {
                facePath.lineTo(projectedPoints[i].x, projectedPoints[i].y);
            }
            facePath.closePath();
            
            // Draw differently based on which face it is
            if (face == FRONT || face == BACK) {
                // Draw the main face with gradient
                GradientPaint faceGradient = new GradientPaint(
                    (float)projectedPoints[0].x, (float)projectedPoints[0].y, 
                    brightenColor(dominoColor, 0.1f),  // Lighter at top
                    (float)projectedPoints[2].x, (float)projectedPoints[2].y, 
                    darkenColor(dominoColor, 0.1f)     // Darker at bottom
                );
                g2d.setPaint(faceGradient);
                g2d.fill(facePath);
                
                // Draw the dividing line between top and bottom halves
                Point2D.Double leftMiddle = new Point2D.Double(
                    (projectedPoints[0].x + projectedPoints[3].x) / 2,  // Middle of left edge
                    (projectedPoints[0].y + projectedPoints[3].y) / 2
                );
                Point2D.Double rightMiddle = new Point2D.Double(
                    (projectedPoints[1].x + projectedPoints[2].x) / 2,  // Middle of right edge
                    (projectedPoints[1].y + projectedPoints[2].y) / 2
                );
                
                // Draw divider line
                g2d.setColor(dividerColor);
                g2d.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
                g2d.draw(new Line2D.Double(leftMiddle, rightMiddle));
                
                if (face == FRONT) {
                    // Draw dots on front face
                    drawDots(g2d, projectedPoints[0], projectedPoints[1], leftMiddle, topValue);
                    drawDots(g2d, leftMiddle, rightMiddle, projectedPoints[3], bottomValue);
                } else {
                    // Draw dots on back face (reversed order)
                    drawDots(g2d, projectedPoints[0], projectedPoints[1], leftMiddle, bottomValue);
                    drawDots(g2d, leftMiddle, rightMiddle, projectedPoints[3], topValue);
                }
                
            } else {
                // Draw side faces with gradient
                GradientPaint faceGradient = new GradientPaint(
                    (float)projectedPoints[0].x, (float)projectedPoints[0].y, 
                    brightenColor(dominoColor, 0.1f),
                    (float)projectedPoints[2].x, (float)projectedPoints[2].y, 
                    darkenColor(dominoColor, 0.1f)
                );
                g2d.setPaint(faceGradient);
                g2d.fill(facePath);
                
            }
            
            // Draw face border
            g2d.setColor(new Color(40, 40, 40, 100));
            g2d.setStroke(new BasicStroke(1.5f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
            g2d.draw(facePath);
            
        }
        
        
        
        /**
         * Draw the dots on a face section
         * This places the dots in the correct positions on each half of the domino
         */
        private void drawDots(Graphics2D g2d, Point2D.Double topLeft, Point2D.Double topRight, 
                             Point2D.Double bottomLeft, int value) {
            
            if (value < 1 || value > 6) return;  // Invalid value
            
            // Calculate dot size based on face dimensions
            double width = topRight.distance(topLeft);
            double height = bottomLeft.distance(topLeft);
            double dotSize = Math.min(width, height) * 0.15;  // Size relative to face
            
            // Draw each dot for this value
            for (Point2D.Double pos : dotPositions[value]) {
                // Calculate dot position using relative coordinates
                double x = topLeft.x + (topRight.x - topLeft.x) * pos.x + (bottomLeft.x - topLeft.x) * pos.y;
                double y = topLeft.y + (topRight.y - topLeft.y) * pos.x + (bottomLeft.y - topLeft.y) * pos.y;
                
                // Create gradient for dot
                RadialGradientPaint dotGradient = new RadialGradientPaint(
                    new Point2D.Double(x - dotSize/4, y - dotSize/4),  // Offset for 3D effect
                    (float)dotSize,
                    new float[]{0.0f, 1.0f},
                    new Color[]{brightenColor(dotColor, 0.3f), dotColor}  // Lighter center, darker edges
                );
                
                // Draw dot
                g2d.setPaint(dotGradient);
                g2d.fill(new Ellipse2D.Double(x - dotSize/2, y - dotSize/2, dotSize, dotSize));
                
                // Add subtle border to dot
                g2d.setColor(new Color(0, 0, 0, 50));
                g2d.draw(new Ellipse2D.Double(x - dotSize/2, y - dotSize/2, dotSize, dotSize));
            }
        }
        
        
        /**
         * Apply rotation transformations to a 3D point
         * This converts a 3D point based on the current rotation angles
         */
        private double[] rotatePoint(double[] point) {
            double[] result = new double[3];
            double[] temp = new double[3];
            
            // Convert degrees to radians for math functions
            double radX = Math.toRadians(currentRotationX);
            double radY = Math.toRadians(currentRotationY);
            
            // Copy point
            System.arraycopy(point, 0, temp, 0, 3);
            
            // X rotation
            result[0] = temp[0];
            result[1] = temp[1] * Math.cos(radX) - temp[2] * Math.sin(radX);
            result[2] = temp[1] * Math.sin(radX) + temp[2] * Math.cos(radX);
            
            System.arraycopy(result, 0, temp, 0, 3);
            
            // Y rotation
            result[0] = temp[0] * Math.cos(radY) + temp[2] * Math.sin(radY);
            result[1] = temp[1];
            result[2] = -temp[0] * Math.sin(radY) + temp[2] * Math.cos(radY);
            
            System.arraycopy(result, 0, temp, 0, 3);
            
            return result;
        }
        
          
        private Color brightenColor(Color color, float factor) {
            float[] hsb = Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), null);
            float brightness = Math.min(1.0f, hsb[2] + factor);
            return Color.getHSBColor(hsb[0], hsb[1], brightness);
        }
        
        private Color darkenColor(Color color, float factor) {
            float[] hsb = Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), null);
            float brightness = Math.max(0.0f, hsb[2] - factor);
            return Color.getHSBColor(hsb[0], hsb[1], brightness);
        }
        
    
    }
     
     
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (Exception e) {
                e.printStackTrace();
            }
            new Domino3D().setVisible(true);
        });
    }
    
}


  


The Final Result:

3D Domino in Java Netbeans

How to Create a 3D Domino Piece in Java

How to Create a 3D Domino Piece in Java Swing

3D Domino Piece in Java Swing



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