user1727668
user1727668

Reputation:

Painting a visual of Selection Sort

I am doing a program that creates an array of 50 numbers, then paints them in a panel as rectangles, the size based on the number. When the panel is clicked, the array will be sorted and the panel redrawn to show a sort of animation of the numbers being sorted. Here's what it's supposed to look like before and after clicking the panel: picture

And here is the code I have:

public class AnimatedSelectionSortPanel extends javax.swing.JPanel {

int[] numbers = new int[50];
int min = 20;
int max = 100;

private void loadArray() {
    int num;
    for (int i = 0; i < numbers.length; i++) {
        numbers[i] = min + (int) Math.random() * ((max - min) + 1);
    }
}

public static void selectionSort(int[] x) {
    for (int i = 0; i < x.length - 1; i++) {
        int minIndex = i;      // Index of smallest remaining value.
        for (int j = i + 1; j < x.length; j++) {
            if (x[minIndex] > x[j]) {
                minIndex = j;  // Remember index of new minimum
            }
        }
        if (minIndex != i) {
            //...  Exchange current element with smallest remaining.
            int temp = x[i];
            x[i] = x[minIndex];
            x[minIndex] = temp;
        }
    }
}

private void drawPass(Graphics g) {
    int xPos = 10;
    int yPos = 120;
    int rectWidth = 1;

    for (int num : numbers) {
        g.setColor(Color.black);
        g.drawRect(xPos, yPos, rectWidth, num);
        xPos += 11;
    }
}

@Override
public void paintComponent (Graphics g) {
    while (numbers.length == 0) {
        loadArray();
    }
    drawPass(g);
}

private void sortPanelMouseClicked(java.awt.event.MouseEvent evt) {
    selectionSort(numbers);
    sortPanel.repaint();
}

The problem I'm having is that nothing is being painted in the frame when I click the panel. Can someone tell me what's wrong with what I'm doing?

Here's the auto-generated code from the GUI builder if that helps:

    private void initComponents() {

    sortPanel = new javax.swing.JPanel();

    sortPanel.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
    sortPanel.addMouseListener(new java.awt.event.MouseAdapter() {
        public void mouseClicked(java.awt.event.MouseEvent evt) {
            sortPanelMouseClicked(evt);
        }
    });

    javax.swing.GroupLayout sortPanelLayout = new javax.swing.GroupLayout(sortPanel);
    sortPanel.setLayout(sortPanelLayout);
    sortPanelLayout.setHorizontalGroup(
        sortPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGap(0, 398, Short.MAX_VALUE)
    );
    sortPanelLayout.setVerticalGroup(
        sortPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGap(0, 165, Short.MAX_VALUE)
    );

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
    this.setLayout(layout);
    layout.setHorizontalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addComponent(sortPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
    );
    layout.setVerticalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
            .addComponent(sortPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
    );
}// </editor-fold>

Upvotes: 0

Views: 1198

Answers (1)

tenorsax
tenorsax

Reputation: 21243

Here are some suggestions:

  1. Please post a compilable example - SSCCE

  2. Don't put too much logic into paintComponent and don't allocate your data in this method. Its purpose is painting. Prepare the array of numbers in advance.

  3. min + (int) Math.random() * ((max - min) + 1); is always 20 since (int) Math.random() is always zero. You should cast the result, ie: min + (int) (Math.random() * ((max - min) + 1));

  4. Wrap the sorting process into a thread or a timer. Wait between iterations and call repaint() to paint intermediate results. Wrapping into a Swing timer is cleaner and preferable, but in the posted code it may be easier/faster to dump the whole logic of selectionSort into a thread. See Performing Custom Painting tutorial for some examples. Also see How to Use Swing Timers.

  5. Looks like drawPass draws rectangles upside down.

Here is an example that uses existing code with minimal changes:

enter image description here enter image description here

import java.awt.*;
import java.awt.event.*;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class AnimatedSelectionSortPanel extends javax.swing.JPanel {

    public static void main(String[] args){
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new AnimatedSelectionSortPanel());
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.pack();
                frame.setLocationByPlatform(true);
                frame.setVisible(true);
            }
        });
    }


    private int[] numbers = new int[50];
    private int min = 20;
    private int max = 100;
    private boolean shuffle = false;
    public static final int ITERATION_SLEEP = 100;

    public AnimatedSelectionSortPanel() {
        loadArray();
        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (shuffle)
                    loadArray();
                selectionSort(numbers);
                shuffle = true;
            }
        });
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(300, 100);
    }

    private void loadArray() {
        for (int i = 0; i < numbers.length; i++) {
            numbers[i] = min + (int) (Math.random() * ((max - min) + 1));
        }
    }

    public void selectionSort(final int[] x) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                    for (int i = 0; i < x.length - 1; i++) {
                    int minIndex = i; // Index of smallest remaining value.
                    for (int j = i + 1; j < x.length; j++) {
                        if (x[minIndex] > x[j]) {
                            minIndex = j; // Remember index of new minimum
                        }
                    }
                    if (minIndex != i) {
                        // ... Exchange current element with smallest remaining.
                        int temp = x[i];
                        x[i] = x[minIndex];
                        x[minIndex] = temp;
                    }
                    repaint();
                    try {
                        Thread.sleep(ITERATION_SLEEP);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }               
            }
        }).start();
    }

    private void drawPass(Graphics g) {
        int rectWidth = 1;

        int width = getWidth() - 1;
        int height = getHeight() - 1;
        int colSpan = Math.round((float)width / (float)numbers.length);
        int x = 0;

        for (int num : numbers) {
            int colHeight = (int) ((float) height * ((float) num / (float) 100));
            g.fillRect(x, height - colHeight, rectWidth, colHeight);
             x += colSpan;
        }
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        drawPass(g);
    }
}

Upvotes: 3

Related Questions