I'm found a solution, only on Bprolog, and ask for a help
how to translate it by JPL on SWI PROLOG? OR maybe you can take me solution by jpl libriry using
// by Nobukuni Kino
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import bprolog.plc.Plc;
public
class Queens extends Applet implements Runnable {
static int nqueens = 8;
/* Run as an application */
public static void main(String args[]) {
Frame f = new Frame("Queens");
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}});
Queens qb = new Queens();
qb.init();
f.add("Center",qb);
f.setSize(321,321);
f.show();
qb.run1();
System.exit(0);
}
int w,h;
Color pieceColor = new Color(255,150,150);
Thread runner;
public void start() {
if (runner == null) {
runner = new Thread(this);
System.out.println("Start");
runner.start();
} else {
runner.resume();
}
}
public void stop() {
if (runner != null) {
runner.suspend();
}
}
public void run(){}
public void run1() {
Plc.startPlc(new String []{});
Integer[] queens = new Integer[nqueens];
for (int i=0; i<nqueens; i++) queens[i] = new Integer(i+1);
Plc goal = new Plc("callQueens", new Object[] {queens,this});
Plc.exec("load('queens')");
goal.call();
}
public void paint(Graphics g) {
board(g);
}
public void update(Graphics g) {
}
public void board(Graphics g) {
w = (getSize().width-1)/nqueens;
h = (getSize().height-1)/nqueens;
g.setColor(Color.black);
g.drawRect(0, 0, nqueens*w+1, nqueens*h+1);
for (int i = 1; i <= nqueens; i++) {
for (int j = 1; j <= nqueens; j++) {
clearSquare(i,j);
}
}
}
public void putSquare(Integer row, Integer col) {
putSquare(row.intValue(), col.intValue());
}
public void putSquare(int row, int col) {
Graphics g = getGraphics();
g.setColor(pieceColor);
g.fillRect(w*(row-1)+1, h*(col-1)+1, w, h);
Thread.yield();
}
public void clearSquare(Integer row, Integer col) {
clearSquare(row.intValue(), col.intValue());
}
public void clearSquare(int row, int col) {
Graphics g = getGraphics();
if ((row+col)%2 == 1) {
g.setColor(Color.black);
}
else {
g.setColor(Color.white);
}
g.fillRect(w*(row-1)+1, h*(col-1)+1, w, h);
Thread.yield();
}
public void sleep(Integer mill) {
try {
Thread.sleep(mill.intValue(),0);
} catch(InterruptedException e) {}
}
}
:-module queens.
:-public queens/2.
draw(M,N):-
global_get(board,Qb),
javaMethod(Qb,putSquare(M,N)).
draw(M,N):-
global_get(board,Qb),
javaMethod(Qb,clearSquare(M,N)),
fail.
callQueens(Q,Qb):-
cputime(Start),
queens(Q,Qb),
cputime(End),
T is End-Start,
write(executionTime(T)),nl,
statistics.
queens(Q,Qb):-
javaMethod(Qb,sleep(500)),
global_set(board,Qb),
put(Q,[],R),write(R),nl,
javaMethod(Qb,sleep(1000)),
fail.
queens(Q,Qb):-
global_set(board,[]). % Qb is not valid after return to Java
put([Q1|Qs],Board,Result):-!,
sel([Q1|Qs],Q,Rs),
safe(Board,Q,Q),
length(Qs,L),N is 1+L,
draw(Q,N),
put(Rs,[Q|Board],Result).
put([],Result,Result).
safe([Q|Rs],P,M):-!,
PP is P+1,
Q\==PP,
MM is M-1,
Q\==MM,
safe(Rs,PP,MM).
safe([],P,M).
sel([X|Y],X,Y).
sel([X|Y],Z,[X|W]):-sel(Y,Z,W).
A literal translation is probably not worth the effort. The code you show encodes a very specific search strategy which is extremely difficult to modify. The actual logic and side effects are completely interwoven.
However, there is an animation for library(clpfd) of SWI which is far more interesting. There, it is possible to exchange the labeling strategies directly. So you can see why simple naive labeling turns out to be ineffective. Equally, you can add your own strategy, without any modification of the viewer's code.
Related
I am trying to code a sorting algorithm visualizer. I put almost everything into one class called visualizer and I was wondering how I can move my "insertionSort" and "bubbleSort" methods into separate classes without breaking my code?
I want to do this because when I integrate merge sort and quick sort I want to keep them in the same class as there helper methods.
public class Visualizer extends JPanel implements ActionListener{
//Initialize Variables
final int SCREEN_WIDTH = 1280;
final int SCREEN_HEIGHT = 720;
final int BAR_HEIGHT = SCREEN_HEIGHT * 4/5;
final int BAR_WIDTH = 5;
final int NUM_BARS = SCREEN_WIDTH/BAR_WIDTH;
JButton bubbleSort = new JButton();
JButton insertSort = new JButton();
SwingWorker<Void,Void> shuffler, sorter;
int[] array = new int[NUM_BARS];
int current;
int traverse;
public Visualizer() {
setBackground(Color.darkGray);
setPreferredSize(new Dimension());
//Initialize Bar Height
for (int i = 0; i < NUM_BARS; i++) {
array[i] = i * BAR_HEIGHT / NUM_BARS;
}
//InsertionSort Button
insertSort.setText("Insertion Sort");
this.add(insertSort);
insertSort.addActionListener(this);
//BubbleSort Button
bubbleSort.setText("Bubble Sort");
this.add(bubbleSort);
bubbleSort.addActionListener(this);
}
public void shuffleArray() {
shuffler = new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws InterruptedException {
Random random = new Random();
for (int i = 0; i < NUM_BARS; i++) {
int swap = random.nextInt(NUM_BARS - 1);
swap(i, swap);
Thread.sleep(10);
repaint();
}
return null;
}
#Override
public void done() {
super.done();
sorter.execute();
}
};
shuffler.execute();
}
public void insertionSort() {
sorter = new SwingWorker<Void, Void>() {
#Override
public Void doInBackground() throws InterruptedException {
for (current = 1; current < NUM_BARS; current++) {
traverse = current;
while (traverse > 0 && array[traverse] < array[traverse - 1]) {
swap(traverse, traverse - 1);
traverse--;
Thread.sleep(1);
repaint();
}
}
current = 0;
traverse = 0;
return null;
}
};
}
public void bubbleSort() {
sorter = new SwingWorker<Void, Void>() {
#Override
public Void doInBackground() throws InterruptedException {
for(current = 0; current < NUM_BARS; current++) {
for(traverse = 1; traverse < (NUM_BARS - current); traverse++) {
if(array[traverse-1] > array[traverse]) {
swap(traverse, traverse-1);
traverse--;
Thread.sleep(1);
repaint();
}
}
}
current = 0;
traverse = 0;
return null;
}
};
}
public void quickSort() {
sorter = new SwingWorker<Void, Void>() {
#Override
public Void doInBackground() throws InterruptedException {
return null;
}
};
}
public void swap(int indexOne, int indexTwo) {
int temp = array[indexOne];
array[indexOne] = array[indexTwo];
array[indexTwo] = temp;
}
#Override
public void paintComponent(Graphics g) {
Graphics2D graphics = (Graphics2D)g;
super.paintComponent(graphics);
g.setColor(Color.white);
for(int i = 0; i < NUM_BARS; i++) {
graphics.fillRect(i * BAR_WIDTH,SCREEN_HEIGHT-array[i],BAR_WIDTH,array[i]);
}
g.setColor(Color.green);
graphics.fillRect(current*BAR_WIDTH,SCREEN_HEIGHT-array[current], BAR_WIDTH, array[current]);
g.setColor(Color.red);
graphics.fillRect(traverse*BAR_WIDTH,SCREEN_HEIGHT-array[traverse], BAR_WIDTH, array[traverse]);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == insertSort) {
insertionSort();
shuffleArray();
}
else if (e.getSource() == bubbleSort) {
bubbleSort();
shuffleArray();
}
}
}
This is not as easy as it might seem, but, the basic answer comes down to making use of models and observers (something like the "model-view-controller" concept), so you can decouple the workflows in a more meaningful way.
One important note to make is, Swing is NOT thread save. This means that you should not be modifying the UI or any state the UI relies on from out side the context the Event Dispatching Thread. Under your current workflow it's possible for the SwingWorker to modify the state of the array (and other state values) while the UI is been painted, this could cause no end of issues.
The core functionality of a sorter is basically the same, it needs some values, needs to be able to swap those values and needs to deliver notifications to interested parties that some kind of state has changed.
public interface Sorter {
public interface Observer {
public void swap(int from, int to);
public void setCurrent(int current);
public void setTraverse(int traverse);
}
public int[] sort(int[] values, Observer observer);
}
Okay, pretty basic, but the nice idea behind this anything that changes the values can be used, for example, we can shuffle the values through the interface...
public class ShuffleSorter extends AbstractSorter {
#Override
public int[] sort(int[] original, Observer observer) {
int[] values = Arrays.copyOf(original, original.length);
Random random = new Random();
for (int i = 0; i < values.length; i++) {
int swap = random.nextInt(values.length - 1);
fireSetCurrent(observer, i);
fireSetTraverse(observer, i);
Helper.swap(values, i, swap);
fireSwap(observer, i, swap);
try {
Thread.sleep(5);
} catch (InterruptedException ex) {
}
}
return values;
}
}
And the insertion sorter...
public class InsertionSorter extends AbstractSorter {
#Override
public int[] sort(int[] original, Observer observer) {
int[] values = Arrays.copyOf(original, original.length);
for (int current = 1; current < values.length; current++) {
int traverse = current;
fireSetCurrent(observer, current);
fireSetTraverse(observer, traverse);
while (traverse > 0 && values[traverse] < values[traverse - 1]) {
Helper.swap(values, traverse, traverse - 1);
fireSwap(observer, traverse, traverse - 1);
traverse--;
fireSetTraverse(observer, traverse);
try {
Thread.sleep(5);
} catch (InterruptedException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
fireSetCurrent(observer, values.length - 1);
fireSetTraverse(observer, values.length - 1);
return values;
}
}
The idea here is the sorters will generate events telling what's changed, so you can apply those changes to the view independently of the sorters, so you don't risk dirty updates.
And finally, the SwingWorker
public class SortWorker extends SwingWorker<Void, Void> {
private Sorter sorter;
private int[] values;
private Sorter.Observer observer;
public SortWorker(int[] values, Sorter sorter, Sorter.Observer observer) {
this.sorter = sorter;
this.values = values;
this.observer = observer;
}
#Override
protected Void doInBackground() throws Exception {
int[] shuffled = new ShuffleSorter().sort(values, observer);
sorter.sort(shuffled, observer);
return null;
}
}
Now, this will shuffle the values and the re-sort them as a single unit of work.
Runnable example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Arrays;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new SortPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class SortPane extends JPanel {
final int SCREEN_WIDTH = 1280;
final int SCREEN_HEIGHT = 720;
final int BAR_HEIGHT = SCREEN_HEIGHT * 4 / 5;
final int BAR_WIDTH = 5;
final int NUM_BARS = SCREEN_WIDTH / BAR_WIDTH;
private JButton bubbleSort = new JButton();
private JButton insertSort = new JButton();
private int[] values = new int[NUM_BARS];
private int current = 0;
private int traverse = 0;
public SortPane() {
for (int i = 0; i < NUM_BARS; i++) {
values[i] = i * BAR_HEIGHT / NUM_BARS;
}
//InsertionSort Button
insertSort.setText("Insertion Sort");
this.add(insertSort);
insertSort.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
insertSort.setEnabled(false);
bubbleSort.setEnabled(false);
current = 0;
traverse = 0;
SortWorker sortWorker = new SortWorker(values, new InsertionSorter(), new Sorter.Observer() {
#Override
public void swap(int from, int to) {
SwingUtilities.invokeLater(() -> {
Helper.swap(values, from, to);
repaint();
});
}
#Override
public void setCurrent(int current) {
SwingUtilities.invokeLater(() -> {
SortPane.this.current = current;
repaint();
});
}
#Override
public void setTraverse(int traverse) {
SwingUtilities.invokeLater(() -> {
SortPane.this.traverse = traverse;
repaint();
});
}
});
sortWorker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (sortWorker.getState() == SwingWorker.StateValue.DONE) {
insertSort.setEnabled(true);
bubbleSort.setEnabled(true);
}
}
});
sortWorker.execute();
}
});
//BubbleSort Button
bubbleSort.setText("Bubble Sort");
this.add(bubbleSort);
bubbleSort.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g.setColor(Color.white);
for (int i = 0; i < values.length; i++) {
g2d.fillRect(i * BAR_WIDTH, SCREEN_HEIGHT - values[i], BAR_WIDTH, values[i]);
}
g2d.setColor(Color.green);
g2d.fillRect(current * BAR_WIDTH, SCREEN_HEIGHT - values[current], BAR_WIDTH, values[current]);
g2d.setColor(Color.red);
g2d.fillRect(traverse * BAR_WIDTH, SCREEN_HEIGHT - values[traverse], BAR_WIDTH, values[traverse]);
g2d.dispose();
}
}
public class Helper {
public static void swap(int[] values, int indexOne, int indexTwo) {
int temp = values[indexOne];
values[indexOne] = values[indexTwo];
values[indexTwo] = temp;
}
}
public interface Sorter {
public interface Observer {
public void swap(int from, int to);
public void setCurrent(int current);
public void setTraverse(int traverse);
}
public int[] sort(int[] values, Observer observer);
}
public abstract class AbstractSorter implements Sorter {
protected void fireSwap(Observer obserer, int from, int to) {
obserer.swap(from, to);
}
protected void fireSetCurrent(Observer obserer, int current) {
obserer.setCurrent(current);
}
protected void fireSetTraverse(Observer obserer, int traverse) {
obserer.setTraverse(traverse);
}
}
public class ShuffleSorter extends AbstractSorter {
#Override
public int[] sort(int[] original, Observer observer) {
int[] values = Arrays.copyOf(original, original.length);
Random random = new Random();
for (int i = 0; i < values.length; i++) {
int swap = random.nextInt(values.length - 1);
fireSetCurrent(observer, i);
fireSetTraverse(observer, i);
Helper.swap(values, i, swap);
fireSwap(observer, i, swap);
try {
Thread.sleep(5);
} catch (InterruptedException ex) {
}
}
return values;
}
}
public class InsertionSorter extends AbstractSorter {
#Override
public int[] sort(int[] original, Observer observer) {
int[] values = Arrays.copyOf(original, original.length);
for (int current = 1; current < values.length; current++) {
int traverse = current;
fireSetCurrent(observer, current);
fireSetTraverse(observer, traverse);
while (traverse > 0 && values[traverse] < values[traverse - 1]) {
Helper.swap(values, traverse, traverse - 1);
fireSwap(observer, traverse, traverse - 1);
traverse--;
fireSetTraverse(observer, traverse);
try {
Thread.sleep(5);
} catch (InterruptedException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
fireSetCurrent(observer, values.length - 1);
fireSetTraverse(observer, values.length - 1);
return values;
}
}
public class SortWorker extends SwingWorker<Void, Void> {
private Sorter sorter;
private int[] values;
private Sorter.Observer observer;
public SortWorker(int[] values, Sorter sorter, Sorter.Observer observer) {
this.sorter = sorter;
this.values = values;
this.observer = observer;
}
#Override
protected Void doInBackground() throws Exception {
int[] shuffled = new ShuffleSorter().sort(values, observer);
sorter.sort(shuffled, observer);
return null;
}
}
}
Food for thought...
A different approach would be to sort the values and in the process generate a series of "events" which describe what actions are been carried out. This would allow you to take the same starting data and apply those actions in a more controlled manner (using a Swing Timer for example). This would reduce some of the overhead of having to copy the array data each time an update occurs.
If you're interested, I've done an example here
An slightly simpler alternative to (though based on an intermediate state of) MadProgrammer's answer - the intention is to use as few custom notification patterns/classes as possible (== zero :)
The collaborators:
an immutable SorterModel to encapsulate the current sort progress (same as intermediate in the other answer)
a custom Worker does the sorting in the background and publishes intermediate sort states as property changes: there's a base class for doing the bookkeeping and notification, subclasses are specialized on a concrete actual (un-) sort algorithm
a custom panel to visualize a SorterModel and logic to trigger a sort and to update itself according to the changes reported from the worker
The Worker is very similar to the intermediate in the other answer, differs in how it publishes its values: here it uses its own property change api to notify interested parties.
#Override
protected void process(List<SorterModel> chunks) {
SorterModel last = chunks.get(chunks.size() - 1);
firePropertyChange("value", null, last);
}
Subclasses simply use the standard mechanism to publish intermediate result
#Override
protected SorterModel doInBackground() throws Exception {
// do sorting step
publish(new SorterModel(<current state>));
..
}
The custom panel is very similar to the other answer, except for the logic to start sorting / update visual state. Now that's extracted (from the button's action listeners) into a separate method to configure a specialized worker, register a property change listener and update the view's model (and related state like button enable) in that listener:
private void process(SortWorker worker, SortWorker next) {
updateEnabled(false);
worker.setModel(getSorterModel());
worker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if ("value".equals(evt.getPropertyName())) {
setSorterModel((SorterModel) evt.getNewValue());
}
if (SwingWorker.StateValue.DONE == evt.getNewValue()) {
try {
setSorterModel(worker.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
if (next != null) {
process(next, null);
} else {
updateEnabled(true);
}
}
}
});
worker.execute();
}
It's usage from a buttons action might be:
insertSort.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
process(new ShuffleWorker(), new InsertionSortWorker());
}
});
Note:
the sort classes (worker/model) are unaware of who is using them and do not require a custom observer/n
the sort trigger/update logic is decoupled from the view - all it needs is a source/target for the model and some enablement toggle. It still resides in the view, though - being lazy, and we had to subclass anyway for custom painting.
Pulling all together into a runnable example:
package so.notfx.swing;
public class SortAnimation {
public class SortPane extends JPanel {
final int SCREEN_WIDTH = 800;
final int SCREEN_HEIGHT = 600;
final int BAR_HEIGHT = SCREEN_HEIGHT * 4 / 5;
final int BAR_WIDTH = 5;
final int NUM_BARS = SCREEN_WIDTH / BAR_WIDTH;
private JButton shuffle = new JButton();
private JButton bubbleSort = new JButton();
private JButton insertSort = new JButton();
private int[] values = new int[NUM_BARS];
private SorterModel model;
public SortPane() {
for (int i = 0; i < NUM_BARS; i++) {
values[i] = i * BAR_HEIGHT / NUM_BARS;
}
model = new SorterModel(values, 0, 0);
// shuffle button to trigger random values
shuffle.setText("Shuffle Values");
add(shuffle);
shuffle.addActionListener(e -> {
process(new ShuffleWorker(), null);
});
// InsertionSort Button
insertSort.setText("Insertion Sort");
this.add(insertSort);
insertSort.addActionListener(e -> {
process(new ShuffleWorker(), new InsertionSortWorker());
});
// BubbleSort Button
bubbleSort.setText("Bubble Sort");
this.add(bubbleSort);
bubbleSort.addActionListener(e -> {
// NYI
});
}
//--------------- sort related
public void setSorterModel(SorterModel model) {
this.model = model;
repaint();
}
public SorterModel getSorterModel() {
return model;
}
private void updateEnabled(boolean enabled) {
shuffle.setEnabled(enabled);
insertSort.setEnabled(enabled);
bubbleSort.setEnabled(enabled);
}
private void process(SortWorker worker, SortWorker next) {
updateEnabled(false);
worker.setModel(getSorterModel());
worker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if ("value".equals(evt.getPropertyName())) {
setSorterModel((SorterModel) evt.getNewValue());
}
if (SwingWorker.StateValue.DONE == evt.getNewValue()) {
try {
setSorterModel(worker.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
if (next != null) {
process(next, null);
} else {
updateEnabled(true);
}
}
}
});
worker.execute();
}
//------------------------
#Override
public Dimension getPreferredSize() {
return new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g.setColor(Color.white);
for (int i = 0; i < model.length(); i++) {
g2d.fillRect(i * BAR_WIDTH, SCREEN_HEIGHT - model.valueAt(i), BAR_WIDTH, model.valueAt(i));
}
int current = model.getCurrent();
g2d.setColor(Color.green);
g2d.fillRect(current * BAR_WIDTH, SCREEN_HEIGHT - model.valueAt(current), BAR_WIDTH,
model.valueAt(current));
int traverse = model.getTraverse();
g2d.setColor(Color.red);
g2d.fillRect(traverse * BAR_WIDTH, SCREEN_HEIGHT - model.valueAt(traverse), BAR_WIDTH,
model.valueAt(traverse));
g2d.dispose();
}
}
public static void main(String[] args) {
new SortAnimation();
}
public SortAnimation() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new SortPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
which is using the support class:
package so.notfx.swing;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import javax.swing.SwingWorker;
/**
* Utility class for sort animation.
* Contains a SorterModel with current sort state and workers that are doing
* the sorting on the background thread and publishing intermediate results
* as property changes with name "value".
*/
public class SortAnimationSupport {
/**
* Base class: bookkeeping, helper and publish a property change for its value. Subclasses are supposed to
* implement the actual sorting in the background and publish a new SorterModel with the current sort
* state when appropriate.
*/
public static abstract class SortWorker extends SwingWorker<SorterModel, SorterModel> {
int[] values;
public void setModel(SorterModel model) {
if (getState() != StateValue.PENDING)
throw new IllegalStateException("model must not be modified after starting the worker");
values = Arrays.copyOf(model.getValues(), model.getValues().length);
}
#Override
protected void process(List<SorterModel> chunks) {
SorterModel last = chunks.get(chunks.size() - 1);
firePropertyChange("value", null, last);
}
protected void swap(int indexOne, int indexTwo) {
int temp = values[indexOne];
values[indexOne] = values[indexTwo];
values[indexTwo] = temp;
}
}
/**
* Use insertion sort.
*/
public static class InsertionSortWorker extends SortWorker {
#Override
protected SorterModel doInBackground() throws Exception {
for (int current = 1; current < values.length; current++) {
int traverse = current;
while (traverse > 0 && values[traverse] < values[traverse - 1]) {
swap(traverse, traverse - 1);
traverse--;
publish(new SorterModel(values, current, traverse));
Thread.sleep(5);
}
}
SorterModel model = new SorterModel(values, values.length - 1, values.length - 1);
publish(model);
return model;
}
}
/**
* Unsort.
*/
public static class ShuffleWorker extends SortWorker {
#Override
protected SorterModel doInBackground() throws Exception {
Random random = new Random();
for (int i = 0; i < values.length; i++) {
int swap = random.nextInt(values.length - 1);
swap(i, swap);
publish(new SorterModel(values, i, 0));
Thread.sleep(5);
}
SorterModel model = new SorterModel(values, values.length - 1, 0);
publish(model);
return model;
}
}
/**
* SorterModel: encapsulates the state of a sort process.
* Note: it has to keep its values immutable, so copying the array
*/
public static class SorterModel {
protected int[] values;
protected int current;
protected int traverse;
public SorterModel(int[] array, int current, int traverse) {
this.values = Arrays.copyOf(array, array.length);
this.current = current;
this.traverse = traverse;
}
public int[] getValues() {
return Arrays.copyOf(values, values.length);
}
public int length() {
return values.length;
}
public int valueAt(int index) {
return values[index];
}
public int getCurrent() {
return current;
}
public int getTraverse() {
return traverse;
}
}
private SortAnimationSupport() {
}
}
I'm trying to create an example with some graphics for a ´Stack´.
I want the Wagons to "Spawn" and move in one track which are the ´stacks´.
The moving process is made by the ´Wagon´ itself. I already tried to give the Wagon a reference to my ´Frame´ called ´Window´ to repaint it in every loop but it still doesn't show up until it reached it's stop.
Wagon:
import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class Window extends JFrame {
private Stack stack1 = new Stack(1);
public Window() {
setSize(800, 400);
setResizable(false);
setLayout(null); //Not perfect, but it works for those little things
setVisible(true);
createTracks(); //Tracksgraphic made out of gray rects
}
public void addWagon(Wagon wagon) { //Is called when adding a Wagon
this.add(wagon);
stack1.addWagon(wagon);
}
public static void main(String[] args) { //main
new Window();
}
}
Stack:
public class Stack {
private int gleis; //gleis = german for track
private Wagon first = null;
public Stack(int g) {
gleis = g;
}
public void addWagon(Wagon wagon) {
if (first != null) {
wagon.setNext(first);
}
first = wagon;
first.moveRight(gleis);
}
public void removeWagon(int id, Stack nextStack) {
Wagon speicherFirst = first;
first.moveLeft(null);
first = first.getNext();
while (speicherFirst.getID() != id) {
speicherFirst.setNext(first);
first.moveLeft(speicherFirst);
speicherFirst = first;
first = first.getNext();
}
nextStack.addWagon(speicherFirst);
if (speicherFirst.getNext() != null) {
speicherFirst = speicherFirst.getNext();
while (speicherFirst!= null) {
speicherFirst.moveRight(gleis);
speicherFirst = speicherFirst.getNext();
}
}
}
public boolean hasID(int id) {
return first.isID(id);
}
}
Wagon:
import javax.swing.*;
import java.awt.*;
import java.util.Random;
public class Wagon extends JPanel { //Entspricht einem Canvas aus .awt
private Wagon next;
private int id;
public Wagon(int i) {
id = i;
setSize(50, 20);
Random r = new Random();
setBackground(new Color(r.nextFloat(), r.nextFloat(), r.nextFloat()));
setVisible(true);
}
public boolean isID(int i) {
if (id == i) {
return true;
} else if (next == null) {
return false;
} else {
return next.isID(i);
}
}
public void setNext(Wagon n) {
next = n;
}
public void moveRight(int gleis) {
setLocation(getX(), gleis * 100);
if (next != null) {
while (next.getX() - getX() < 70) {
next.moveRight(gleis);
move(3);
}
} else {
while (getX() < 700) {
move(3);
}
}
}
public Wagon getNext() {
return next;
}
public int getID() {
return id;
}
public void moveLeft(Wagon previous) {
if (previous == null) {
while (getX() > 50) {
move(-3);
}
} else {
while (getX() - previous.getX() > 50) {
move(-3);
}
}
}
public void move(int dir) {
this.setLocation(getX() + dir, getY());
try {
Thread.sleep(20);
} catch (InterruptedException e) {}
}
}
it still doesn't show up until it reached it's stop.
Your code is executing on the Event Dispatch Thread (EDT), which is the thread that is responsible for handling GUI events and repainting the GUI. The Thread.sleep() prevents the GUI from repainting itself until the while/loop is finished executing so you only see the painting at the end. Read the section from the Swing tutorial on Concurrency for more information.
The solution is to use a Swing Timer to provide the animation, not Thread.sleep().
It looks like you don't actually have the replaint(); call anywhere in your code. I would have that in both the moveLeft() and moveRight() commands.
Another thing, you're using JPanels as your wagons. I wouldn't do this, it'll take more resources and is bad practice. Unless there's a specific reason, I'd use a base sprite image, and load it to an int[] array, and paint that array to that screen using BufferedImage, instead of having x number of JPanel's running around.
Invoke javax.swing.Timer#start() same time,
7u25 is not problem.
but 7u40 is big problem.
Too laggy invoke ActionListener#actionPerformed. (basically same time invoke u25)
Totally different move between u25 and u40. (I use Windows 8)
I bug report but still not add bug tracking system. Oracle crushing swing apps?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TimerProblem extends JComponent {
int red = 0;
TimerProblem(final long startMs) {
setPreferredSize(new Dimension(10, 10));
Timer t = new Timer(16, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
red = (int)(System.currentTimeMillis() - startMs) % 255;
repaint();
}
});
t.setInitialDelay(1000);
t.start();
}
#Override
protected void paintComponent(Graphics g) {
g.setColor(new Color(red, 255 - red, 0));
g.fillRect(0, 0, getWidth(), getHeight());
}
public static void main(String[] args) {
JFrame f = new JFrame();
Container c = f.getContentPane();
c.setLayout(new GridLayout(10, 10));
long startMs = System.currentTimeMillis();
for (int i = 0; i < 100; i++) {
c.add(new TimerProblem(startMs));
}
f.pack();
f.setVisible(true);
}
}
Several issues arise in your example:
Swing GUI objects should be constructed and manipulated only on the event dispatch thread.
All Swing Timer instances share a common thread, which is being saturated.
Depending on the goal, some alternatives are possible:
Use a single Timer instance, and select some fraction for update at a proportionally higher rate. The example below randomly selects N of the components and updates them every 100 ms.
Use TexturePaint, as shown here.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.swing.*;
/** #see https://stackoverflow.com/a/18936444/230513 */
public class BlinkenLights {
private static final int S = 24;
private static final int N = 10;
private static final Random r = new Random();
private static final List<MyComponent> list = new ArrayList<MyComponent>();
private static final class MyComponent extends JComponent {
public MyComponent() {
this.setOpaque(true);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(S, S);
}
#Override
protected void paintComponent(Graphics g) {
g.setColor(Color.getHSBColor(r.nextFloat() / 6, 1, 1));
g.fillRect(0, 0, getWidth(), getHeight());
}
}
private static JPanel createPanel() {
final JPanel p = new JPanel();
p.setLayout(new GridLayout(N, N));
for (int i = 0; i < N * N; i++) {
MyComponent c = new MyComponent();
p.add(c);
list.add(c);
}
Timer t = new Timer(1000 / N, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Collections.shuffle(list, r);
for (int i = 0; i < N; i++) {
list.get(i).repaint();
}
}
});
t.start();
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(createPanel());
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
}
Finally I write DIY repaint management class .. :(
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
/**
* EffectTimer
*/
public class EffectTimer {
/**
* All of effect timers in instance of this class.
*/
static class GlobalTimer implements ActionListener {
List<EffectTimer> registeredEffects = new ArrayList<>();
Timer timer = new Timer(16, this);
public void start(final EffectTimer t) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
internalStart(t);
}
});
}
void internalStart(EffectTimer t) {
int initialDelay = Math.max(0, (int) (t.getEffectStartTime() - System.currentTimeMillis()));
if(timer.getInitialDelay() >= initialDelay) {
timer.setInitialDelay(initialDelay);
}
if(!registeredEffects.contains(t)) {
registeredEffects.add(t);
if(registeredEffects.size() == 1) {
timer.start();
}
}
}
void stop(final EffectTimer t) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
registeredEffects.remove(t);
checkStop();
}
});
}
#Override
public void actionPerformed(ActionEvent e) {
long now = e.getWhen();
Iterator<EffectTimer> iter = registeredEffects.iterator();
while(iter.hasNext()) {
EffectTimer t = iter.next();
long elapsedMs = now - t.getEffectStartTime();
if(elapsedMs > 0) {
float p = elapsedMs / (float)t.getEffectLengthMs();
if(p >= 1.0f) {
iter.remove();
t.stop();
} else {
if(t.isReversed()) {
p = 1.0f - p;
}
t.progressChanged(p);
}
}
}
checkStop();
}
void checkStop() {
if(registeredEffects.isEmpty()) {
timer.stop();
}
}
public int getRunningTimerCount() {
return registeredEffects.size();
}
public void stopAll() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
registeredEffects.clear();
checkStop();
}
});
}
}
static final GlobalTimer GTIMER = new GlobalTimer();
int effectLengthMs = -1;
long effectStartMs = -1;
float progress = 0.0f;
boolean reversed = true;
public long getEffectStartTime() {
return effectStartMs;
}
public int getEffectLengthMs() {
return effectLengthMs;
}
public void start(int lengthMs) {
start(lengthMs, System.currentTimeMillis());
}
public void start(int lengthMs, long startMs) {
effectLengthMs = lengthMs;
effectStartMs = startMs;
reversed = false;
progress = 0.0f;
GTIMER.start(this);
}
public boolean isReversed() {
return reversed;
}
public void reverse(final int lengthMs) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
internalReverse(lengthMs);
}
});
}
void internalReverse(int lengthMs) {
reversed = !reversed;
effectLengthMs = lengthMs;
int adjust = reversed ? (int)(lengthMs * (1.0f - progress)) : (int)(lengthMs * progress);
effectStartMs = System.currentTimeMillis() - adjust;
GTIMER.start(this);
}
final public void progressChanged(float p) {
progress = p;
run(p);
}
/**
* 0.0f to 1.0f effect progress.
* <code>Float.compare(progress, 1.0f) >= 0</code> to end progress.
*/
protected void run(float p) {}
public void stop() {
progress = reversed ? 0.0f : 1.0f;
GTIMER.stop(this);
}
public boolean isRunning() {
return 0.0f < progress && progress < 1.0f;
}
public float getProgress() {
return progress;
}
public static int getRunningTimerCount() {
return GTIMER.getRunningTimerCount();
}
public static void stopAll() {
GTIMER.stopAll();
}
}
There are no errors showing up in eclipse, but when I go to run the code, nothing happens in the application. It is broken up into three classes. The first class contains the if statements. I am wondering if my issue lies here.
package course.infsci0017.lab04;
import java.util.Scanner;
import javax.swing.JFrame;
public class GameOfLife {
public static void main(String[] args) {
int testCase = 1;
JFrame frame = new JFrame();
frame.setSize(500, 500);
frame.setTitle("Conway's Game of Life");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Cell[][] universe = new Cell[100][100];
for (int x = 0; x < universe.length-1; x++) {
for (int y = 0; y < universe[x].length-1; y++) {
universe[x][y] = new Cell();
}
}
if (testCase == 1) {
universe[3][2].calculateNext(3);
universe[3][2].updateCurrent();
universe[3][3].calculateNext(3);
universe[3][3].updateCurrent();
universe[3][4].calculateNext(3);
universe[3][4].updateCurrent();
} else if (testCase == 2) {
universe[49][50].calculateNext(3);
universe[49][50].updateCurrent();
universe[49][51].calculateNext(3);
universe[49][51].updateCurrent();
universe[50][49].calculateNext(3);
universe[50][49].updateCurrent();
universe[50][50].calculateNext(3);
universe[50][50].updateCurrent();
universe[51][50].calculateNext(3);
universe[51][50].updateCurrent();
} else {
}
UniverseComponent component = new UniverseComponent(universe);
frame.add(component);
frame.setVisible(true);
Scanner in = new Scanner(System.in);
String input = in.nextLine();
while (input.length() == 0) {
int neighborCount = 0;
for (int x=1; x<universe.length-2; x++) {
for (int y=1; y<universe[x].length-2; y++) {
neighborCount = 0;
if (universe[x-1][y-1].isAlive()) {
neighborCount++;
}
if (universe[x-1][y].isAlive()) {
neighborCount++;
}
if (universe[x-1][y+1].isAlive()) {
neighborCount++;
}
if (universe[x][y-1].isAlive()) {
neighborCount++;
}
if (universe[x][y+1].isAlive()) {
neighborCount++;
}
if (universe[x+1][y-1].isAlive()) {
neighborCount++;
}
if (universe[x+1][y].isAlive()) {
neighborCount++;
}
if (universe[x+1][y+1].isAlive()) {
neighborCount++;
}
universe[x][y].calculateNext(neighborCount);
}
}
for (int x=1; x<universe.length-2; x++) {
for (int y=1; y<universe[x].length-2; y++) {
universe[x][y].updateCurrent();
}
}
component.repaint();
input = in.nextLine();
}
in.close();
}
}
Class 2
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JComponent;
public class UniverseComponent extends JComponent {
private Cell[][] universe;
public UniverseComponent(Cell[][] universe) {
super();
this.universe = universe;
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
for (int x=0; x<universe.length-1; x++) {
for (int y=0; y<universe[x].length-1; y++) {
if (universe[x][y].isAlive()) {
g2.fillRect(x*5, y*5, 4, 4);
}
}
}
}
}
Class 3
public class Cell {
private boolean current;
private boolean next;
public Cell() {
current = false;
next = false;
}
public Cell(int neighborCount) {
calculateNext(neighborCount);
updateCurrent();
}
public void calculateNext(int neighborCount) {
if (current) {
if ((neighborCount < 2) || (neighborCount > 3)) {
next = false;
} else {
next = true;
}
} else {
if (neighborCount == 3) {
next = true;
} else {
next = false;
}
}
}
public void updateCurrent() {
current = next;
}
public boolean isAlive() {
return current;
}
}
If any one has any idea what how to fix this please let me know. Feel free to copy and paste code if necessary. It will not let me post an image because i do not have enough reputation. Apologies
Your while loop says
while (input.length() == 0)
But if you type anything into the input at all, it will not be equal to zero, so the loop will not be executed and your program will exit.
The program seems to be designed to only allow the user to hit 'enter' without typing any words at the console. That is, the loop will be executed if you type nothing but enter, otherwise the program will exit.
This is obviously not your own code, since it doesn't appear to have a bug after all but your usage of it is incorrect. Please be more honest with your questions (and I hope you haven't been plagiarising).
My program visually demonstrates a sequential version of the well known QuickSort algorithm, with two new visual demonstrations: (I) a parallel version of QuickSort, implemented using low level Thread API and SwingUtilities, and (II) a parallel version of QuickSort, implemented using SwingWorker API.
I am trying to have a facility to restart the program after a successful run. Currently, the buttons are disabled when the sorting operation starts, which is correct, but they never re-enable and so I was wondering if there is a way to enable all the buttons after the successful run? Some of the code is as follows:
// http://www.java2s.com/Code/Java/Collections-Data-Structure/Animationforquicksort.htm
// http://www.sorting-algorithms.com/quick-sort
import java.lang.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Rectangle2D;
import java.util.*;
import javax.swing.*;
import java.util.concurrent.atomic.*;
public class QuickSortVisualizer implements Runnable {
static int LENGTH = 32;
static int LEFT = 500;
static int RIGHT = 500;
static int SWAP = 1000;
int[] Values;
AtomicInteger WorkerThreads = new AtomicInteger();
public static void main(String[] args) {
try {
if (args.length == 0) {
LENGTH = 32;
LEFT = 500;
RIGHT = 500;
SWAP = 1000;
} else if (args.length == 4) {
//dw about this
} else {
throw new Exception("incorrect command-line argument count");
}
System.err.format("... LENGTH=%d LEFT=%d RIGHT=%d SWAP=%d%n", LENGTH, LEFT, RIGHT, SWAP);
SwingUtilities.invokeAndWait(new QuickSortVisualizer());
System.err.format("... GUI started%n");
} catch (Exception ex) {
System.err.format("*** %s%n", ex.getMessage());
}
}
JButton BoredButton;
JButton WorkerButtonSequential;
JButton WorkerButtonThreads;
JButton WorkerButtonSwingWorkers;
SorterPanel MySortPanel;
JLabel StatusBar;
public void run() {
JFrame frame = new JFrame();
frame.setTitle("My Quick Sort Visualizer");
Font font = new Font("Monospaced", Font.BOLD, 18);
BoredButton = new JButton("I am bored");
BoredButton.setFont(font);
BoredButton.setPreferredSize(new Dimension(180, 30));
BoredButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
BoredButton_Click();
}
});
WorkerButtonSequential = new JButton("QS Sequential");
WorkerButtonSequential.setFont(font);
WorkerButtonSequential.setPreferredSize(new Dimension(185, 30));
WorkerButtonSequential.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
WorkerButtonSequential_Click();
}
});
WorkerButtonThreads = new JButton("QS Threads");
WorkerButtonThreads.setFont(font);
WorkerButtonThreads.setPreferredSize(new Dimension(185, 30));
WorkerButtonThreads.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
WorkerButtonThreads_Click();
}
});
WorkerButtonSwingWorkers = new JButton("QS SwingWorkers");
WorkerButtonSwingWorkers.setFont(font);
WorkerButtonSwingWorkers.setPreferredSize(new Dimension(200, 30));
WorkerButtonSwingWorkers.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
WorkerButtonSwingWorkers_Click();
}
});
JPanel strip = new JPanel(new FlowLayout(FlowLayout.CENTER));
strip.add(BoredButton);
strip.add(WorkerButtonSequential);
strip.add(WorkerButtonThreads);
strip.add(WorkerButtonSwingWorkers);
frame.getContentPane().add(strip, BorderLayout.NORTH);
StatusBar = new JLabel();
StatusBar.setFont(font);
StatusBar.setPreferredSize(new Dimension(800, 20));
frame.getContentPane().add(StatusBar, BorderLayout.SOUTH);
MySortPanel = new SorterPanel();
frame.getContentPane().add(MySortPanel, BorderLayout.CENTER);
frame.getRootPane().setDefaultButton(BoredButton);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 400);
frame.setResizable(true);
frame.setVisible(true);
}
public void BoredButton_Click() {
String text = Calendar.getInstance().getTime().toString();
StatusBar.setText(text);
System.err.format("... now %s%n", text);
}
public void WorkerButtonSequential_Click() {
WorkerButtonSequential.setEnabled(false);
WorkerButtonThreads.setEnabled(false);
WorkerButtonSwingWorkers.setEnabled(false);
System.err.format("... sequential%n");
QSSequential();
}
public void WorkerButtonThreads_Click() {
WorkerButtonSequential.setEnabled(false);
WorkerButtonThreads.setEnabled(false);
WorkerButtonSwingWorkers.setEnabled(false);
int processors = Runtime.getRuntime().availableProcessors();
int threshold = processors * 2;
System.err.format("... parallel threads: processors=%d threshold=%d%n", processors, threshold);
QSThreads(threshold);
}
public void WorkerButtonSwingWorkers_Click() {
WorkerButtonSequential.setEnabled(false);
WorkerButtonThreads.setEnabled(false);
WorkerButtonSwingWorkers.setEnabled(false);
int processors = Runtime.getRuntime().availableProcessors();
int threshold = processors * 2;
System.err.format("... parallel swingworkers: processors=%d threshold=%d%n", processors, threshold);
QSSwingWorkers(threshold);
}
void QSInit() {
Values = new int[LENGTH];
for (int i = 0; i < Values.length; i++) {
Values[i] = (int)Math.round(Math.random() * (MySortPanel.getHeight()-10));
}
print("... initial values");
MySortPanel.setValues(Values);
}
void QSSequential() {
QSInit();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
QuickSortSequential qss = new QuickSortSequential(Values, 0, Values.length - 1, MySortPanel);
System.err.format("... started%n");
qss.run();
DoneAll();
}
});
}
void QSThreads(int threshold) {
QSInit();
QuickSortThread qst = new QuickSortThread(Values, 0, Values.length - 1, threshold, MySortPanel);
WorkerThreads.set(0);
incWorkerThreads();
System.err.format("... started%n");
qst.start();
}
void QSSwingWorkers(int threshold) {
QSInit();
QuickSortWorker qsw = new QuickSortWorker(Values, 0, Values.length - 1, threshold, MySortPanel);
WorkerThreads.set(0);
incWorkerThreads();
System.err.format("... started%n");
qsw.execute();
}
void print(String caption) {
System.err.format("%s%n", caption);
for (int i=0; i<Values.length; i++) {
System.err.format(" %d:%d", i, Values[i]);
}
System.err.format("%n");
}
void incWorkerThreads() {
int w = WorkerThreads.incrementAndGet();
System.err.format("... workers=%d%n", w);
}
void decWorkerThreads() {
int w = WorkerThreads.decrementAndGet();
System.err.format("... workers=%d%n", w);
if (w <= 0) DoneAll();
}
void DoneAll() {
print("... sorted values");
WorkerButtonSequential.setEnabled(true);
WorkerButtonThreads.setEnabled(true);
WorkerButtonSwingWorkers.setEnabled(true);
System.err.format("%n");
}
// === SorterPanel
/* colour codes
pivot : YELLOW
left item : GREEN
right item : BLUE
left item just before swap : PINK
right item just before swap : PINK
left item just after swap : RED
right item just after swap : RED
*/
class SorterPanel extends JComponent {
int[] Values;
int width;
Graphics2D g2;
Color pen;
Color back;
public void setValues(int[] Values) {
this.Values = Values;
width = super.getWidth() / Values.length;
repaint();
}
#Override
public void paintComponent(Graphics g) {
if (Values == null) return;
g2 = (Graphics2D) g;
pen = Color.BLACK; // g2.getColor();
back = g2.getBackground();
for (int i = 0; i < Values.length; i++) {
g2.draw(new Rectangle2D.Double(width*i+1, 0, width-2, Values[i]));
}
}
public void mark(int i, int value, Color m) {
g2 = (Graphics2D) super.getGraphics();
pen = g2.getColor();
g2.setColor(m);
//g2.fill(new Rectangle2D.Double(width*i+2, 1, width-4, Values[i]-2));
g2.fill(new Rectangle2D.Double(width*i+2, 1, width-4, value-2));
g2.setColor(pen);
}
public void unmark(final int i, final int value) {
mark(i, value, back);
}
public void erase(int i, int value) {
g2 = (Graphics2D) super.getGraphics();
//g2.clearRect(width*i+1, 0, width-1, Values[i]+1);
g2.clearRect(width*i+1, 0, width-1, value+1);
}
public void redraw(int i, int value) {
g2 = (Graphics2D) super.getGraphics();
//g2.draw(new Rectangle2D.Double(width*i+1, 0, width-2, Values[i]));
g2.draw(new Rectangle2D.Double(width*i+1, 0, width-2, value));
mark(i, value, back);
}
}
// === QuickSort Sequential
class QuickSortSequential implements Runnable {
int[] array;
int left;
int right;
// === GUI stuff
SorterPanel sortpan;
void publish(Runnable gui_update) {
gui_update.run();
}
void mark(final int idx, final Color color) {
final int value = array[idx];
publish(new Runnable() {
public void run() {
sortpan.mark(idx, value, color);
}
});
}
void unmark(final int idx) {
final int value = array[idx];
publish(new Runnable() {
public void run() {
sortpan.unmark(idx, value);
}
});
}
void erase(final int idx) {
final int value = array[idx];
publish(new Runnable() {
public void run() {
sortpan.erase(idx, value);
}
});
}
void redraw(final int idx) {
final int value = array[idx];
publish(new Runnable() {
public void run() {
sortpan.redraw(idx, value);
}
});
}
void sleep(int period) {
try {
Thread.sleep(period);
} catch (Exception ex) {
System.err.format("%s%n", ex.getMessage());
}
}
// === stuff
public QuickSortSequential(final int array[], final int left, final int right, final SorterPanel sortpan) {
this.array = array;
this.left = left;
this.right = right;
this.sortpan = sortpan;
}
public void run() {
QuickSort();
}
// === QuickSort stuff
void QuickSort() {
if (left >= right) return;
final int pivot = Partition();
if (pivot < 0) return;
QuickSortSequential lquick = new QuickSortSequential(array, left, pivot-1, sortpan);
QuickSortSequential rquick = new QuickSortSequential(array, pivot, right, sortpan);
lquick.run();
rquick.run();
}
int Partition() {
int leftIdx = left;
int rightIdx = right;
int pivotIdx = (left + right) / 2;
final int pivot = array[pivotIdx];
while (true) {
if (leftIdx > rightIdx) break;
mark(pivotIdx, Color.YELLOW);
mark(leftIdx, Color.GREEN);
mark(rightIdx, Color.BLUE);
sleep(LEFT);
while (true) {
if (array[leftIdx] >= pivot) break;
else {
unmark(leftIdx);
leftIdx += 1;
mark(pivotIdx, Color.YELLOW);
mark(leftIdx, Color.GREEN);
sleep(LEFT);
}
}
while (true) {
if (pivot >= array[rightIdx]) break;
else {
unmark(rightIdx);
rightIdx -= 1;
mark(pivotIdx, Color.YELLOW);
mark(rightIdx, Color.BLUE);
sleep(RIGHT);
}
}
unmark(pivotIdx);
unmark(leftIdx);
unmark(rightIdx);
if (leftIdx <= rightIdx) {
if (leftIdx < rightIdx) {
mark(pivotIdx, Color.YELLOW);
mark(leftIdx, Color.PINK);
mark(rightIdx, Color.PINK);
sleep(SWAP);
erase(leftIdx);
erase(rightIdx);
int temp = array[rightIdx];
array[rightIdx] = array[leftIdx];
array[leftIdx] = temp;
if (pivotIdx == leftIdx) pivotIdx = rightIdx;
else if (pivotIdx == rightIdx) pivotIdx = leftIdx;
redraw(leftIdx);
redraw(rightIdx);
mark(pivotIdx, Color.YELLOW);
mark(leftIdx, Color.RED);
mark(rightIdx, Color.RED);
sleep(SWAP);
}
unmark(pivotIdx);
unmark(leftIdx);
unmark(rightIdx);
leftIdx += 1;
rightIdx -= 1;
}
}
return leftIdx;
}
}
// === QuickSort with Threads
class QuickSortThread extends Thread {
int[] array;
int left;
int right;
int threshold;
// === GUI stuff
SorterPanel sortpan;
// === Thread etc stuff
public QuickSortThread(final int array[], final int left, final int right, final int threshold, final SorterPanel sortpan) {
this.array = array;
this.left = left;
this.right = right;
this.sortpan = sortpan;
this.threshold = threshold;
}
#Override
public void run() {
decWorkerThreads();
}
}
// === QuickSort with SwingWorkers
class QuickSortWorker extends SwingWorker<Boolean, Runnable> {
int[] array;
int left;
int right;
int threshold;
// === GUI stuff
SorterPanel sortpan;
// === SwingWorker stuff
public QuickSortWorker(final int array[], final int left, final int right, final int threshold, final SorterPanel sortpan) {
this.array = array;
this.left = left;
this.right = right;
this.threshold = threshold;
this.sortpan = sortpan;
}
#Override
public Boolean doInBackground() {
return true;
}
#Override
public void process(java.util.List<Runnable> gui_updates) {
}
#Override
public void done() {
decWorkerThreads();
}
}
}
not directly the answers to your question, but there I see three areas, I think that your code missed
implements SwingWorker#cancel(), for restart of processes
implements PropertyChangeListener for listening changes from SwingWorker
invoke SwingWorker from Executor,
notice please read How to get Exception from SwingWorker