Java Swing Paginated Table

How to Create an Advanced Paginated Table in Java Swing Using Netbeans



How to Create an Advanced Paginated Table in Java Swing Using Netbeans


In this Java Tutorial we will see How To Create a complete paginated table with custom styling, navigation controls, and Jump-to-page functionality In Java Using Netbeans.

Project Overview:
Our paginated table will include:
    - 1000 sample records with ID, Name, Email, and Status columns
    - Configurable page sizes (5, 10, 15, 20 rows)
    - Navigation controls (First, Previous, Next, Last)
    - Page number buttons with ellipsis for large datasets
    - Jump-to-page functionality

What We Are Gonna Use In This Project:

- Java Programming Language.
- NetBeans Editor.





Project Source Code:

public class PaginatedTable extends JFrame {

    private JTable table;
    private DefaultTableModel model;
    private JPanel paginationPanel;
    private int currentPage = 1;
    private int recordPerPage = 5;
    private List<Object[]> allData;
    private int totalPages;
    private JComboBox<String> pageSizeCombo;
    private JTextField pageJump;
    
    private final Color primaryColor = new Color(79, 70, 229);
    private final Color borderColor = new Color(229, 231, 235);
    private final Color backgroundColor = new Color(249, 250, 251);
    private final Color textColor = new Color(17, 24, 39);
    
    public PaginatedTable(){
        
        setTitle("Paginated Table");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        initializeComponents();
        setupLayout();
        loadSampleData();
        updateTable();
        setSize(1000, 600);
        setLocationRelativeTo(null);
        setVisible(true);
        
    }
    
    // Initialize all UI components
    private void initializeComponents(){
        
        String[] columns = {"ID", "Name", "Email", "Status"};
        model = new DefaultTableModel(columns, 0);
        table = new JTable(model);
        customizeTable(table);
        
        // Create custom cell renderer for modern look
        DefaultTableCellRenderer cellRender = new DefaultTableCellRenderer(){
            
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, 
                                                                                                    boolean hasFocus, int row, int column){
                
                Component comp = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                setBorder(new EmptyBorder(0, 20, 0, 20));
                
                if(!isSelected){ setBackground(row % 2 == 0 ? Color.WHITE : backgroundColor); }
                
                return comp;
                
            }
            
        };
        
        cellRender.setHorizontalAlignment(JLabel.LEFT);
        
        for(int i = 0; i < table.getColumnCount(); i++){
            table.getColumnModel().getColumn(i).setCellRenderer(cellRender);
        }
        
        paginationPanel = new JPanel();
        paginationPanel.setBackground(Color.WHITE);
        
        pageSizeCombo = new JComboBox<>(new String[]{"5 rows", "10 rows", "15 rows", "20 rows"});
        pageSizeCombo.setFont(new Font("Arial", Font.PLAIN, 17));
        
        // Add change listener for page size
        pageSizeCombo.addActionListener(e -> {
            String selected = (String) pageSizeCombo.getSelectedItem();
            recordPerPage = Integer.parseInt(selected.split(" ")[0]); // Update records per page
            currentPage = 1;        // Reset to first page
            totalPages = (int) Math.ceil((double) allData.size() / recordPerPage);  // Recalculate total pages
            updateTable();               // Refresh table
        });
        
        pageJump = new JTextField(3);
        pageJump.setFont(new Font("Arial", Font.PLAIN, 14));
        
        // Add action listener for page jumping
        pageJump.addActionListener(e -> {
        
            try{
                
                int page = Integer.parseInt(pageJump.getText());  // Validate page number
                
                if(page >= 1 && page <= totalPages){
                    currentPage = page; // Update current page
                    updateTable();               // Refresh table
                }
            }
            catch(NumberFormatException ex){ /* Ignore invalid input*/ }
            
            pageJump.setText("");             // Clear input field
        
        });

    }
    
    
    // Load sample data for demonstration
    private void loadSampleData(){
        allData = new ArrayList<>();  // Initialize data list
        String[] status = { "Active", "Pending", "Completed", "Inactive"}; // Define possible statuses
        Random random = new Random();
        // Generate 1000 sample records
        for(int i = 1; i <= 1000; i++){
            allData.add(new Object[]{
                String.format("#%03d", i),  // Format ID with leading zeros
                "User" + i, // Generate user name
                "user" + i + "@example.com", // Generate email
                status[random.nextInt(status.length)] // Random status
            });         
        }
        
        // Calculate total pages
        totalPages = (int)Math.ceil((double)allData.size() / recordPerPage);
        
    }
    
    // Setup the main layout
    private void setupLayout(){
        
         setLayout(new BorderLayout());                         // Use border layout for main frame
        
        // Create main panel with shadow effect
        JPanel mainPanel = new JPanel(new BorderLayout());
        mainPanel.setBackground(Color.darkGray);              // Set panel background
        mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); // Add padding

        // Create table container
        JPanel tableContainer = new JPanel(new BorderLayout());
        tableContainer.setBackground(Color.WHITE);             // Set container background
        tableContainer.setBorder(BorderFactory.createLineBorder(borderColor, 1)); // Add border

        // Create scroll pane for table
        JScrollPane scrollPane = new JScrollPane(table);
        scrollPane.setBorder(BorderFactory.createEmptyBorder()); // Remove scroll pane border
        scrollPane.getViewport().setBackground(Color.WHITE);   // Set viewport background
        
        // Assemble components
        tableContainer.add(scrollPane);                        // Add table to container
        mainPanel.add(tableContainer, BorderLayout.CENTER);    // Add container to main panel
        mainPanel.add(paginationPanel, BorderLayout.SOUTH);    // Add pagination to main panel
        add(mainPanel);                                        // Add main panel to frame
        
    }
    
    
    
    // Update table data based on current page
    private void updateTable(){
        model.setRowCount(0); // Clear current table data
        int start = (currentPage - 1) * recordPerPage;  // Calculate start index
        int end = Math.min(start + recordPerPage, allData.size());  // Calculate end index
        
        // Add rows for current page
        for(int i = start; i < end; i++){
            model.addRow(allData.get(i));
        }
        
        updatePagination(); // Update pagination controls
    }
    
    
    
        // Update pagination controls
        private void updatePagination(){
            paginationPanel.removeAll(); // Clear existing controls
            paginationPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 15, 15)); // Set layout
            
            // Create left section with page size selector and total records
            JPanel leftSection = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 0));
            leftSection.setBackground(Color.WHITE);
            leftSection.add(pageSizeCombo);
            
            // Add total records label
            JLabel totalRecords = new JLabel(String.format("Total: %d records", allData.size()));
            totalRecords.setFont(new Font("Arial", Font.PLAIN, 14));
            leftSection.add(totalRecords);
            
            // Create center section for navigation
            JPanel centerSection = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 0));
            centerSection.setBackground(Color.WHITE);
            
             // Add navigation buttons
             // First page button
            addPaginationButton(centerSection, "⟪", currentPage > 1, () -> {
                currentPage = 1;
                updateTable();
            });
            
            // Previous page button
           addPaginationButton(centerSection, "←", currentPage > 1, () -> {
                currentPage--;
                updateTable();
            });
           
           // Add page number buttons
           int start = Math.max(1, currentPage - 2);     // Calculate start page
           int end = Math.min(totalPages, start + 4);   // Calculate start page

           // Add ellipsis if needed     
           if(start > 1){ centerSection.add((new JLabel("..."))); }

           // Add page number buttons
           for(int i = start; i <= end; i++){
               final int page = i;
               addPageButton(centerSection, String.valueOf(i), i == currentPage, () -> {
                   currentPage = page;
                   updateTable();
               });
           }
           
           // Add ellipsis if needed     
           if(end < totalPages){ centerSection.add((new JLabel("..."))); }
           
           
            // Add next and last page buttons
            addPaginationButton(centerSection, "→", currentPage < totalPages, () -> { // Next page button
                   currentPage++;
                   updateTable();
            });

           addPaginationButton(centerSection, "⟫", currentPage < totalPages, () -> { // Last page button
                   currentPage = totalPages;
                   updateTable();
            });

           // Create right section with page jump
           JPanel rightSection = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 0));
           rightSection.setBackground(Color.WHITE);

           // Add page jump label and field
           JLabel jumpLabel = new JLabel("Go to page");
           jumpLabel.setFont(new Font("Arial", Font.PLAIN, 14));
           rightSection.add(jumpLabel);
           rightSection.add(pageJump);

           // Add all sections to pagination panel
           paginationPanel.add(leftSection);
           paginationPanel.add(centerSection);
           paginationPanel.add(rightSection);
           // Refresh panel
           paginationPanel.revalidate();
           paginationPanel.repaint();

        }
    
    
        // Add navigation button to pagination panel
         private void addPaginationButton(JPanel panel, String text, boolean enabled, Runnable action){

            JButton button = createButton(text, enabled, false);  // Create styled button
            button.addActionListener(e -> action.run());   // Add click handler
            panel.add(button);  // Add to panel
            
        }
    
    
        // Add page number button to pagination panel
        private void addPageButton(JPanel panel, String text, boolean isActive, Runnable action){

            JButton button = createButton(text, true, isActive);  // Create styled button
            button.addActionListener(e -> action.run());   // Add click handler
            panel.add(button);  // Add to panel
            
        }
    
    
        // Create styled button with modern look
        private JButton createButton(String text, boolean enabled, boolean isActive){
            
                    // Create custom button with modern painting
                JButton button = new JButton(text) {
                    @Override
                    protected void paintComponent(Graphics g) {
                        Graphics2D g2d = (Graphics2D) g.create();
                        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
                                RenderingHints.VALUE_ANTIALIAS_ON);

                        // Set button background color
                        if (isActive) {  g2d.setColor(primaryColor);   }                  // Active state

                        else { g2d.setColor(Color.lightGray);   }                  // Normal state

                        // Draw button background
                        g2d.fill(new RoundRectangle2D.Double(0, 0, getWidth(), getHeight(), 10, 10));

                        // Draw button border
                        if (!isActive) {
                            g2d.setColor(borderColor);
                            g2d.draw(new RoundRectangle2D.Double(0, 0, getWidth() - 1, getHeight() - 1, 10, 10));
                        }

                        // Set text color
                        g2d.setColor(isActive ? Color.WHITE : enabled ? textColor : Color.GRAY);

                        // Center and draw text
                        FontMetrics fm = g2d.getFontMetrics();
                        int x = (getWidth() - fm.stringWidth(getText())) / 2;
                        int y = ((getHeight() - fm.getHeight()) / 2) + fm.getAscent();
                        g2d.drawString(getText(), x, y);

                        g2d.dispose();                                       // Clean up graphics context
                    }
                };

                // Configure button styling
                button.setFont(new Font("Inter", Font.PLAIN, 14));         // Set button font
                button.setPreferredSize(new Dimension(40, 40));           // Set button size
                button.setFocusPainted(false);                            // Remove focus border
                button.setBorderPainted(false);                           // Remove default border
                button.setContentAreaFilled(false);                       // Remove default background
                button.setEnabled(enabled);                               // Set button state
                button.setCursor(enabled ? new Cursor(Cursor.HAND_CURSOR) : // Set appropriate cursor
                                         new Cursor(Cursor.DEFAULT_CURSOR));

                return button;                                            // Return the styled button

        }
      
    
    
    
        private void customizeTable(JTable table) {
            // Colors
             Color HEADER_BACKGROUND = new Color(52, 73, 94);
             Color HEADER_FOREGROUND = Color.WHITE;
             Color ROW_ALTERNATE = new Color(245, 245, 245);
             Color SELECTION_COLOR = new Color(52, 152, 219);

            // Customize header
            JTableHeader header = table.getTableHeader();
            header.setBackground(HEADER_BACKGROUND);
            header.setForeground(HEADER_FOREGROUND);
            header.setFont(header.getFont().deriveFont(Font.BOLD, 14f));
            header.setBorder(BorderFactory.createEmptyBorder());

            // Set custom renderer for header
            TableCellRenderer headerRenderer = new DefaultTableCellRenderer() {
                @Override
                public Component getTableCellRendererComponent(JTable table, Object value,
                        boolean isSelected, boolean hasFocus, int row, int column) {
                    JLabel label = (JLabel) super.getTableCellRendererComponent(
                            table, value, isSelected, hasFocus, row, column);
                    label.setBackground(HEADER_BACKGROUND);
                    label.setForeground(HEADER_FOREGROUND);
                    label.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
                    return label;
                }
            };

            for (int i = 0; i < table.getColumnCount(); i++) {
                table.getColumnModel().getColumn(i).setHeaderRenderer(headerRenderer);
            }

            // Customize table appearance
            table.setRowHeight(40);
            table.setFont(new Font("Arial", Font.PLAIN, 13));
            table.setSelectionBackground(SELECTION_COLOR);
            table.setSelectionForeground(Color.WHITE);
            table.setShowVerticalLines(false);
            table.setShowHorizontalLines(true);
            table.setGridColor(new Color(230, 230, 230));
            table.setIntercellSpacing(new Dimension(0, 0));

            // Custom renderer for alternating row colors
            DefaultTableCellRenderer cellRenderer = new DefaultTableCellRenderer() {
                @Override
                public Component getTableCellRendererComponent(JTable table, Object value,
                        boolean isSelected, boolean hasFocus, int row, int column) {
                    JLabel label = (JLabel) super.getTableCellRendererComponent(
                            table, value, isSelected, hasFocus, row, column);

                    if (!isSelected) {
                        label.setBackground(row % 2 == 0 ? Color.WHITE : ROW_ALTERNATE);
                    }
                    label.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10));

                    // Right-align numbers
                    if (value instanceof Number) {
                        label.setHorizontalAlignment(SwingConstants.RIGHT);
                    } else {
                        label.setHorizontalAlignment(SwingConstants.LEFT);
                    }

                    return label;
                }
            };

            for (int i = 0; i < table.getColumnCount(); i++) {
                table.getColumnModel().getColumn(i).setCellRenderer(cellRenderer);
            }

            // Enable sorting
            table.setAutoCreateRowSorter(true);
        }
    
    
    
    
    public static void main(String[] args) {
        
        // Set system look and feel for native appearance
        /*
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
            e.printStackTrace();                                  // Print any errors
        }
        */
        
        
        new PaginatedTable();
        
    }
            
    
}


  


The Final Result:










Python Tkinter Image Zoom

How To Create an Image Zooming and Pan App in Python Using Tkinter



How To Create an Image Zooming and Pan App in Python Using Tkinter




In this Python Tutorial we will see How to Create an image viewer with zoom, pan, and drag functionality Using Python and Tkinter library.

What We're Building?
Our image viewer will include:
- Image loading with file dialog.
- Zoom in/out functionality.
- Pan and drag.
- Fit-to-window.
- Keyboard shortcuts.
- Status bar with image information.

What We Are Gonna Use In This Project:

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






Project Source Code:




import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import Image, ImageTk
import os


class ImageZoomApp:
def __init__(self, root):
"""Initialize the image viewer application"""
# Set up the main window
self.root = root
self.root.title("Simple Image Zoom App")
self.root.geometry("1000x700") # Width x Height
self.root.configure(bg='#2c3e50') # Dark blue background
# Variables to store image data
self.original_image = None # The original image file
self.display_image = None # The image we show on screen
self.zoom_level = 1.0 # How zoomed in we are (1.0 = normal size)
# Variables for dragging the image around
self.drag_start_x = 0
self.drag_start_y = 0
self.image_x = 0 # Where the image is positioned
self.image_y = 0
# Create all the parts of our interface
self.create_buttons()
self.create_canvas()
self.create_status_bar()
self.setup_keyboard_shortcuts()



def create_buttons(self):
"""Create the button toolbar at the top"""
# Frame to hold all our buttons
button_frame = tk.Frame(self.root, bg='#34495e', height=60)
button_frame.pack(fill=tk.X, padx=10, pady=10)
button_frame.pack_propagate(False) # Keep the frame height fixed
# Open Image button
open_btn = tk.Button(
button_frame,
text="Open Image",
command=self.open_image,
bg='#3498db', # Blue background
fg='white', # White text
font=('Arial', 12, 'bold'),
padx=20,
pady=8,
cursor='hand2' # Hand cursor when hovering
)
open_btn.pack(side=tk.LEFT, padx=5, pady=10)

# Zoom In button
zoom_in_btn = tk.Button(
button_frame,
text="Zoom In (+)",
command=self.zoom_in,
bg='#27ae60', # Green background
fg='white',
font=('Arial', 10),
padx=15,
pady=8,
cursor='hand2'
)
zoom_in_btn.pack(side=tk.LEFT, padx=5, pady=10)
# Zoom Out button
zoom_out_btn = tk.Button(
button_frame,
text="Zoom Out (-)",
command=self.zoom_out,
bg='#e74c3c', # Red background
fg='white',
font=('Arial', 10),
padx=15,
pady=8,
cursor='hand2'
)
zoom_out_btn.pack(side=tk.LEFT, padx=5, pady=10)
# Reset Size button
reset_btn = tk.Button(
button_frame,
text="Reset Size",
command=self.reset_size,
bg='#9b59b6', # Purple background
fg='white',
font=('Arial', 10),
padx=15,
pady=8,
cursor='hand2'
)
reset_btn.pack(side=tk.LEFT, padx=5, pady=10)
# Fit to Window button
fit_btn = tk.Button(
button_frame,
text="Fit to Window",
command=self.fit_to_window,
bg='#f39c12', # Orange background
fg='white',
font=('Arial', 10),
padx=15,
pady=8,
cursor='hand2'
)
fit_btn.pack(side=tk.LEFT, padx=5, pady=10)
# Zoom level display
self.zoom_label = tk.Label(
button_frame,
text="100%",
bg='#34495e',
fg='#ecf0f1',
font=('Arial', 12, 'bold'),
padx=20
)
self.zoom_label.pack(side=tk.RIGHT, pady=10)
def create_canvas(self):
"""Create the canvas where we display the image"""
# Frame to hold the canvas and scrollbars
canvas_frame = tk.Frame(self.root, bg='#2c3e50')
canvas_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=(0, 10))
# Create the canvas
self.canvas = tk.Canvas(
canvas_frame,
bg='#1a252f', # Dark background for the image area
highlightthickness=0, # No border
cursor='crosshair' # Crosshair cursor
)

# Create scrollbars for when image is larger than window
v_scrollbar = tk.Scrollbar(canvas_frame, orient=tk.VERTICAL,
command=self.canvas.yview)
h_scrollbar = tk.Scrollbar(canvas_frame, orient=tk.HORIZONTAL,
command=self.canvas.xview)
# Connect scrollbars to canvas
self.canvas.configure(yscrollcommand=v_scrollbar.set,
xscrollcommand=h_scrollbar.set)
# Position everything in the frame
v_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
h_scrollbar.pack(side=tk.BOTTOM, fill=tk.X)
self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# Set up mouse interactions
self.setup_mouse_events()
def create_status_bar(self):
"""Create the status bar at the bottom"""
status_frame = tk.Frame(self.root, bg='#34495e', height=40)
status_frame.pack(fill=tk.X, padx=10, pady=(0, 10))
status_frame.pack_propagate(False)
# Status text (left side)
self.status_text = tk.Label(
status_frame,
text="Ready - Click 'Open Image' to start",
bg='#34495e',
fg='#bdc3c7',
font=('Arial', 10),
anchor=tk.W # Align text to the left
)
self.status_text.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=10, pady=10)
# Image info (right side)
self.image_info = tk.Label(
status_frame,
text="",
bg='#34495e',
fg='#3498db',
font=('Arial', 10, 'bold')
)
self.image_info.pack(side=tk.RIGHT, padx=10, pady=10)

def setup_mouse_events(self):
# Mouse dragging for moving the image around
self.canvas.bind("<Button-1>", self.start_drag) # Left click
self.canvas.bind("<B1-Motion>", self.drag_image) # Drag while holding left click
self.canvas.bind("<ButtonRelease-1>", self.end_drag) # Release left click
# Double-click to fit image to window
self.canvas.bind("<Double-Button-1>", lambda e: self.fit_to_window())


def setup_keyboard_shortcuts(self):
"""Set up keyboard shortcuts"""
# Ctrl+O to open image
self.root.bind("<Control-o>", lambda e: self.open_image())
# Plus key to zoom in
self.root.bind("<Control-plus>", lambda e: self.zoom_in())
# Minus key to zoom out
self.root.bind("<Control-minus>", lambda e: self.zoom_out())
# Ctrl+0 to reset size
self.root.bind("<Control-0>", lambda e: self.reset_size())





def open_image(self):
"""Open a file dialog to select an image"""
# Define what types of files we can open
file_types = [
("All Images", "*.png *.jpg *.jpeg *.gif *.bmp"),
("PNG files", "*.png"),
("JPEG files", "*.jpg *.jpeg"),
("GIF files", "*.gif"),
("BMP files", "*.bmp"),
("All files", "*.*")
]
# Show the file selection dialog
filename = filedialog.askopenfilename(
title="Choose an image file",
filetypes=file_types
)
# If user selected a file, try to load it
if filename:
try:
self.load_image(filename)
except Exception as e:
# Show error message if something goes wrong
messagebox.showerror("Error", f"Could not open image:\n{str(e)}")


def load_image(self, filename):
"""Load an image file and display it"""
try:
# Open the image file
self.original_image = Image.open(filename)

# Reset zoom to normal size
self.zoom_level = 1.0
# Center the image in the window
self.center_image()
# Update the display
self.update_display()

# Update status information
self.update_status(filename)

except Exception as e:
raise Exception(f"Failed to load image: {str(e)}")

def center_image(self):
"""Center the image in the canvas"""
# Wait a moment for the window to update its size
self.root.update_idletasks()
# Get the canvas size
canvas_width = self.canvas.winfo_width()
canvas_height = self.canvas.winfo_height()
# Put the image in the center
if canvas_width > 1 and canvas_height > 1:
self.image_x = canvas_width // 2
self.image_y = canvas_height // 2

def update_display(self):
"""Update what we see on the screen"""
if not self.original_image:
return # Nothing to show if no image is loaded
try:
# Calculate the new size based on zoom level
new_width = int(self.original_image.width * self.zoom_level)
new_height = int(self.original_image.height * self.zoom_level)
# Make sure size is at least 1 pixel
new_width = max(1, new_width)
new_height = max(1, new_height)
# Resize the image for display
if self.zoom_level == 1.0:
# Use original image if no zoom
display_image = self.original_image
else:
# Resize the image
display_image = self.original_image.resize((new_width, new_height),
Image.LANCZOS)
# Convert to format Tkinter can display
self.display_image = ImageTk.PhotoImage(display_image)
# Clear the canvas and show the new image
self.canvas.delete("all")
self.canvas.create_image(
self.image_x, self.image_y,
anchor=tk.CENTER,
image=self.display_image
)
# Update the scroll area
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
# Update the zoom percentage display
zoom_percent = int(self.zoom_level * 100)
self.zoom_label.config(text=f"{zoom_percent}%")

except Exception as e:
self.status_text.config(text=f"Error displaying image: {str(e)}")

def update_status(self, filename):
"""Update the status bar with image information"""
if self.original_image:
# Get just the filename without the full path
basename = os.path.basename(filename)
# Get image dimensions
width = self.original_image.width
height = self.original_image.height
# Get image format
image_format = getattr(self.original_image, 'format', 'Unknown')
# Update status displays
self.status_text.config(text=f"Loaded: {basename}")
self.image_info.config(text=f"{width} × {height}{image_format}")


def zoom_in(self):
"""Make the image bigger"""
if self.original_image and self.zoom_level < 10.0: # Max zoom: 1000%
self.zoom_level *= 1.2 # Increase by 20%
self.update_display()
def zoom_out(self):
"""Make the image smaller"""
if self.original_image and self.zoom_level > 0.1: # Min zoom: 10%
self.zoom_level /= 1.2 # Decrease by 20%
self.update_display()
def reset_size(self):
"""Reset image to its original size (100%)"""
if self.original_image:
self.zoom_level = 1.0
self.center_image()
self.update_display()
def fit_to_window(self):
"""Resize image to fit in the window"""
if not self.original_image:
return
# Make sure window size is updated
self.root.update_idletasks()
# Get canvas size
canvas_width = self.canvas.winfo_width()
canvas_height = self.canvas.winfo_height()
# Only proceed if canvas has valid size
if canvas_width > 50 and canvas_height > 50:
# Calculate how much we need to zoom to fit
zoom_x = (canvas_width - 20) / self.original_image.width #Leave 20px margin
zoom_y = (canvas_height - 20) / self.original_image.height
# Use the smaller zoom so image fits completely
self.zoom_level = min(zoom_x, zoom_y, 1.0) # Don't zoom larger than 100%
# Center the image
self.center_image()
self.update_display()

def start_drag(self, event):
"""Start dragging the image"""
self.drag_start_x = event.x
self.drag_start_y = event.y
self.canvas.configure(cursor='fleur') # Four-arrow cursor
def drag_image(self, event):
"""Move the image while dragging"""
if self.original_image:
# Calculate how far the mouse moved
dx = event.x - self.drag_start_x
dy = event.y - self.drag_start_y
# Move the image by that amount
self.image_x += dx
self.image_y += dy
# Update starting position for next movement
self.drag_start_x = event.x
self.drag_start_y = event.y
# Update the display
self.update_display()
def end_drag(self, event):
"""Stop dragging the image"""
self.canvas.configure(cursor='crosshair') # Back to normal cursor



def main():
"""Create and run the image viewer application"""
# Create the main window
root = tk.Tk()
# Create our image viewer
app = ImageZoomApp(root)
# Start the application
root.mainloop()

# Run the program
if __name__ == "__main__":
main()



The Final Result: