How to Create a Collapsing Sidebar Menu in Java Netbeans
In this Java Tutorial we will see How To Create a collapsing sidebar in Java Swing with smooth animations, hover effects and custom icons, ideal for dashboards and admin panels. Built using NetBeans.
What We Will Make:
- Expand And Collapse animations.
- Custom button.
- Hover animations.
- Custom tooltip with arrow pointers.
- Icons design using Java2D graphics.
What We Are Gonna Use In This Project:
- Java Programming Language.- NetBeans Editor.
Project Source Code:
/**
*
* @author 1BestCsharp
*/
public class Collapsing_Sidebar extends JPanel{
// These arrays control the hover animation for each menu item
private final Timer[] hoverTimers = new Timer[6]; // One timer for each menu item to control animation timing
private final float[] hoverScales = new float[6]; // Track scale (size) of each menu item during hover animation
private final float MAX_SCALE = 1.05f; // Maximum size increase when hovering (5% larger)
// Constants for sidebar dimensions and animation
private static final int EXPANDED_WIDTH = 280; // Width of sidebar when expanded
private static final int COLLAPSED_WIDTH = 70; // Width of sidebar when collapsed
private static final int ANIMATION_DURATION = 250; // How long the collapse/expand animation takes (in milliseconds)
// Main components of the interface
private final JPanel sidebar; // The sidebar panel containing menu items
private JButton collapseButton; // Button to collapse/expand the sidebar
private JButton selectedButton; // Currently selected menu button
private final JPanel contentPanel; // The main content area
private Timer sidebarAnimationTimer; // Controls the animation when collapsing/expanding sidebar
private boolean isSidebarCollapsed; // Tracks if sidebar is currently collapsed
private final JWindow tooltipWindow; // Custom tooltip window that appears when hovering over collapsed menu items
private final Map<String, Color> iconColors; // Colors for each menu icon
// Color scheme for the application
private final Color primaryColor = new Color(23, 25, 35); // Dark blue-gray for primary backgrounds
private final Color secondaryColor = new Color(32, 34, 45); // Slightly lighter blue-gray
private final Color accentColor = new Color(103, 118, 240); // Bright purple-blue for highlights
private final Color backgroundColor = new Color(245, 246, 250); // Light gray background
private final Color textColor = new Color(255, 255, 255); // White text
private final Color tooltipBackground = new Color(45, 47, 57, 230); // Semi-transparent dark background for tooltips
private final Color menuActiveColor = new Color(103, 118, 240, 100); // Semi-transparent accent for active menu items
/**
* Constructor: sets up the main layout and initializes components
*/
public Collapsing_Sidebar(){
// Set up the main panel with BorderLayout (divides screen into North, South, East, West, Center regions)
setLayout(new BorderLayout());
setBackground(backgroundColor);
// Initialize colors for each icon
iconColors = initializeIconColors();
// Create the tooltip window (appears when hovering over collapsed sidebar items)
tooltipWindow = createTooltipWindow();
// Create the sidebar and content panels
sidebar = createSidebar();
contentPanel = createContentPanel();
// Add sidebar to the west (left) and content to the center
add(sidebar, BorderLayout.WEST);
add(contentPanel, BorderLayout.CENTER);
}
/**
* Define colors for each icon in the sidebar
*/
private Map<String, Color> initializeIconColors() {
Map<String, Color> colors = new HashMap<>();
colors.put("dashboard", new Color(255, 184, 108)); // Orange
colors.put("menu", new Color(132, 255, 147)); // Green
colors.put("orders", new Color(255, 129, 129)); // Red
colors.put("customers", new Color(129, 236, 255)); // Blue
colors.put("analytics", new Color(255, 162, 255)); // Pink
colors.put("settings", new Color(255, 231, 129)); // Yellow
return colors;
}
/**
* Creates the sidebar panel containing logo, menu items, and collapse button
*/
private JPanel createSidebar() {
// Create sidebar panel with custom background painting
JPanel sidebarPanel = new JPanel(new BorderLayout()) {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// Create gradient background from primary to secondary color
GradientPaint gp = new GradientPaint(
0, 0, primaryColor, // Top color
0, getHeight(), secondaryColor // Bottom color
);
g2d.setPaint(gp);
g2d.fillRect(0, 0, getWidth(), getHeight());
// Add subtle horizontal lines pattern overlay
g2d.setColor(new Color(255, 255, 255, 5)); // Very transparent white
for (int i = 0; i < getHeight(); i += 4) {
g2d.drawLine(0, i, getWidth(), i);
}
g2d.dispose();
}
};
// Set initial size and padding
sidebarPanel.setPreferredSize(new Dimension(EXPANDED_WIDTH, getHeight()));
sidebarPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 15, 0));
// Add logo at the top
JPanel logoPanel = createLogoPanel();
sidebarPanel.add(logoPanel, BorderLayout.NORTH);
// Add menu items in the center
JPanel menuPanel = createMenuPanel();
sidebarPanel.add(menuPanel, BorderLayout.CENTER);
// Add collapse button at bottom
collapseButton = createCollapseButton();
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
buttonPanel.setOpaque(false);
buttonPanel.add(collapseButton);
sidebarPanel.add(buttonPanel, BorderLayout.SOUTH);
return sidebarPanel;
}
/**
* Creates the button that collapses/expands the sidebar
*/
private JButton createCollapseButton() {
// Create button with custom painting
JButton button = new JButton() {
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int width = getWidth();
int height = getHeight();
// Draw background with gradient
GradientPaint gp = new GradientPaint(
0, 0, new Color(
accentColor.getRed(),
accentColor.getGreen(),
accentColor.getBlue(),
80),
width, height, new Color(accentColor.getRed(),
accentColor.getGreen(),
accentColor.getBlue(), 60)
);
g2d.setPaint(gp);
g2d.fill(new RoundRectangle2D.Double(0, 0,
width, height, height, height)); // Fully rounded ends
// Draw arrow icon
g2d.setColor(textColor);
g2d.setStroke(new BasicStroke(1.5f, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND));
int arrowSize = 8;
int centerX = width / 2;
int centerY = height / 2;
// Create arrow path based on sidebar state
Path2D.Double arrow = new Path2D.Double();
if (isSidebarCollapsed) {
// Right-pointing arrow when collapsed (will expand)
arrow.moveTo(centerX - arrowSize/2, centerY - arrowSize/2);
arrow.lineTo(centerX + arrowSize/2, centerY);
arrow.lineTo(centerX - arrowSize/2, centerY + arrowSize/2);
} else {
// Left-pointing arrow when expanded (will collapse)
arrow.moveTo(centerX + arrowSize/2, centerY - arrowSize/2);
arrow.lineTo(centerX - arrowSize/2, centerY);
arrow.lineTo(centerX + arrowSize/2, centerY + arrowSize/2);
}
g2d.draw(arrow);
}
};
// Set button properties
button.setPreferredSize(new Dimension(50, 35));
button.setBorderPainted(false);
button.setContentAreaFilled(false);
button.setFocusPainted(false);
button.setCursor(new Cursor(Cursor.HAND_CURSOR));
// Add action to toggle sidebar when clicked
button.addActionListener(e -> toggleSidebar());
return button;
}
// This method handles the animation of the sidebar expanding and collapsing
private void toggleSidebar() {
// If an animation is already running, don't start another one
if (sidebarAnimationTimer != null && sidebarAnimationTimer.isRunning()) {
return;
}
// Determine the target width based on current state
int targetWidth = isSidebarCollapsed ? EXPANDED_WIDTH : COLLAPSED_WIDTH;
int currentWidth = sidebar.getWidth(); // Current width of sidebar
int totalSteps = 15; // Number of animation steps
// Create a timer that will fire events to animate the sidebar
// ANIMATION_DURATION is divided by totalSteps to get the delay between steps
sidebarAnimationTimer = new Timer(ANIMATION_DURATION / totalSteps, null);
final int[] step = {0}; // Use array to hold step counter so it can be modified in lambda
// Add the action that happens on each timer tick
sidebarAnimationTimer.addActionListener(e -> {
step[0]++; // Increment step counter
if (step[0] <= totalSteps) {
// Calculate progress as a value from 0 to 1
double progress = step[0] / (double) totalSteps;
// Apply easing function for smoother animation
// This makes the animation start and end slowly, but move quickly in the middle
double easeProgress = progress < 0.5
? 2 * progress * progress // Accelerate in first half
: 1 - Math.pow(-2 * progress + 2, 2) / 2; // Decelerate in second half
// Calculate the new width based on progress
int newWidth = currentWidth + (int) (easeProgress * (targetWidth - currentWidth));
// Apply the new width to the sidebar
sidebar.setPreferredSize(new Dimension(newWidth, getHeight()));
sidebar.revalidate(); // Tell layout manager to recalculate layout
sidebar.repaint(); // Request a repaint of the sidebar
} else {
// Animation is complete, set final width
sidebar.setPreferredSize(new Dimension(targetWidth, getHeight()));
((Timer) e.getSource()).stop(); // Stop the timer
isSidebarCollapsed = !isSidebarCollapsed; // Toggle the collapsed state
updateSidebarContent(); // Update sidebar contents for new state
collapseButton.repaint(); // Repaint the collapse button
}
});
// Start the animation
sidebarAnimationTimer.start();
}
// This method updates the content of the sidebar when it expands or collapses
private void updateSidebarContent() {
// Get all components in the sidebar
Component[] components = sidebar.getComponents();
// Loop through each component
for (Component component : components) {
// Check if the component is a JPanel
if (component instanceof JPanel) {
// Get all components inside this panel
Component[] panelComponents = ((JPanel) component).getComponents();
// Loop through each component in the panel
for (Component panelComponent : panelComponents) {
// Check if component is a button but not the collapse button
if (panelComponent instanceof JButton && panelComponent != collapseButton) {
JButton button = (JButton) panelComponent;
// Get the original text stored as a property on the button
String originalText = (String) button.getClientProperty("originalText");
// Create a timer for fade animation of text
Timer fadeTimer = new Timer(20, null);
// Use array to hold opacity value so it can be modified in lambda
float[] opacity = {button.getForeground().getAlpha() / 255f};
// Create color with current opacity
Color textColorWithAlpha = new Color(
textColor.getRed(),
textColor.getGreen(),
textColor.getBlue(),
(int) (opacity[0] * 255)
);
button.setForeground(textColorWithAlpha);
// Add actions for each timer tick to animate text fading
fadeTimer.addActionListener(evt -> {
if (isSidebarCollapsed) {
// If sidebar is collapsing, reduce opacity
opacity[0] -= 0.1f; // Decrease by 10%
if (opacity[0] <= 0) {
// Text fully transparent, remove it
opacity[0] = 0;
button.setText(""); // Clear text
button.setHorizontalAlignment(SwingConstants.CENTER); // Center icon
fadeTimer.stop(); // Stop animation
}
} else {
// If sidebar is expanding, increase opacity
if (opacity[0] == 0) {
// If starting from zero, restore text and left alignment
button.setText(originalText);
button.setHorizontalAlignment(SwingConstants.LEFT);
}
opacity[0] += 0.1f; // Increase by 10%
if (opacity[0] >= 1) {
// Text fully visible
opacity[0] = 1;
fadeTimer.stop(); // Stop animation
}
}
// Apply the new opacity to the text color
button.setForeground(new Color(
textColor.getRed(),
textColor.getGreen(),
textColor.getBlue(),
(int) (opacity[0] * 255) // Convert 0-1 to 0-255
));
});
// Start the fade animation
fadeTimer.start();
}
}
}
}
// Tell the layout manager to recalculate layout
sidebar.revalidate();
// Request a repaint of the sidebar
sidebar.repaint();
}
/**
* Creates the logo panel at the top of the sidebar
*/
private JPanel createLogoPanel() {
JPanel logoPanel = new JPanel(new BorderLayout());
logoPanel.setOpaque(false); // Make transparent to show sidebar background
logoPanel.setBorder(new EmptyBorder(25, 25, 25, 25)); // Add padding
// Create and style the logo text
JLabel logoLabel = new JLabel("My App Logo");
logoLabel.setFont(new Font("Inter", Font.BOLD, 22));
logoLabel.setForeground(textColor);
logoPanel.add(logoLabel, BorderLayout.CENTER);
return logoPanel;
}
/**
* Creates the panel containing menu buttons
*/
private JPanel createMenuPanel() {
// Create panel with vertical box layout (components stacked top to bottom)
JPanel menuPanel = new JPanel();
menuPanel.setLayout(new BoxLayout(menuPanel, BoxLayout.Y_AXIS));
menuPanel.setOpaque(false); // Transparent to show sidebar background
menuPanel.setBorder(BorderFactory.createEmptyBorder(15, 0, 15, 0)); // Add padding
// Menu items to display
String[] menuItems = {"Dashboard", "Menu", "Orders", "Customers", "Analytics", "Settings"};
// Create and add each menu button
for (int i = 0; i < menuItems.length; i++) {
// Create the button (first one is selected by default)
JButton menuButton = createMenuButton(menuItems[i], i == 0);
if (i == 0) {
selectedButton = menuButton; // Track the initially selected button
}
menuPanel.add(menuButton);
menuPanel.add(Box.createRigidArea(new Dimension(0, 8))); // Add spacing between buttons
// Add action listener to handle selection
menuButton.addActionListener(e -> {
// Deselect previous button
if (selectedButton != null) {
selectedButton.putClientProperty("selected", false);
selectedButton.repaint();
}
// Select this button
selectedButton = menuButton;
menuButton.putClientProperty("selected", true);
menuButton.repaint();
});
}
return menuPanel;
}
/**
* Creates a menu button with custom styling and animation effects
*/
private JButton createMenuButton(String text, boolean isSelected) {
// Create a custom button that overrides paintComponent for custom rendering
JButton menuButton = new JButton(text) {
private float glowOpacity = 1f; // Controls glow effect intensity
@Override
protected void paintComponent(Graphics g) {
// Use Graphics2D for better quality rendering
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
// Find which button this is (by index) to get its scale value
int buttonIndex = Arrays.asList(new String[]{"Dashboard", "Menu", "Orders",
"Customers", "Analytics", "Settings"}).indexOf(text);
float currentScale = hoverScales[buttonIndex];
// Apply scaling transformation if button is hovered (scale > 1.0)
if (currentScale != 1.0f) {
double scaleX = currentScale;
double scaleY = currentScale;
double centerX = getWidth() / 2.0;
double centerY = getHeight() / 2.0;
// Move to center, scale, then move back
g2d.translate(centerX, centerY);
g2d.scale(scaleX, scaleY);
g2d.translate(-centerX, -centerY);
}
boolean isButtonSelected = Boolean.TRUE.equals(getClientProperty("selected"));
// Draw glow effect when selected
if (isButtonSelected) {
// Create glow effect with decreasing opacity for outer rings
int glowSize = 12;
for (int i = glowSize; i > 0; i--) {
float alpha = (glowOpacity * 0.3f) * (1.0f - (float)i / glowSize);
g2d.setColor(new Color(
accentColor.getRed()/255f,
accentColor.getGreen()/255f,
accentColor.getBlue()/255f,
alpha
));
g2d.fillRoundRect(
8 - i/2,
4 - i/2,
getWidth() - 16 + i,
getHeight() - 8 + i,
12 + i, // Corner radius X
12 + i // Corner radius Y
);
}
}
// Draw button background (only when pressed or selected)
if (getModel().isPressed() || isButtonSelected) {
g2d.setColor(menuActiveColor); // Active color for selected/pressed
}
if (getModel().isPressed() || isButtonSelected) {
// Draw rounded rectangle background
g2d.fillRoundRect(8, 4, getWidth() - 16, getHeight() - 8, 12, 12);
}
// Let the parent class draw the text and icon
super.paintComponent(g2d);
g2d.dispose(); // Clean up graphics resources
}
};
// Initialize hover animation properties for this button
int buttonIndex = Arrays.asList(new String[]{"Dashboard", "Menu", "Orders",
"Customers", "Analytics", "Settings"}).indexOf(text);
hoverScales[buttonIndex] = 1.0f; // Start at normal scale (no zoom)
// Add mouse listeners for hover effects
menuButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
// Show tooltip if sidebar is collapsed
if (isSidebarCollapsed) {
showTooltip((String) menuButton.getClientProperty("originalText"), menuButton);
}
// Start hover scale animation (grow)
startHoverAnimation(buttonIndex, true);
}
@Override
public void mouseExited(MouseEvent e) {
// Hide tooltip
tooltipWindow.dispose();
// Start hover scale animation (shrink back)
startHoverAnimation(buttonIndex, false);
}
});
// Set button appearance properties
menuButton.setForeground(textColor);
menuButton.setFont(new Font("Inter", Font.BOLD, 14));
menuButton.setAlignmentX(Component.LEFT_ALIGNMENT); // Align to left side of container
menuButton.setMaximumSize(new Dimension(240, 45)); // Limit maximum size
menuButton.setBorderPainted(false); // Don't paint the default button border
menuButton.setContentAreaFilled(false); // Don't fill content area (we do custom painting)
menuButton.setFocusPainted(false); // Don't show focus rectangle
menuButton.setHorizontalAlignment(SwingConstants.LEFT); // Align text to left
menuButton.setBorder(new EmptyBorder(8, 16, 8, 16)); // Add padding
menuButton.setCursor(new Cursor(Cursor.HAND_CURSOR)); // Show hand cursor on hover
// Create and set the icon based on button name
ImageIcon icon = createModernIcon(text.toLowerCase());
menuButton.setIcon(icon);
menuButton.setIconTextGap(16); // Space between icon and text
// Store original text and selected state as client properties
menuButton.putClientProperty("originalText", text);
menuButton.putClientProperty("selected", isSelected);
return menuButton;
}
/**
* Creates custom icons for the sidebar menu items
* @param iconName The name of the icon to create
* @return An ImageIcon with the drawn icon
*/
private ImageIcon createModernIcon(String iconName) {
int size = 24; // Size of the icon in pixels
// Create a blank transparent image
BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = image.createGraphics();
// Enable anti-aliasing for smoother edges
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// Get color for this icon (or use default text color)
Color iconColor = iconColors.getOrDefault(iconName, textColor);
g2d.setColor(iconColor);
// Set stroke style (line thickness and cap style)
g2d.setStroke(new BasicStroke(1.5f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
// Draw different icons based on the name
switch (iconName) {
case "dashboard" -> {
// Draw 4 small squares arranged in a grid
int padding = 3;
int gridSize = (size - 2 * padding) / 2;
g2d.drawRoundRect(padding, padding, gridSize, gridSize, 4, 4);
g2d.drawRoundRect(padding + gridSize + 2, padding, gridSize - 2, gridSize, 4, 4);
g2d.drawRoundRect(padding, padding + gridSize + 2, gridSize, gridSize - 2, 4, 4);
g2d.drawRoundRect(padding + gridSize + 2, padding + gridSize + 2, gridSize - 2, gridSize - 2, 4, 4);
}
case "menu" -> {
// Draw 3 horizontal lines (hamburger menu)
RoundRectangle2D.Double rect1 = new RoundRectangle2D.Double(3, 5, size - 6, 3, 2, 2);
RoundRectangle2D.Double rect2 = new RoundRectangle2D.Double(3, 11, size - 6, 3, 2, 2);
RoundRectangle2D.Double rect3 = new RoundRectangle2D.Double(3, 17, size - 6, 3, 2, 2);
g2d.fill(rect1);
g2d.fill(rect2);
g2d.fill(rect3);
}
case "orders" -> {
// Draw a document with lines
g2d.drawRoundRect(3, 3, size - 6, size - 6, 6, 6);
g2d.drawLine(7, 9, size - 7, 9); // First line
g2d.drawLine(7, 15, size - 7, 15); // Second line
g2d.drawLine(7, 21, size - 11, 21); // Third line (shorter)
}
case "customers" -> {
// Draw a person icon (circle for head, arc for body)
g2d.fillOval(7, 3, 10, 10); // Head
g2d.fillArc(3, 11, 18, 12, 0, 180); // Body
}
case "analytics" -> {
// Draw bar chart icon
g2d.drawLine(3, size - 3, size - 3, size - 3); // X-axis
g2d.drawLine(3, size - 3, 3, 3); // Y-axis
int barWidth = 3;
// Draw 3 bars of different heights
g2d.fillRoundRect(8, 14, barWidth, 7, 2, 2); // Short bar
g2d.fillRoundRect(14, 8, barWidth, 13, 2, 2); // Tall bar
g2d.fillRoundRect(20, 11, barWidth, 10, 2, 2); // Medium bar
}
case "settings" -> {
// Draw gear icon
int centerX = size / 2;
int centerY = size / 2;
int gearRadius = 8;
// Draw gear teeth (8 spokes)
for (int i = 0; i < 8; i++) {
double angle = i * Math.PI / 4; // 45 degree spacing
int x1 = centerX + (int) (gearRadius * Math.cos(angle));
int y1 = centerY + (int) (gearRadius * Math.sin(angle));
int x2 = centerX + (int) ((gearRadius + 4) * Math.cos(angle));
int y2 = centerY + (int) ((gearRadius + 4) * Math.sin(angle));
g2d.drawLine(x1, y1, x2, y2);
}
// Draw center circle of the gear
g2d.drawOval(centerX - 4, centerY - 4, 8, 8);
}
}
g2d.dispose(); // Clean up graphics resources
return new ImageIcon(image);
}
/**
* Animates the hover effect (scaling) of menu buttons
* @param buttonIndex Index of the button to animate
* @param mouseEntered True if mouse entered (grow), false if exited (shrink)
*/
private void startHoverAnimation(int buttonIndex, boolean mouseEntered) {
// Stop any existing animation for this button
if (hoverTimers[buttonIndex] != null && hoverTimers[buttonIndex].isRunning()) {
hoverTimers[buttonIndex].stop();
}
// Set target scale based on whether mouse entered or exited
float targetScale = mouseEntered ? MAX_SCALE : 1.0f;
float currentScale = hoverScales[buttonIndex];
// Create a timer for animation
hoverTimers[buttonIndex] = new Timer(16, null);
final float[] progress = {0f}; // Track animation progress
hoverTimers[buttonIndex].addActionListener(e -> {
progress[0] += 0.15f; // Increase progress by 15% each frame
if (progress[0] >= 1f) {
// Animation complete
hoverScales[buttonIndex] = targetScale;
((Timer)e.getSource()).stop();
} else {
// Calculate eased progress for smooth animation
// easeInOutQuad gives acceleration at start and deceleration at end
float easedProgress = progress[0] < 0.5f
? 2 * progress[0] * progress[0] // First half: quadratic easing in
: 1 - (float)Math.pow(-2 * progress[0] + 2, 2) / 2; // Second half: quadratic easing out
// Calculate new scale based on progress
hoverScales[buttonIndex] = currentScale + (targetScale - currentScale) * easedProgress;
}
// Repaint the sidebar so the button gets redrawn with new scale
sidebar.repaint();
});
hoverTimers[buttonIndex].start();
}
/**
* Creates an empty, transparent window for custom tooltips
*/
private JWindow createTooltipWindow() {
JWindow window = new JWindow();
window.setBackground(new Color(0, 0, 0, 0)); // Fully transparent background
return window;
}
/**
* Shows a tooltip with the given text next to the specified component
*/
private void showTooltip(String text, Component component) {
// Create a panel for the tooltip with custom painting
JPanel tooltipPanel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
// Cast to Graphics2D for better rendering quality
Graphics2D g2d = (Graphics2D) g.create();
// Enable anti-aliasing for smoother edges
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int arrowSize = 8;
// Create a custom shape for the tooltip with an arrow pointing left
Path2D path = new Path2D.Double();
path.moveTo(arrowSize, 0);
path.lineTo(getWidth(), 0);
path.lineTo(getWidth(), getHeight());
path.lineTo(arrowSize, getHeight());
path.lineTo(0, getHeight()/2.0); // The arrow point
path.closePath();
// Draw shadow effect slightly offset
g2d.setColor(new Color(0, 0, 0, 50));
g2d.translate(2, 2); // Move 2 pixels right and down
g2d.fill(path);
g2d.translate(-2, -2); // Move back to original position
// Draw the tooltip background
g2d.setColor(tooltipBackground);
g2d.fill(path);
// Add subtle gradient overlay
GradientPaint gp = new GradientPaint(
0, 0, new Color(255, 255, 255, 25), // Light top
0, getHeight(), new Color(255, 255, 255, 5) // Darker bottom
);
g2d.setPaint(gp);
g2d.fill(path);
g2d.dispose();
}
};
tooltipPanel.setLayout(new BorderLayout());
tooltipPanel.setOpaque(false); // Make panel transparent
// Create and style the text label
JLabel label = new JLabel(text);
label.setForeground(textColor);
label.setFont(new Font("Inter", Font.BOLD, 13));
label.setBorder(BorderFactory.createEmptyBorder(8, 16, 8, 16)); // Add padding
tooltipPanel.add(label);
// Set the tooltip content
tooltipWindow.setContentPane(tooltipPanel);
tooltipWindow.pack(); // Size the window to fit the content
// Position tooltip next to the component that triggered it
Point locationOnScreen = component.getLocationOnScreen();
tooltipWindow.setLocation(
locationOnScreen.x + component.getWidth() + 5, // 5px to the right of component
locationOnScreen.y + (component.getHeight() - tooltipWindow.getHeight()) / 2 // Vertically centered
);
// Add fade-in animation for the tooltip
tooltipWindow.setOpacity(0.0f); // Start fully transparent
tooltipWindow.setVisible(true);
Timer fadeTimer = new Timer(20, null); // 20ms interval for smooth animation
float[] opacity = {0.0f};
fadeTimer.addActionListener(e -> {
opacity[0] += 0.1f; // Increase opacity by 10% each step
if (opacity[0] >= 1.0f) {
opacity[0] = 1.0f;
fadeTimer.stop(); // Stop the timer when fully visible
}
tooltipWindow.setOpacity(opacity[0]);
});
fadeTimer.start();
}
/**
* Creates the main content panel where app content would go
*/
private JPanel createContentPanel() {
// Create panel with custom background
JPanel panel = new JPanel(new BorderLayout()) {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON
);
// Create subtle gradient background
GradientPaint gp = new GradientPaint(
0, 0, backgroundColor,
getWidth(), getHeight(),
new Color(
backgroundColor.getRed() - 105,
backgroundColor.getGreen() - 5,
backgroundColor.getBlue() - 5
)
);
g2d.setPaint(gp);
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.dispose();
}
};
// Add some sample content
JPanel contentArea = new JPanel(new GridBagLayout());
contentArea.setOpaque(false);
JLabel welcomeLabel = new JLabel("Welcome to The Application");
welcomeLabel.setFont(new Font("Inter", Font.BOLD, 24));
welcomeLabel.setForeground(new Color(23, 25, 35));
contentArea.add(welcomeLabel);
panel.add(contentArea, BorderLayout.CENTER);
// Add close button to the top right of content panel
JPanel headerPanel = new JPanel(new BorderLayout());
headerPanel.setOpaque(false);
JButton closeButton = createCloseButton();
JPanel closeButtonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
closeButtonPanel.setOpaque(false);
closeButtonPanel.add(closeButton);
headerPanel.add(closeButtonPanel, BorderLayout.EAST);
panel.add(headerPanel, BorderLayout.NORTH);
return panel;
}
// This method creates a custom close button with an X symbol
// It uses Java Swing graphics to draw the button rather than using a standard button
private JButton createCloseButton() {
// Create a new button and override its paintComponent method to customize its appearance
JButton button = new JButton() {
@Override
protected void paintComponent(Graphics g) {
// Create a Graphics2D object which gives more advanced drawing capabilities
Graphics2D g2d = (Graphics2D) g.create();
// Turn on anti-aliasing to make the lines look smoother
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// Get the current width and height of the button
int width = getWidth();
int height = getHeight();
// Draw the X mark
g2d.setColor(secondaryColor); // Use the app's primary or accentColor color
// Set line style: 2 pixels thick with rounded ends and corners
g2d.setStroke(new BasicStroke(2f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
// Calculate where to start/end lines with padding from edges
int padding = 8;
// Draw first diagonal line (top-left to bottom-right)
g2d.drawLine(padding, padding, width-padding, height-padding);
// Draw second diagonal line (top-right to bottom-left)
g2d.drawLine(width-padding, padding, padding, height-padding);
g2d.dispose();
}
};
// Set button properties
button.setPreferredSize(new Dimension(30, 30)); // Set size to 30x30 pixels
button.setBorderPainted(false); // Don't show a border
button.setContentAreaFilled(false); // Don't fill the background (we're custom drawing it)
button.setFocusPainted(false); // Don't show focus outline
button.setCursor(new Cursor(Cursor.HAND_CURSOR)); // Show hand cursor on hover
button.setToolTipText("Close"); // Show "Close" tooltip on hover
// Add action listener - defines what happens when button is clicked
button.addActionListener(e -> {
// Find the window that contains this button
Window window = SwingUtilities.getWindowAncestor(button);
if (window != null) {
window.dispose(); // Close the window
}
});
return button;
}
public static void main(String[] args) {
try {
// Set system look and feel
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("Dashboard");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1000, 600);
frame.setLocationRelativeTo(null);
frame.setContentPane(new Collapsing_Sidebar());
// Add window decoration
frame.setUndecorated(true);
frame.getRootPane().setWindowDecorationStyle(JRootPane.FRAME);
frame.setVisible(true);
});
}
}
The Final Result:
More Java Projects:
Download Projects Source Code



