0

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>
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
  • For better help sooner, post an [SSCCE](http://sscce.org/). – Andrew Thompson Apr 18 '13 at 02:08
  • There's no mouse listener? – MadProgrammer Apr 18 '13 at 02:09
  • `public void paintComponent (Graphics g) {` should be `public void paintComponent (Graphics g) { super.paintComponent(g);` – Andrew Thompson Apr 18 '13 at 02:09
  • 3
    You might also like to take a look at [this similar question](http://stackoverflow.com/questions/15756210/java-multiple-graphics/15756352#15756352) – MadProgrammer Apr 18 '13 at 02:11
  • @MadProgrammer There is, I'm using the NetBeans GUI Builder, so it's in the auto-generated code. –  Apr 18 '13 at 02:15
  • @AndrewThompson I added that, but still nothing. –  Apr 18 '13 at 02:16
  • *"I added that,"* I see no SSCCE. – Andrew Thompson Apr 18 '13 at 02:18
  • @AndrewThompson I meant the super.paintComponent. I've tried making this as short and simple as I can. –  Apr 18 '13 at 03:01
  • *"short and simple"* simple is not part of SSCCE. While that is 'short' & in some sense SC, it is not C or an E of the problem. – Andrew Thompson Apr 18 '13 at 03:04
  • @AndrewThompson Okay, I think what I added should solve it, but it's not exactly short anymore. I added in the auto-generated code by NetBeans. I don't usually add that because it generates so much, but that's all the code for the panel. –  Apr 18 '13 at 03:13
  • An SSCCE is one source file. As opposed to one source file and uncompilable code snippets. Try to understand the concept of it. The idea is to make it easy for other people to see the same error. – Andrew Thompson Apr 18 '13 at 03:15

1 Answers1

3

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);
    }
}
tenorsax
  • 21,123
  • 9
  • 60
  • 107
  • 1
    +1 woow, but I'd be to use [JProgressBar for Equalizer](http://stackoverflow.com/a/12525351/714968) – mKorbel Apr 18 '13 at 05:45