Reputation:
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:
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
Reputation: 21243
Here are some suggestions:
Please post a compilable example - SSCCE
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.
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));
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.
Looks like drawPass
draws rectangles upside down.
Here is an example that uses existing code with minimal changes:
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