I have finally been able to get my thread to resume after some excellent advice from you guys, but am unable to stop it.. It seems to be locked still but i cannot get it to stop gracefully. here is the whole class so you can run it. I'm so close.. I think. I have commented out what i was attempting in the run and stopmethods
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package treadmakestop;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
*
* #author brett
*/
public class WorkFile {
public static void main(String[] args) {
WorkFile workFile = new WorkFile();
}
public WorkFile() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
}
JFrame frame = new JFrame("TvCOnvert");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TvGui());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setSize(350, 100);
frame.setResizable(false);
frame.setVisible(true);
}
});
}
public class TvGui extends JPanel {
private JProgressBar tvpb;
private JButton startButton;
private JButton cancelButton;
private JButton exitButton;
private Worker worker;
private Thread t;
public TvGui() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.anchor = GridBagConstraints.NORTHWEST;
startButton = new JButton();
startButton.setText("Start");
gbc.insets = new Insets(10, 5, 0, 0);
gbc.gridx = 1;
gbc.gridy = 2;
gbc.weightx = 0.5;
add(startButton, gbc);
cancelButton = new JButton();
gbc.insets = new Insets(10, 0, 0, 0);
gbc.gridx = 2;
gbc.gridy = 2;
gbc.weightx = 0.5;
cancelButton.setText("Cancel");
add(cancelButton, gbc);
exitButton = new JButton();
gbc.insets = new Insets(10, 0, 0, 5);
gbc.gridx = 3;
gbc.gridy = 2;
gbc.weightx = 0.5;
exitButton.setText("Exit");
add(exitButton, gbc);
tvpb = new JProgressBar();
tvpb.setBorderPainted(true);
tvpb.setStringPainted(true);
gbc.insets = new Insets(5, 5, 0, 5);
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.gridx = 1;
gbc.gridy = 3;
gbc.gridwidth = 3;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.anchor = GridBagConstraints.BASELINE;
add(tvpb, gbc);
tvpb.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
System.out.println(tvpb.getValue());
if (tvpb.getValue() >= 100) {
worker = null;
}
}
});
tvpb.addPropertyChangeListener("value", new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
}
});
startButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (worker == null) {
worker = new Worker(tvpb);
t = new Thread(worker);
t.start();
}
}
});
cancelButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
worker.pause();
tvpb.setIndeterminate(true);
int n = JOptionPane.showConfirmDialog(
null,
"Sure you want to delete this process?",
"Kill Operation",
JOptionPane.YES_NO_OPTION);
if (n == JOptionPane.YES_OPTION) {
worker.stop();
//t.interrupt();
//worker = null;
tvpb.setIndeterminate(false);
tvpb.setValue(0);
} else if (n == JOptionPane.NO_OPTION) {
tvpb.setIndeterminate(false);
worker.resume();
}
}
});
exitButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
}
}
public class Worker implements Runnable {
TvGui gu = new TvGui();
private ReentrantLock pauseLock;
private Condition pauseCondition;
private AtomicBoolean paused;
private JProgressBar tvpg;
public Worker(JProgressBar tvpg) {
paused = new AtomicBoolean();
pauseLock = new ReentrantLock();
pauseCondition = pauseLock.newCondition();
this.tvpg = tvpg;
}
public void pause() {
paused.set(true);
}
public void resume() {
paused.set(false);
pauseLock.lock();
try {
pauseCondition.signal();
} finally {
pauseLock.unlock();
}
}
public synchronized void stop(){
try {
// gu.t = null;
// gu.t.interrupt();
//Thread thr = Thread.currentThread();
System.out.println("Thread name is:"+" "+gu.t.getName());
Thread.currentThread().interrupt();
} catch (Exception e) {
}
}
private volatile boolean threadSuspended;
#Override
public void run() {
Thread thisThread = Thread.currentThread();
while ( gu.t == thisThread) {
try {
Thread.sleep(1);
synchronized(this) {
while (threadSuspended && gu.t ==thisThread)
wait();
}
} catch (InterruptedException e){
}
}
int times = 100_000;
for (int i = 0; i <= times; i++) {
checkPauseState();
updateProgress(Math.round((i / (float) times) * 100f));
try {
Thread.sleep(1);
} catch (InterruptedException ex) {
}
}
}
protected void checkPauseState() {
while (paused.get()) {
pauseLock.lock();
try {
pauseCondition.await();
} catch (Exception e) {
} finally {
pauseLock.unlock();
}
}
}
protected void updateProgress(int progress) {
if (EventQueue.isDispatchThread()) {
tvpg.setValue(progress);
} else {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
updateProgress(progress);
}
});
}
}
public boolean isPaused() {
return paused.get();
}
}
}
Unless you're actually checking the intrrupted state of the current thread, then interrupting it will have no effect...
Instead, you could use another AtomicBoolean value which indicates if the thread should continue performing it's work, for example
public class Worker implements Runnable {
//...
private AtomicBoolean keepRunning;
public Worker(JProgressBar tvpg) {
//...
keepRunning = new AtomicBoolean(true);
//...
}
//...
public synchronized void stop() {
keepRunning.set(false);
// Make sure the thread isn't currently
// paused, otherwise it will never exit...
resume();
}
//...
#Override
public void run() {
System.out.println("Runnable has started");
int times = 100_000;
int i = 0;
while (i < times && keepRunning.get()) {
checkPauseState();
updateProgress(Math.round((i / (float) times) * 100f));
try {
Thread.sleep(1);
} catch (InterruptedException ex) {
}
i++;
}
System.out.println("Runnable has exited");
}
We change the loop within the run method to accommodate the new exit condition...
for (int i = 0; i < times && keepRunning.get(); i++) {
checkPauseState();
updateProgress(Math.round((i / (float) times) * 100f));
try {
Thread.sleep(1);
} catch (InterruptedException ex) {
}
}
And the full thing...
public class Worker implements Runnable {
private ReentrantLock pauseLock;
private Condition pauseCondition;
private AtomicBoolean paused;
private AtomicBoolean keepRunning;
private JProgressBar tvpg;
public Worker(JProgressBar tvpg) {
paused = new AtomicBoolean();
keepRunning = new AtomicBoolean(true);
pauseLock = new ReentrantLock();
pauseCondition = pauseLock.newCondition();
this.tvpg = tvpg;
}
public void pause() {
paused.set(true);
}
public void resume() {
paused.set(false);
pauseLock.lock();
try {
pauseCondition.signal();
} finally {
pauseLock.unlock();
}
}
public synchronized void stop() {
keepRunning.set(false);
resume();
}
#Override
public void run() {
System.out.println("Runnable has started");
int times = 100_000;
int i = 0;
while (i < times && keepRunning.get()) {
checkPauseState();
updateProgress(Math.round((i / (float) times) * 100f));
try {
Thread.sleep(1);
} catch (InterruptedException ex) {
}
i++;
}
System.out.println("Runnable has exited");
}
protected void checkPauseState() {
while (paused.get()) {
pauseLock.lock();
try {
pauseCondition.await();
} catch (Exception e) {
} finally {
pauseLock.unlock();
}
}
}
protected void updateProgress(int progress) {
if (EventQueue.isDispatchThread()) {
tvpg.setValue(progress);
} else {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
updateProgress(progress);
}
});
}
}
public boolean isPaused() {
return paused.get();
}
}
Another solution would be to have a state value, which determined the current of the Worker class
public static class Worker implements Runnable {
public enum State {
RUNNING,
PAUSED,
NOT_STARTED,
STOPPPED,
COMPLETED;
}
private volatile State state = State.NOT_STARTED;
This provides you with more information about the current state of the Worker and also information about how it completed (did it complete naturally or was it stopped), for example...
public static class Worker implements Runnable {
public enum State {
RUNNING,
PAUSED,
NOT_STARTED,
STOPPPED,
COMPLETED;
}
private volatile State state = State.NOT_STARTED;
private ReentrantLock pauseLock;
private Condition pauseCondition;
private JProgressBar tvpg;
public Worker(JProgressBar tvpg) {
pauseLock = new ReentrantLock();
pauseCondition = pauseLock.newCondition();
this.tvpg = tvpg;
}
public void pause() {
if (state == State.RUNNING) {
state = State.PAUSED;
}
}
public void resume() {
if (state == State.PAUSED || state == State.STOPPPED) {
if (state == State.PAUSED) {
state = State.RUNNING;
}
pauseLock.lock();
try {
pauseCondition.signal();
} finally {
pauseLock.unlock();
}
}
}
public synchronized void stop() {
state = State.STOPPPED;
resume();
}
#Override
public void run() {
state = State.RUNNING;
System.out.println("Runnable has started");
int times = 100_000;
for (int i = 0; i < times && state != State.STOPPPED; i++) {
checkPauseState();
updateProgress(Math.round((i / (float) times) * 100f));
try {
Thread.sleep(1);
} catch (InterruptedException ex) {
}
}
if (state != State.STOPPPED) {
state = State.COMPLETED;
}
System.out.println("Runnable has exited");
}
protected void checkPauseState() {
while (state == State.PAUSED) {
pauseLock.lock();
try {
pauseCondition.await();
} catch (Exception e) {
} finally {
pauseLock.unlock();
}
}
}
protected void updateProgress(int progress) {
if (EventQueue.isDispatchThread()) {
tvpg.setValue(progress);
} else {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
updateProgress(progress);
}
});
}
}
public boolean isPaused() {
return state == State.PAUSED;
}
public boolean isRunning() {
return state == State.RUNNING;
}
public boolean wasStopped() {
return state == State.STOPPPED;
}
public boolean didComplete() {
return state == State.COMPLETED;
}
}
This does away with the AtomicBoolean variables in favour of the state variable...as another idea
Related
The buttons originally do appear in my original code (which I have not refactored):
package oose.vcs;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.Timer;
import javax.swing.UIManager;
import vehicle.types.Airplane;
import vehicle.types.Bicycle;
import vehicle.types.Boat;
import vehicle.types.Bus;
import vehicle.types.Car;
import vehicle.types.Helicopter;
import vehicle.types.Motorcycle;
import vehicle.types.Ship;
import vehicle.types.Train;
import vehicle.types.Tram;
import vehicle.types.Truck;
import vehicle.types.Vehicle;
public class Controller {
private Vehicle vehicle;
private String[] vehicles = { "Boat", "Ship", "Truck", "Motorcycle", "Bus", "Car", "Bicycle", "Helicopter", "Airplane", "Tram", "Train"};
private Simulator simulationPane;
private JLabel speedlabel;
private JButton button1;
private JButton button2;
private JButton button3;
private JButton button4;
private JButton button5;
private JComboBox<String> combobox;
private JFrame frame;
private boolean accelerate, decelerate, cruise,stop;
int currentvelocity = 1;
int maximumvelocity = 300;
public static void main(String args[]) {
new Controller();
}
public Controller() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName() );
} catch (Exception e) {
e.printStackTrace();
}
frame = new JFrame("Vehicle Control System");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
combobox = new JComboBox<String>(vehicles);
combobox.setSelectedIndex(6);
combobox.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
int selectedIndex = combobox.getSelectedIndex();
String vehicleName = vehicles[selectedIndex];
initialiseVehicle(vehicleName);
}
});
speedlabel = new JLabel(" ");
configStart();
configAccelerate();
configDecelerate();
configCruise();
configStop();
JToolBar toolBar =new JToolBar();
toolBar.setRollover(true);
toolBar.add(combobox);
toolBar.add(speedlabel);
toolBar.add(button1);
toolBar.add(button2);
toolBar.add(button3);
toolBar.add(button4);
toolBar.add(button5);
frame.add(toolBar,BorderLayout.NORTH);
frame.setPreferredSize(new Dimension(800,200));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
private void configStart() {
button1 = new JButton("start");
button1.setBackground(Color.lightGray);
button1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(vehicle == null) {
int selectedIndex = combobox.getSelectedIndex();
String vehicleName = vehicles[selectedIndex];
initialiseVehicle(vehicleName);
speedlabel.setText(vehicle.printSpeed());
}
if(simulationPane !=null) {
frame.remove(simulationPane);
}
accelerate = false;
decelerate = false;
cruise = false;
stop = false;
button1.setBackground(Color.GREEN);
button2.setBackground(Color.lightGray);
button3.setBackground(Color.lightGray);
button4.setBackground(Color.lightGray);
button5.setBackground(Color.lightGray);
simulationPane = new Simulator();
frame.add(simulationPane,BorderLayout.CENTER);
frame.revalidate();
frame.repaint();
}
});
}
private void configAccelerate() {
button2 = new JButton("accelerate");
button2.setBackground(Color.lightGray);
button2.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
accelerate = true;
decelerate = false;
cruise = false;
stop = false;
button1.setBackground(Color.lightGray);
button2.setBackground(Color.green);
button3.setBackground(Color.lightGray);
button4.setBackground(Color.lightGray);
button5.setBackground(Color.lightGray);
Thread thread = new Thread(){
public void run(){
try {
while(accelerate) {
Thread.sleep(2 * 1000);
if(currentvelocity<=maximumvelocity) {
currentvelocity = currentvelocity +1;
vehicle.setCurrentSpeed(currentvelocity);
speedlabel.setText(vehicle.printSpeed());
simulationPane.updateTimer();
}
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
}
});
}
private void configCruise() {
button3 = new JButton("cruise");
button3.setBackground(Color.lightGray);
button3.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
accelerate = false;
decelerate = false;
cruise = true;
stop = false;
button1.setBackground(Color.lightGray);
button2.setBackground(Color.lightGray);
button3.setBackground(Color.green);
button4.setBackground(Color.lightGray);
button5.setBackground(Color.lightGray);
}
});
}
private void configDecelerate() {
button4 = new JButton("decelerate");
button4.setBackground(Color.lightGray);
button4.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
accelerate = false;
decelerate = true;
cruise = false;
stop = false;
button1.setBackground(Color.lightGray);
button2.setBackground(Color.lightGray);
button3.setBackground(Color.lightGray);
button4.setBackground(Color.green);
button5.setBackground(Color.lightGray);
Thread thread = new Thread(){
public void run(){
try {
while(decelerate) {
Thread.sleep(2 * 1000);
if(currentvelocity >1) {
currentvelocity = currentvelocity -1;
vehicle.setCurrentSpeed(currentvelocity);
speedlabel.setText(vehicle.printSpeed());
simulationPane.updateTimer();
}
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
}
});
}
private void configStop() {
button5 = new JButton("stop");
button5.setBackground(Color.lightGray);
button5.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
accelerate = false;
decelerate = false;
cruise = false;
stop = true;
button1.setBackground(Color.lightGray);
button2.setBackground(Color.lightGray);
button3.setBackground(Color.lightGray);
button4.setBackground(Color.lightGray);
button5.setBackground(Color.green);
currentvelocity = 1;
vehicle.setCurrentSpeed(currentvelocity);
speedlabel.setText(vehicle.printSpeed());
simulationPane.updateTimer();
}
});
}
private void initialiseVehicle(String vehicleName) {
if(vehicleName.equals("Boat")) {
vehicle = new Boat("Apollo ");
}
else if(vehicleName.equals("Ship")) {
vehicle = new Ship("Cruizz");
}
else if(vehicleName.equals("Truck")) {
vehicle = new Truck("Ford F-650");
}
else if(vehicleName.equals("Motorcycle")) {
vehicle = new Motorcycle("Suzuki");
}
else if(vehicleName.equals("Bus")) {
vehicle = new Bus("Aero");
}
else if(vehicleName.equals("Car")) {
vehicle = new Car("BMW");
}
else if(vehicleName.equals("Bicycle")) {
vehicle = new Bicycle("A-bike");
}
else if(vehicleName.equals("Helicopter")) {
vehicle = new Helicopter("Eurocopter");
}
else if(vehicleName.equals("Airplane")) {
vehicle = new Airplane("BA");
}
else if(vehicleName.equals("Tram")) {
vehicle = new Tram("EdinburghTram");
}
else if(vehicleName.equals("Train")) {
vehicle = new Train("Virgin",4);
}
}
public class Simulator extends JPanel {
private BufferedImage boat;
private int xPos = 0;
private int direction = 1;
private File file;
private Timer timer;
public Simulator() {
setDisplayObject();
try {
boat = ImageIO.read(file);
timer = new Timer(maximumvelocity/currentvelocity, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
xPos += direction;
if (xPos + boat.getWidth() > getWidth()) {
xPos = 0;
direction *= -1;
} else if (xPos < 0) {
xPos = 0;
direction *= -1;
}
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void updateTimer() {
timer.setDelay(maximumvelocity/currentvelocity);
}
private void setDisplayObject() {
if(vehicle instanceof Boat) {
file = new File(System.getProperty("user.dir")+"/img/boat.png");
}
else if(vehicle instanceof Ship) {
file = new File(System.getProperty("user.dir")+"/img/ship.png");
}
else if(vehicle instanceof Truck) {
file = new File(System.getProperty("user.dir")+"/img/truck.png");
}
else if(vehicle instanceof Motorcycle) {
file = new File(System.getProperty("user.dir")+"/img/motorcycle.png");
}
else if(vehicle instanceof Bus) {
file = new File(System.getProperty("user.dir")+"/img/bus.png");
}
else if(vehicle instanceof Car) {
file = new File(System.getProperty("user.dir")+"/img/car.png");
}
else if(vehicle instanceof Bicycle) {
file = new File(System.getProperty("user.dir")+"/img/bicycle.png");
}
else if(vehicle instanceof Helicopter) {
file = new File(System.getProperty("user.dir")+"/img/helicopter.png");
}
else if(vehicle instanceof Airplane) {
file = new File(System.getProperty("user.dir")+"/img/airplane.png");
}
else if(vehicle instanceof Tram) {
file = new File(System.getProperty("user.dir")+"/img/tram.png");
}
else if(vehicle instanceof Train) {
file = new File(System.getProperty("user.dir")+"/img/train.png");
}
}
#Override
public Dimension getPreferredSize() {
return boat == null ? super.getPreferredSize() : new Dimension(boat.getWidth() * 4, boat.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int y = getHeight() - boat.getHeight();
g.drawImage(boat, xPos, y, this);
}
}
}
However, after refactoring the buttons, they no longer appear on the simulator:
package oose.vcs;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.Timer;
import javax.swing.UIManager;
import vehicle.types.Airplane;
import vehicle.types.Bicycle;
import vehicle.types.Boat;
import vehicle.types.Bus;
import vehicle.types.Car;
import vehicle.types.Helicopter;
import vehicle.types.Motorcycle;
import vehicle.types.Ship;
import vehicle.types.Train;
import vehicle.types.Tram;
import vehicle.types.Truck;
import vehicle.types.Vehicle;
import java.util.HashMap;
import java.util.Map;
public class Controller {
enum ButtonState {
Start,
Accelerate,
Cruise,
Decelerate,
Stop;
}
static Vehicle vehicle;
static String[] vehicles = { "Boat", "Ship", "Truck", "Motorcycle", "Bus", "Car", "Bicycle", "Helicopter", "Airplane", "Tram", "Train"};
private Simulator simulationPane;
private JLabel speedlabel;
private JComboBox<String> combobox;
private JFrame frame;
private JButton[] buttons;
private ButtonState state;
private boolean accelerate, decelerate;
static int currentvelocity = 1;
static int maximumvelocity = 300;
static String vehicleName;
static int selectedIndex;
public static void main(String args[]) {
new Controller();
}
public Controller() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName() );
} catch (Exception e) {
e.printStackTrace();
}
frame = new JFrame("Vehicle Control System");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
combobox = new JComboBox<String>(vehicles);
combobox.setSelectedIndex(6);
combobox.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
int selectedIndex = combobox.getSelectedIndex();
vehicleName = vehicles[selectedIndex];
initialiseVehicle(vehicleName);
}
});
speedlabel = new JLabel(" ");
configButtons();
JToolBar toolBar =new JToolBar();
toolBar.setRollover(true);
toolBar.add(combobox);
toolBar.add(speedlabel);
frame.add(toolBar,BorderLayout.NORTH);
frame.setPreferredSize(new Dimension(800,200));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
private void setState(ButtonState state) {
this.buttons[this.state.ordinal()].setBackground(Color.lightGray);
this.buttons[state.ordinal()].setBackground(Color.green);
this.state = state;
}
private void configButtons() {
this.buttons = new JButton[ButtonState.values().length];
for (ButtonState state : ButtonState.values()) {
JButton button = new JButton(state.name().toLowerCase());
button.setBackground(Color.lightGray);
switch(state) {
case Start:
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
start(e);
}
});
break;
case Accelerate:
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
accelerate(e);
}
});
break;
case Cruise:
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
cruise(e);
}
});
break;
case Decelerate:
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
decelerate(e);
}
});
break;
case Stop:
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
stop(e);
}
});
break;
}
this.buttons[state.ordinal()] = button;
}
}
private void start(ActionEvent e) {
if(vehicle == null) {
selectedIndex = combobox.getSelectedIndex();
String vehicleName = vehicles[selectedIndex];
initialiseVehicle(vehicleName);
speedlabel.setText(vehicle.printSpeed());
}
if(simulationPane !=null) {
frame.remove(simulationPane);
}
this.setState(ButtonState.Start);
simulationPane = new Simulator();
frame.add(simulationPane,BorderLayout.CENTER);
frame.revalidate();
frame.repaint();
}
private void accelerate(ActionEvent e) {
this.setState(ButtonState.Accelerate);
Thread thread = new Thread(){
public void run(){
try {
while(accelerate) {
Thread.sleep(2 * 1000);
if(currentvelocity<=maximumvelocity) {
currentvelocity = currentvelocity +1;
vehicle.setCurrentSpeed(currentvelocity);
speedlabel.setText(vehicle.printSpeed());
simulationPane.updateTimer();
}
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
}
private void cruise(ActionEvent e) {
this.setState(ButtonState.Cruise);
}
private void decelerate(ActionEvent e) {
this.setState(ButtonState.Decelerate);
Thread thread = new Thread(){
public void run(){
try {
while(decelerate) {
Thread.sleep(2 * 1000);
if(currentvelocity >1) {
currentvelocity = currentvelocity -1;
vehicle.setCurrentSpeed(currentvelocity);
speedlabel.setText(vehicle.printSpeed());
simulationPane.updateTimer();
}
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
}
private void stop(ActionEvent e) {
this.setState(ButtonState.Stop);
currentvelocity = 1;
vehicle.setCurrentSpeed(currentvelocity);
speedlabel.setText(vehicle.printSpeed());
simulationPane.updateTimer();
}
public void initialiseVehicle(String vehicleName){
// Create a hashmap with key value pairs
Map<String,Vehicle> objectMap = new HashMap<String, Vehicle>();
// Add all the items into this map
objectMap.put("Airplane",new Airplane("BA"));
objectMap.put("Tram",new Tram("EdinburghTram"));
objectMap.put("Train",new Train("Virgin",4));
objectMap.put("Helicopter",new Helicopter("Eurocopter"));
objectMap.put("Bicycle",new Bicycle("A-bike"));
objectMap.put("Car",new Car("BMW"));
objectMap.put("Bus",new Bus("Aero"));
objectMap.put("Motorcycle",new Motorcycle("Suzuki"));
objectMap.put("Truck",new Truck("Ford F-650"));
objectMap.put("Ship",new Ship("Cruizz"));
objectMap.put("Boat", new Boat("Apollo"));
// checks if the item exist in the map
if(objectMap.containsKey(vehicleName)){
vehicle = objectMap.get(vehicleName);
}
}
private class Simulator extends JPanel {
private static final long serialVersionUID = 8809852587026347126L;
private BufferedImage boat;
private int xPos = 0;
private int direction = 1;
protected File file;
private Timer timer;
public Simulator() {
setDisplayObject();
try {
boat = ImageIO.read(file);
timer = new Timer(Controller.maximumvelocity/Controller.currentvelocity, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
xPos += direction;
if (xPos + boat.getWidth() > getWidth()) {
xPos = 0;
direction *= -1;
} else if (xPos < 0) {
xPos = 0;
direction *= -1;
}
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void updateTimer() {
timer.setDelay(Controller.maximumvelocity/Controller.currentvelocity);
}
private void setDisplayObject() {
if(vehicle instanceof Boat) {
file = new File(System.getProperty("user.dir")+"/img/boat.png");
}
else if(vehicle instanceof Ship) {
file = new File(System.getProperty("user.dir")+"/img/ship.png");
}
else if(vehicle instanceof Truck) {
file = new File(System.getProperty("user.dir")+"/img/truck.png");
}
else if(vehicle instanceof Motorcycle) {
file = new File(System.getProperty("user.dir")+"/img/motorcycle.png");
}
else if(vehicle instanceof Bus) {
file = new File(System.getProperty("user.dir")+"/img/bus.png");
}
else if(vehicle instanceof Car) {
file = new File(System.getProperty("user.dir")+"/img/car.png");
}
else if(vehicle instanceof Bicycle) {
file = new File(System.getProperty("user.dir")+"/img/bicycle.png");
}
else if(vehicle instanceof Helicopter) {
file = new File(System.getProperty("user.dir")+"/img/helicopter.png");
}
else if(vehicle instanceof Airplane) {
file = new File(System.getProperty("user.dir")+"/img/airplane.png");
}
else if(vehicle instanceof Tram) {
file = new File(System.getProperty("user.dir")+"/img/tram.png");
}
else if(vehicle instanceof Train) {
file = new File(System.getProperty("user.dir")+"/img/train.png");
}
}
#Override
public Dimension getPreferredSize() {
return boat == null ? super.getPreferredSize() : new Dimension(boat.getWidth() * 4, boat.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int y = getHeight() - boat.getHeight();
g.drawImage(boat, xPos, y, this);
}
}
}
May I ask what could have gone wrong and how I could modify my refactored code?
Here are example of what the vehicle classes look like (essentially getters and setters):
package vehicle.types;
public abstract class Aircraft extends Vehicle{
private double steering;
public Aircraft(String name) {
setName(name);
setType(Type.SKIED);
}
#Override
public void streer(double degree, double speed) {
setCurrentSpeed(speed);
setSteering(degree);
}
#Override
public String printSpeed() {
return getCurrentSpeed()+"km/hr";
}
public double getSteering() {
return steering;
}
public void setSteering(double degrees) {
this.steering = degrees;
}
}
package vehicle.types;
public class Airplane extends Aircraft {
public Airplane(String name) {
super(name);
}
}
In the original code you were adding the buttons to the toolbar
toolBar.add(button1);
toolBar.add(button2);
toolBar.add(button3);
...
But in the refactored code you don't do that anymore. I guess you could add them in configButtons() while you are looping through them.
I have a minimal app to show Java Swing GUI update problem, seems it's not painting the components properly, the errors look like this :
Here is my program :
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import java.util.concurrent.*;
public class Java_Test extends JPanel
{
static JFrame frame=new JFrame("Java Test");
static int W=800,H=260,Executor_Count=12;
JPanel Progress_Panel=new JPanel(),Center_Panel;
JButton Do_Test_Button=new JButton("Do Test");
Get_Time Timer=new Get_Time();
ThreadPoolExecutor executor;
Progress_Bar Progress_bar;
Timer Display_Timer=new Timer(1);
public Java_Test()
{
setLayout(new BorderLayout());
JPanel Top_Panel=new JPanel();
Top_Panel.setPreferredSize(new Dimension(W-6,60));
add("North",Top_Panel);
Do_Test_Button.setFont(new Font("Times New Roman",0,16));
Do_Test_Button.setBackground(new Color(118,198,250));
Do_Test_Button.setForeground(new Color(0,28,218));
Do_Test_Button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { Do_Test(); } });
Top_Panel.add(Do_Test_Button);
JPanel Center_Panel=new JPanel();
Center_Panel.setPreferredSize(new Dimension(W-2,170));
add("Center",Center_Panel);
Progress_Panel.setPreferredSize(new Dimension(W-2,160));
Center_Panel.add(Progress_Panel);
JLabel Progress_Label=new JLabel("Progress");
Progress_Label.setFont(new Font("Times New Roman",0,20));
Progress_Label.setBackground(new Color(253,253,253));
Progress_Label.setForeground(new Color(8,68,128));
Progress_Label.setPreferredSize(new Dimension(W-20,53));
Progress_Label.setHorizontalAlignment(SwingConstants.CENTER);
Progress_Panel.add(Progress_Label);
Progress_bar=new Progress_Bar(620,26);
Progress_Panel.add(Progress_bar);
JPanel Time_Used_Panel=new JPanel(new FlowLayout(FlowLayout.CENTER,6,26));
Time_Used_Panel.setPreferredSize(new Dimension(W-20,60));
Progress_Panel.add(Time_Used_Panel);
JLabel Time_Used_Label=new JLabel("Time : ");
Time_Used_Label.setFont(new Font("Times New Roman",0,14));
Time_Used_Label.setForeground(new Color(0,0,238));
Time_Used_Label.setHorizontalAlignment(SwingConstants.CENTER);
Time_Used_Panel.add(Time_Used_Label);
Display_Timer.setFont(new Font("Times New Roman",0,14));
Display_Timer.setForeground(new Color(0,0,238));
Display_Timer.setPreferredSize(new Dimension(50,17));
Time_Used_Panel.add(Display_Timer);
Clock clock=new Clock(0);
clock.setFont(new Font("Monospaced",Font.PLAIN,16));
clock.setBackground(new Color(0,110,220));
clock.setForeground(new Color(250,250,250));
clock.setOpaque(true);
clock.setPreferredSize(new Dimension(288,30));
clock.start();
JPanel Bottom_Panel=new JPanel();
Bottom_Panel.setPreferredSize(new Dimension(W-2,50));
Bottom_Panel.add(clock);
add("South",Bottom_Panel);
setPreferredSize(new Dimension(W,H));
}
void Do_Test()
{
String Info="",Result;
Out("Do_Test");
try
{
Display_Timer.start();
Timer.Start();
Output_Time("[ 1 ]");
Progress_bar.Set_Progress(1);
int Task_Count=222;
executor=new ThreadPoolExecutor(Executor_Count,Executor_Count*2,1,TimeUnit.SECONDS,new LinkedBlockingQueue());
ArrayList<Future<String>> futures=new ArrayList<>(Task_Count);
Test_Runner A_Runner;
try
{
for (int i=0;i<Task_Count;i++)
{
A_Runner=new Test_Runner();
futures.add(executor.submit(A_Runner));
}
executor.shutdown();
while (!executor.isTerminated()) { executor.awaitTermination(100,TimeUnit.MILLISECONDS); }
for (Future<String> future : futures)
{
Result=future.get();
if (Result!=null) Info+=Result;
}
}
catch (Exception e) { e.printStackTrace(); }
}
catch (Exception e) { e.printStackTrace(); }
Output_Time("[ 2 ]");
Progress_bar.Set_Progress(100);
Out("Done");
Display_Timer.stop();
}
String Output_Time(String Id)
{
Timer.End();
String Time_Duration=Id+" : Time = "+Timer.Get_Duration_Hour_Minute_Second();
Out(Time_Duration);
return Time_Duration;
}
private static void Out(String message) { System.out.println(message); }
static void Create_And_Show_GUI()
{
final Java_Test demo=new Java_Test();
frame.add(demo);
frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } });
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { Create_And_Show_GUI(); } }); }
}
class Progress_Bar extends JPanel implements Runnable
{
int W,H,Last_Progress=-99,Progress,counter=0,Unit_Size=20;
static JProgressBar b=new JProgressBar();
boolean Started_B=false,Do_Step_B=false;
Thread Progress_Bar_Runner_Thread;
public Progress_Bar(int W,int H)
{
setPreferredSize(new Dimension(W,H));
b.setPreferredSize(new Dimension(W-20,H-8));
b.setStringPainted(true);
add(b);
start();
}
public void Set_Progress(int Progress)
{
if (Progress==1 || (this.Progress<Progress && Progress<=100))
{
this.Progress=Progress;
b.setValue(Progress);
b.paintImmediately(0,0,b.getWidth(),b.getHeight());
Out(" Progress = "+Progress+" %");
}
if (Progress==1) Started_B=true;
else if (Progress>=100)
{
Started_B=false;
Do_Step_B=false;
}
}
public void run()
{
try
{
while (Progress<=100)
{
if ((Progress==0 || Progress==50 || Progress==100 || Do_Step_B) && Last_Progress!=Progress)
{
b.setValue(Progress);
// revalidate();
b.paintImmediately(0,0,b.getWidth(),b.getHeight());
Last_Progress=Progress;
}
Thread.sleep(200); // Delay the thread
Do_Step_B=(Started_B && (counter++ % Unit_Size ==0));
if (Progress<100 && Do_Step_B) Progress++;
}
}
catch (Exception e) { e.printStackTrace(); }
}
public void start()
{
if (Progress_Bar_Runner_Thread==null)
{
Progress_Bar_Runner_Thread=new Thread(this);
Progress_Bar_Runner_Thread.setPriority(Thread.NORM_PRIORITY);
Progress_Bar_Runner_Thread.start();
}
}
public void stop() { if (Progress_Bar_Runner_Thread!=null) Progress_Bar_Runner_Thread=null; }
private static void Out(String message) { System.out.println(message); }
}
class Test_Runner implements Callable<String>
{
int Start_Index=0,End_Index=6999;
StringBuilder StrBdr=new StringBuilder();
public Test_Runner() { }
public String call() throws InterruptedException
{
try { for (int i=Start_Index;i<End_Index;i++) StrBdr.append("Test_Runner + Test_Runner + Test_Runner + Test_Runner + Test_Runner + Test_Runner"); }
catch (Exception e) {}
return StrBdr.toString();
}
}
class Timer extends JLabel implements Runnable
{
public static final long serialVersionUID=26362862L;
private Thread Timer_Thread;
String Time_Text="";
int updateInterval=1000,Format=0;
Get_Time Timer=new Get_Time();
public Timer()
{
setFont(new Font("Monospaced",Font.PLAIN,16));
setVerticalAlignment(SwingConstants.CENTER);
setHorizontalAlignment(SwingConstants.CENTER);
}
public Timer(int Format) { this.Format=Format; }
public void start()
{
Timer.Start();
if (Timer_Thread==null)
{
Timer_Thread=new Thread(this);
Timer_Thread.setPriority(Thread.NORM_PRIORITY);
Timer_Thread.start();
}
}
public void run()
{
Thread myThread=Thread.currentThread();
while (Timer_Thread==myThread)
{
switch (Format)
{
case 1 : Time_Text=Timer.Get_Duration_Hour_Minute_Second();break;
}
setText(Time_Text);
paintImmediately(0,0,getWidth(),getHeight());
revalidate();
try { Thread.sleep(updateInterval); }
catch (InterruptedException e) { }
}
}
public void stop() { if (Timer_Thread != null) Timer_Thread=null; }
}
class Clock extends JLabel implements Runnable
{
public static final long serialVersionUID=26362862L;
private Thread clockThread;
String Time_Text="";
int updateInterval=1000,Format=0;
Get_Time Timer=new Get_Time();
public Clock() { start(); }
public Clock(int Format)
{
this.Format=Format;
start();
}
public void start()
{
setVerticalAlignment(SwingConstants.CENTER);
setHorizontalAlignment(SwingConstants.CENTER);
if (clockThread==null)
{
clockThread=new Thread(this);
// clockThread.setPriority(Thread.NORM_PRIORITY);
clockThread.setPriority(Thread.MIN_PRIORITY);
clockThread.start();
}
}
public void run()
{
Thread myThread=Thread.currentThread();
while (clockThread==myThread)
{
switch (Format)
{
case 0 : Time_Text=" "+new java.util.Date().toString().substring(0,19)+" ";break;
}
setText(Time_Text);
paintImmediately(0,0,getWidth(),getHeight());
revalidate();
try { Thread.sleep(updateInterval); }
catch (InterruptedException e) { }
}
}
public void stop() { if (clockThread != null) clockThread=null; }
}
class Get_Time
{
private long start,end;
public int Hours,Minutes,Seconds,Total_Seconds;
String ST_Hours,ST_Minutes,ST_Seconds;
public Get_Time() { Reset(); }
public void Start() { start=System.currentTimeMillis(); }
public void End()
{
int half_second;
end=System.currentTimeMillis();
Total_Seconds=(int)(end-start)/1000;
half_second=(int)(end-start)%1000;
if (half_second>499) Total_Seconds++;
Hours=Total_Seconds/3600;
Minutes=(Total_Seconds%3600)/60;
Seconds=(Total_Seconds%3600)%60;
ST_Hours=new String((Hours>9)?""+Hours:"0"+Hours);
ST_Minutes=new String((Minutes>9)?""+Minutes:"0"+Minutes);
ST_Seconds=new String((Seconds>9)?""+Seconds:"0"+Seconds);
}
public String Get_Duration_Hour_Minute_Second()
{
End();
return ST_Hours+":"+ST_Minutes+":"+ST_Seconds;
}
public void Reset() { start=0;end=0; }
}
My computer has a 12 core 3.33 GH Intel Corei7 x 980 CPU, with 24 GB of RAM, running on Windows 7, Java Version = 1.8.0_212
The question is how to fix it ?
Enumeration of Swing threading and painting problems:
All of the following code is called from the Swing event dispatch thread (EDT), and so far so good....
void Do_Test() {
String Info = "", Result;
Out("Do_Test");
try {
Display_Timer.start();
Timer.Start();
Output_Time("[ 1 ]");
Progress_bar.Set_Progress(1); // OK to call this on the event thread
int Task_Count = 222;
executor = new ThreadPoolExecutor(Executor_Count, Executor_Count * 2, 1,
TimeUnit.SECONDS, new LinkedBlockingQueue());
ArrayList<Future<String>> futures = new ArrayList<>(Task_Count);
Test_Runner A_Runner;
try {
for (int i = 0; i < Task_Count; i++) {
A_Runner = new Test_Runner();
futures.add(executor.submit(A_Runner));
}
executor.shutdown();
OK, here we start seeing problems as you're calling a potentially long while loop on the EDT, potentially blocking it:
while (!executor.isTerminated()) {
executor.awaitTermination(100, TimeUnit.MILLISECONDS);
}
Same here, as the call to Future#get() is a blocking call:
for (Future<String> future : futures) {
Result = future.get();
if (Result != null)
Info += Result;
}
OK, now we start seeing some truly unusual Swing code where you make Swing calls, including setting a JProgressBar's value off the EDT and then try to force the EDT to do some painting via paintImmediately(....). Making calls off the EDT can result in intermittent and unpredictable errors, and can cause the painting to mess up, and the GUI to sometimes freeze:
class Progress_Bar extends JPanel implements Runnable {
// .....
public void Set_Progress(int Progress) {
if (Progress == 1 || (this.Progress < Progress && Progress <= 100)) {
this.Progress = Progress; // ****** being called off the EDT
b.paintImmediately(0, 0, b.getWidth(), b.getHeight()); // ***** Don't do this
Out(" Progress = " + Progress + " %");
}
// .....
}
public void run() {
try {
while (Progress <= 100) {
if ((Progress == 0 || Progress == 50 || Progress == 100 || Do_Step_B)
&& Last_Progress != Progress) {
// ***** called off the EDT -- don't do this
b.setValue(Progress);
// revalidate();
b.paintImmediately(0, 0, b.getWidth(), b.getHeight()); // **** and don't do this
Last_Progress = Progress;
}
Thread.sleep(200); // Delay the thread
Do_Step_B = (Started_B && (counter++ % Unit_Size == 0));
if (Progress < 100 && Do_Step_B)
Progress++;
}
} catch (Exception e) {
e.printStackTrace();
}
}
// .......
}
Similar strange goings-ons in this class, the Timer class, where you set a JLabel's text off of the EDT:
class Timer extends JLabel implements Runnable {
// ....
public void run() {
Thread myThread = Thread.currentThread();
while (Timer_Thread == myThread) {
switch (Format) {
case 1:
Time_Text = Timer.Get_Duration_Hour_Minute_Second();
break;
}
// again this is dangerous code **********
setText(Time_Text);
paintImmediately(0, 0, getWidth(), getHeight());
// ....
Same for the Clock class...
Solutions:
To repeatedly call code in a Swing GUI, use a javax.swing.Timer or "Swing Timer". For an example of use of this, please see my implementation of your MCVE, but using a Swing Timer for your threading code above.
The other code, the one that calls long-running tasks, should be done within a SwingWorker. This worker thread usually communicates with the Swing GUI in one of two ways (or both) -- either using a publish/process method pair, or (as in the example below), using a PropertyChangeListener attached to the Worker. Workers have several "bound" properties, fields that notify listeners of change, including the progress property, that can hold a value from 0 to 100, and the SwingWorker.StateValue, or "state" property:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.swing.*;
#SuppressWarnings("serial")
public class JavaTest2 extends JPanel {
private static final int W = 800;
private static final int H = 260;
private Action doTestAction = new DoTestAction("Do Test");
private JProgressBar progressBar = new JProgressBar(0, 100);
private MyClockPanel clockPanel = new MyClockPanel();
private MyTimerPanel timerPanel = new MyTimerPanel();
public JavaTest2() {
JPanel topPanel = new JPanel();
topPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 35, 5));
topPanel.add(new JButton(doTestAction));
progressBar.setStringPainted(true);
JPanel progressPanel = new JPanel(new GridBagLayout());
progressPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1.0;
progressPanel.add(progressBar, gbc);
JLabel progressLabel = new JLabel("Progress", SwingConstants.CENTER);
progressLabel.setFont(new Font("Times New Roman", 0, 20));
progressLabel.setForeground(new Color(8, 68, 128));
JPanel centralPanel = new JPanel(new BorderLayout(5, 5));
centralPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
centralPanel.add(progressLabel, BorderLayout.PAGE_START);
centralPanel.add(progressPanel);
JPanel clockWrapper = new JPanel();
clockWrapper.add(clockPanel);
JPanel bottomPanel = new JPanel();
bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.PAGE_AXIS));
bottomPanel.add(timerPanel, BorderLayout.PAGE_START);
bottomPanel.add(clockWrapper, BorderLayout.PAGE_END);
setLayout(new BorderLayout());
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
add(topPanel, BorderLayout.PAGE_START);
add(bottomPanel, BorderLayout.PAGE_END);
add(centralPanel);
}
#Override
public Dimension getPreferredSize() {
Dimension superSize = super.getPreferredSize();
if (isPreferredSizeSet()) {
return superSize;
} else {
int w = Math.max(superSize.width, W);
int h = Math.max(superSize.height, H);
return new Dimension(w, h);
}
}
private class DoTestAction extends AbstractAction {
private MyWorker myWorker = null;
public DoTestAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
if (myWorker != null && myWorker.getState() == SwingWorker.StateValue.STARTED) {
return; // still running
}
timerPanel.start();
progressBar.setValue(0);
myWorker = new MyWorker();
myWorker.addPropertyChangeListener(new WorkerListener());
myWorker.execute();
setEnabled(false);
}
}
class WorkerListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
// if the worker is changing its progress bound property:
if (evt.getPropertyName().equals("progress")) {
int progress = (int) evt.getNewValue();
// just for safety's sake, limit progress to 100 and no more
progress = Math.min(progress, 100);
progressBar.setValue(progress);
} else if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
// else if worker is done
try {
// get the result to at least trap errors
String result = ((MyWorker) evt.getSource()).get();
// can display result in the GUI
timerPanel.stop();
} catch (Exception e) {
// worker's exception is available to the GUI if desired here
e.printStackTrace();
}
progressBar.setValue(100);
doTestAction.setEnabled(true);
}
}
}
private static class MyWorker extends SwingWorker<String, Void> {
private static final int EXECUTOR_COUNT = 12;
private static final int TASK_COUNT = 222;
#Override
protected String doInBackground() throws Exception {
ExecutorService executor = new ThreadPoolExecutor(EXECUTOR_COUNT, EXECUTOR_COUNT * 2, 1,
TimeUnit.SECONDS, new LinkedBlockingQueue<>());
List<Future<String>> futures = new ArrayList<>();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < TASK_COUNT; i++) {
Callable<String> aRunner = new ARunner();
futures.add(executor.submit(aRunner));
}
executor.shutdown();
int index = 0;
for (Future<String> future : futures) {
String result = future.get();
sb.append(result);
sb.append(" ");
index++;
int progress = (100 * index) / TASK_COUNT;
progress = Math.min(progress, 100);
setProgress(progress);
}
return sb.toString();
}
}
private static class ARunner implements Callable<String> {
private static final long SLEEP_TIME = 800;
#Override
public String call() throws Exception {
TimeUnit.MILLISECONDS.sleep(SLEEP_TIME);
return "Foo";
}
}
private static void createAndShowGui() {
JavaTest2 mainPanel = new JavaTest2();
JFrame frame = new JFrame("Java Test 2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
#SuppressWarnings("serial")
class MyClockPanel extends JPanel {
private static final Color FG = new Color(250, 250, 250);
private static final Color BG = new Color(0, 110, 220);
private static final int TIMER_DELAY = 200;
private static final Font FONT = new Font("Monospaced", Font.PLAIN, 16);
private JLabel clockLabel = new JLabel("", SwingConstants.CENTER);
private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("E MMM dd yyyy kk:mm:ss");
public MyClockPanel() {
setBackground(BG);
clockLabel.setForeground(FG);
clockLabel.setFont(FONT);
displayDateTime();
setLayout(new BorderLayout());
setBorder(BorderFactory.createEmptyBorder(5, 50, 5, 50));
add(clockLabel);
new javax.swing.Timer(TIMER_DELAY, e -> {
displayDateTime();
}).start();
}
private void displayDateTime() {
LocalDateTime dateTime = LocalDateTime.now();
String text = dateTime.format(formatter);
clockLabel.setText(text);
}
}
#SuppressWarnings("serial")
class MyTimerPanel extends JPanel {
private static final Color FG = new Color(0, 0, 238);
private static final Font FONT = new Font("Times New Roman", 0, 14);
private static final int TIMER_DELAY = 40;
private static final String FORMAT_TXT = "Elapsed Time: %02d:%02d:%02d";
private JLabel timerLabel = new JLabel("", SwingConstants.CENTER);
private LocalDateTime startTime = null;
private Timer timer = null;
public MyTimerPanel() {
timerLabel.setForeground(FG);
timerLabel.setFont(FONT);
setLayout(new BorderLayout());
setBorder(BorderFactory.createEmptyBorder(5, 50, 5, 50));
timerLabel.setText(String.format(FORMAT_TXT, 0, 0, 0));
add(timerLabel);
}
public void start() {
stop();
startTime = LocalDateTime.now();
timer = new Timer(TIMER_DELAY, e -> incrementTime());
timer.start();
}
public void stop() {
if (timer != null && timer.isRunning()) {
timer.stop();
}
}
private void incrementTime() {
LocalDateTime currentTime = LocalDateTime.now();
long hours = ChronoUnit.HOURS.between(startTime, currentTime);
long minutes = ChronoUnit.MINUTES.between(startTime, currentTime) % 60;
long seconds = ChronoUnit.SECONDS.between(startTime, currentTime) % 60;
String text = String.format(FORMAT_TXT, hours, minutes, seconds);
timerLabel.setText(text);
}
}
public class frame11 extends javax.swing.JFrame implements ActionListener,
PropertyChangeListener {
public String[] columnNames = { "Path",
"File Name",
"Size"};
public Object[][] data ;
int isJPEG (String s) throws IOException
{ int c=0;//not jpeg
if ( (s.endsWith(".JPG")) || (s.endsWith(".JPEG"))||(s.endsWith(".jpeg"))||(s.endsWith(".jpg")))
{
c=1;//is jpeg
}
return c;
}
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
JFileChooser fch = new JFileChooser("C:\\");
jProgressBar1.setValue(0);
jProgressBar1.setStringPainted(true);
jTextField1.setText(null);
jTextField2.setText(null);
jTextField4.setText(null);
jLabel7.setText(null);
data = new Object[15][3];
jTable2.setModel(new DefaultTableModel(data, columnNames));
fch.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int ret = fch.showOpenDialog(null);
int apr=0;
if (ret==JFileChooser.APPROVE_OPTION)
{ apr=1;
jTextField1.setText(fch.getSelectedFile().toString());
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
}
else jTextField1.setText("Nothing clicked!!!");
if (apr==1) {
jLabel7.setText("Wait Please, While searching ...");
task = new Task();
task.addPropertyChangeListener(this);
task.execute();
EventQueue.invokeLater(new Runnable() { // Added
#Override
public void run() {
File f = fch.getSelectedFile();
String s= f.getAbsolutePath();
int cnt;
int st=0;
Path myfile = Paths.get(s);
if(f.isDirectory()&& Files.isReadable(myfile)){
try {
st=st+CheckFiles(f);
cnt=count(f);
String ss=Integer.toString(cnt);
jTextField2.setText(ss);
jTextField4.setText(Integer.toString(st));
} catch (IOException ex) {
Logger.getLogger(frame1.class.getName()).log(Level.SEVERE, null, ex);
}
}
jLabel7.setText("Scanning Finished. Thanks for waiting ");
}
});
}
}//GEN-LAST:event_jButton1ActionPerformed
private Task task;
#Override
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
int progress = (Integer) evt.getNewValue();
jProgressBar1.setValue(progress);
System.out.println("Property changed");
}
}
//#Override
public void actionPerformed(ActionEvent e) {
}
class Task extends SwingWorker<Void, Void> {
#Override
public Void doInBackground() {
Random random = new Random();
int progress = 0;
setProgress(0);
while (progress < 100) {
try {
Thread.sleep(random.nextInt(100));
} catch (InterruptedException ignore) {}
progress += random.nextInt(10);
setProgress(Math.min(progress, 100));
}
return null;
}
/*
* Executed in event dispatching thread
*/
#Override
public void done() {
Toolkit.getDefaultToolkit().beep();
setCursor(null);
}
}
I would like your help, I'm trying to scan my pc for JPEG images to count them. I have two problems, the first is that I'm using a jtable, but the results is never added until the program ends, and the progress bar isn't synchronized sometimes it ends before the program and sometimes after. please help me resolve these two problems and thank you.
You're using a SwingWorker in order to create a background thread -- good -- but you're making Swing calls directly from that background thread -- bad:
jProgressBar1.setValue(n);
Instead call setProgress(...) from within your SwingWorker, and add a PropertyChangeListener to the worker that listens for changes to the worker's "progress" bound property.
For examples:
How do I make my SwingWorker example work properly?
Cant get JProgressBar to update from SwingWorker class
JProgressBar Tutorial
For an example of an mcve that shows an example of use of a JProgressBar with a SwingWorker:
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
#SuppressWarnings("serial")
public class TestProgress2 extends JPanel {
private JProgressBar progressBar = new JProgressBar(0, 100);
private Action startBackgroundTaskAction = new StartBackgroundTaskAction();
public TestProgress2() {
progressBar.setStringPainted(true);
add(progressBar);
add(new JButton(startBackgroundTaskAction));
}
public void setActionEnabled(boolean enabled) {
startBackgroundTaskAction.setEnabled(enabled);
}
private class StartBackgroundTaskAction extends AbstractAction {
public StartBackgroundTaskAction() {
super("Start Background Task");
putValue(MNEMONIC_KEY, KeyEvent.VK_S);
}
#Override
public void actionPerformed(ActionEvent e) {
progressBar.setString(null);
progressBar.setValue(0);
setActionEnabled(false);
MyTask myTask = new MyTask();
myTask.addPropertyChangeListener(new MyTaskListener());
myTask.execute();
}
}
private class MyTaskListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
MyTask myTask = (MyTask) pcEvt.getSource();
if ("progress".equals(pcEvt.getPropertyName())) {
int progress = myTask.getProgress();
progressBar.setValue(progress);
}
if (pcEvt.getNewValue() == SwingWorker.StateValue.DONE) {
setActionEnabled(true);
progressBar.setString("Done");
try {
myTask.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
private class MyTask extends SwingWorker<Void, Void> {
#Override
protected Void doInBackground() throws Exception {
Random random = new Random();
int progress = 0;
setProgress(0);
while (progress < 100) {
try {
Thread.sleep(random.nextInt(1000));
} catch (InterruptedException ignore) {}
progress += random.nextInt(10);
setProgress(Math.min(progress, 100));
}
return null;
}
}
private static void createAndShowGui() {
TestProgress2 mainPanel = new TestProgress2();
JFrame frame = new JFrame("TestProgress2");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Okay, this is my first question here so go easy on me guys. I'm trying to generate sound on the fly using the noteOn in the MidiChannel class with the internal Java Synthesizer. It produces sound perfectly. My problem is outputing that sound to my sequencer so I can save it to a midi file. At the moment, my program creates the file but its empty. The disconnect occurs with my transmitter/receiver setup. When I try to get the synth's transmitter, it produces the lovely MidiUnavailbleException.
I have a crapload of code in here so I'll just give you the highlights. The complete class will be at the very bottom.
public Piano()
{
try
{
//previous code not shown//
sequence = new Sequence(Sequence.PPQ, 4); //I know. Just let it be.
sequence.createTrack();
sequencer = MidiSystem.getSequencer();
sequencer.open();
sequencer.setSequence(sequence);
sequencer.recordEnable(sequencer.getSequence().getTracks()[0], 1);
receiver = sequencer.getReceiver();
transmitter = synth.getTransmitter();
transmitter.setReceiver(receiver);
}
catch (Exception e)
{
e.printStackTrace();
}
}
When it hits the transmitter = synth.getTransmitter();, I get the MidiUnavailableException. Any ideas on how to get the MidiEvents from my synth to the sequencer?
//Complete Class - Warning: May Cause Headaches and/or Hysteria
package main;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import java.lang.reflect.Method;
import java.net.URL;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.List;
import javax.imageio.ImageIO;
import javax.sound.midi.*;
import javax.sound.midi.MidiDevice.Info;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.TargetDataLine;
import javax.swing.*;
import org.jfugue.DeviceThatWillReceiveMidi;
import org.jfugue.DeviceThatWillTransmitMidi;
public class Piano implements ActionListener
![enter image description here][2]{
KeyEventDispatcher dispatcher = new KeyEventDispatcher()
{
public boolean dispatchKeyEvent(KeyEvent e)
{
if(e.getID()==401)
{
if(e.getKeyCode()==KeyEvent.VK_SPACE)
{
sustain();
}
if(e.getKeyCode()==KeyEvent.VK_PERIOD)
{
octaveUp();
}
if(e.getKeyCode()==KeyEvent.VK_COMMA)
{
octaveDown();
}
if(e.getKeyCode()==KeyEvent.VK_A)
{
start(freq);
}
if(e.getKeyCode()==KeyEvent.VK_W)
{
start(freq+1);
}
if(e.getKeyCode()==KeyEvent.VK_S)
{
start(freq+2);
}
if(e.getKeyCode()==KeyEvent.VK_E)
{
start(freq+3);
}
if(e.getKeyCode()==KeyEvent.VK_D)
{
start(freq+4);
}
if(e.getKeyCode()==KeyEvent.VK_F)
{
start(freq+5);
}
if(e.getKeyCode()==KeyEvent.VK_T)
{
start(freq+6);
}
if(e.getKeyCode()==KeyEvent.VK_G)
{
start(freq+7);
}
if(e.getKeyCode()==KeyEvent.VK_Y)
{
start(freq+8);
}
if(e.getKeyCode()==KeyEvent.VK_H)
{
start(freq+9);
}
if(e.getKeyCode()==KeyEvent.VK_U)
{
start(freq+10);
}
if(e.getKeyCode()==KeyEvent.VK_J)
{
start(freq+11);
}
if(e.getKeyCode()==KeyEvent.VK_K)
{
start(freq+12);
}
if(e.getKeyCode()==KeyEvent.VK_O)
{
start(freq+13);
}
if(e.getKeyCode()==KeyEvent.VK_L)
{
start(freq+14);
}
if(e.getKeyCode()==KeyEvent.VK_P)
{
start(freq+15);
}
if(e.getKeyCode()==KeyEvent.VK_SEMICOLON)
{
start(freq+16);
}
}
if(e.getID()==402)
{
if(!sustain)
{
if(e.getKeyCode()==KeyEvent.VK_A)
{
end(freq);
}
if(e.getKeyCode()==KeyEvent.VK_W)
{
end(freq+1);
}
if(e.getKeyCode()==KeyEvent.VK_S)
{
end(freq+2);
}
if(e.getKeyCode()==KeyEvent.VK_E)
{
end(freq+3);
}
if(e.getKeyCode()==KeyEvent.VK_D)
{
end(freq+4);
}
if(e.getKeyCode()==KeyEvent.VK_F)
{
end(freq+5);
}
if(e.getKeyCode()==KeyEvent.VK_T)
{
end(freq+6);
}
if(e.getKeyCode()==KeyEvent.VK_G)
{
end(freq+7);
}
if(e.getKeyCode()==KeyEvent.VK_Y)
{
end(freq+8);
}
if(e.getKeyCode()==KeyEvent.VK_H)
{
end(freq+9);
}
if(e.getKeyCode()==KeyEvent.VK_U)
{
end(freq+10);
}
if(e.getKeyCode()==KeyEvent.VK_J)
{
end(freq+11);
}
if(e.getKeyCode()==KeyEvent.VK_K)
{
end(freq+12);
}
if(e.getKeyCode()==KeyEvent.VK_O)
{
end(freq+13);
}
if(e.getKeyCode()==KeyEvent.VK_L)
{
end(freq+14);
}
if(e.getKeyCode()==KeyEvent.VK_P)
{
end(freq+15);
}
if(e.getKeyCode()==KeyEvent.VK_SEMICOLON)
{
end(freq+16);
}
}
else
{
if(e.getKeyCode()==KeyEvent.VK_A)
{
endSoft(freq);
}
if(e.getKeyCode()==KeyEvent.VK_W)
{
endSoft(freq+1);
}
if(e.getKeyCode()==KeyEvent.VK_S)
{
endSoft(freq+2);
}
if(e.getKeyCode()==KeyEvent.VK_E)
{
endSoft(freq+3);
}
if(e.getKeyCode()==KeyEvent.VK_D)
{
endSoft(freq+4);
}
if(e.getKeyCode()==KeyEvent.VK_F)
{
endSoft(freq+5);
}
if(e.getKeyCode()==KeyEvent.VK_T)
{
endSoft(freq+6);
}
if(e.getKeyCode()==KeyEvent.VK_G)
{
endSoft(freq+7);
}
if(e.getKeyCode()==KeyEvent.VK_Y)
{
endSoft(freq+8);
}
if(e.getKeyCode()==KeyEvent.VK_H)
{
endSoft(freq+9);
}
if(e.getKeyCode()==KeyEvent.VK_U)
{
endSoft(freq+10);
}
if(e.getKeyCode()==KeyEvent.VK_J)
{
endSoft(freq+11);
}
if(e.getKeyCode()==KeyEvent.VK_K)
{
endSoft(freq+12);
}
if(e.getKeyCode()==KeyEvent.VK_O)
{
endSoft(freq+13);
}
if(e.getKeyCode()==KeyEvent.VK_L)
{
endSoft(freq+14);
}
if(e.getKeyCode()==KeyEvent.VK_P)
{
endSoft(freq+15);
}
if(e.getKeyCode()==KeyEvent.VK_SEMICOLON)
{
endSoft(freq+16);
}
}
}
return false;
}
};
final int VOLUME_MAX = 120;
int freq = 60;
int volume = VOLUME_MAX;
int instr;
int delay = 1000;
int velocity = 1000;
int count = 0;
boolean sustain = false;
boolean recording = false;
DecimalFormat df;
List<Icon> icons;
AnimatedIcon aIcon;
Synthesizer synth;
Sequence sequence;
Sequencer sequencer;
MidiChannel[] mc;
Instrument[] instruments;
Instrument instrument;
Transmitter transmitter;
Receiver receiver;
File file;
JFrame mainFrame;
JPanel mainPanel;
ImagePanel iPanel;
JButton rec;
JButton stop;
JButton load;
JButton sustainB;
JButton octave;
JButton up;
JButton down;
JButton volumeB;
JButton vUp;
JButton vDown;
OctavePanel oPanel;
VolumePanel vPanel;
GridBagLayout gridBag;
GridBagConstraints c;
Image redCir;
Image greenCir;
Image recCir;
public Piano()
{
DefaultKeyboardFocusManager.getCurrentKeyboardFocusManager().
addKeyEventDispatcher(dispatcher);
InputMap im = (InputMap)UIManager.get("Button.focusInputMap");
im.put(KeyStroke.getKeyStroke("pressed SPACE"), "none");
im.put(KeyStroke.getKeyStroke("released SPACE"), "none");
try
{
synth = MidiSystem.getSynthesizer();
synth.open();
FileInputStream stream = new FileInputStream(this.getClass().getResource("resources/soundbank1.gm").toString().substring(6));
Soundbank sBank = MidiSystem.getSoundbank(stream);
instruments = sBank.getInstruments();
synth.loadAllInstruments(sBank);
mc = synth.getChannels();
instrument = (Instrument)JOptionPane.showInputDialog(null, "Choose an instrument", "", JOptionPane.PLAIN_MESSAGE, null, instruments, instruments[0]);
mc[0].programChange(instrument.getPatch().getProgram());
greenCir = ImageIO.read(getClass().getResource("resources/greenCir.gif"));
redCir = ImageIO.read(getClass().getResource("resources/redCir.gif"));
recCir = ImageIO.read(getClass().getResource("resources/rec.gif"));
sequence = new Sequence(Sequence.PPQ, 4);
sequence.createTrack();
sequencer = MidiSystem.getSequencer();
sequencer.open();
sequencer.setSequence(sequence);
sequencer.recordEnable(sequencer.getSequence().getTracks()[0], 1);
df = new DecimalFormat("000");
receiver = sequencer.getReceiver();
transmitter = synth.getTransmitter();
transmitter.setReceiver(receiver);
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void sustain()
{
sustain = !sustain;
if(sustain)
{
sustainB.setIcon(new ImageIcon(greenCir));
}
else
{
sustainB.setIcon(new ImageIcon(redCir));
}
}
public void octaveUp()
{
freq += 12;
octave.setText("Octave: " + (freq-60)/12);
}
public void octaveDown()
{
freq -= 12;
octave.setText("Octave: " + (freq-60)/12);
}
public void vUp()
{
if(volume < 120)
volume += 12;
volumeB.setText(setVText(volume));
}
public void vDown()
{
if(volume > 0)
volume -= 12;
volumeB.setText(setVText(volume));
}
public void resetVolume()
{
volume = VOLUME_MAX;
volumeB.setText(setVText(volume));
}
public String setVText(int v)
{
return "Volume " + volume/12 * 10 + "%";
}
public void selectInstrument()
{
instrument = (Instrument)JOptionPane.showInputDialog(null, "Choose an instrument", "", JOptionPane.PLAIN_MESSAGE, null, instruments, instruments[0]);
mc[0].programChange(instrument.getPatch().getProgram());
}
public BufferedImage getPiano()
{
URL url = this.getClass().getResource("piano.gif");
try
{
BufferedImage buffImage = ImageIO.read(url);
return buffImage;
}
catch (IOException e)
{
System.out.println("Error");
return null;
}
}
public void start(int note)
{
mc[0].noteOn(note, volume);
}
public void end(int note)
{
mc[0].noteOff(note);
}
public void endSoft(int note)
{
//mc[0].noteOff(note, velocity);
}
public void createAndShowGUI()
{
mainFrame = new JFrame("Piano Maestro");
mainFrame.setDefaultCloseOperation(0);
mainFrame.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e) {System.exit(0);}
});
setupFrame(mainFrame.getContentPane());
mainFrame.pack();
mainFrame.setMinimumSize(new Dimension(500, 300));
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
mainFrame.setMinimumSize(new Dimension(iPanel.getWidth()+20, mainFrame.getHeight()));
mainFrame.setResizable(false);
}
public void setupFrame(Container pane)
{
gridBag = new GridBagLayout();
pane.setLayout(gridBag);
c = new GridBagConstraints();
sustainB = new JButton("Sustain");
sustainB.addActionListener(this);
sustainB.setActionCommand("sustain");
up = new JButton();
up.addActionListener(this);
up.setActionCommand("up");
down = new JButton();
down.addActionListener(this);
down.setActionCommand("down");
octave = new JButton("Octave: 0");
octave.addActionListener(this);
octave.setActionCommand("resetOctave");
stop = new JButton("Stop");
stop.addActionListener(this);
stop.setActionCommand("stop");
rec = new JButton("rec");
rec.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){rec();}});
load = new JButton("Load Instr.");
load.addActionListener(this);
load.setActionCommand("load");
volumeB = new JButton(setVText(volume));
volumeB.addActionListener(this);
volumeB.setActionCommand("resetVolume");
vUp = new JButton();
vUp.addActionListener(this);
vUp.setActionCommand("vUp");
vDown = new JButton();
vDown.addActionListener(this);
vDown.setActionCommand("vDown");
c.gridx = 0;
c.gridy = 0;
c.weightx = 1;
c.ipady = 10;
vPanel = new VolumePanel(vDown,volumeB,vUp);
pane.add(vPanel,c);
c.gridy = 1;
oPanel = new OctavePanel(down,octave,up);
pane.add(oPanel,c);
c.gridx = 1;
c.gridy = 0;
pane.add(sustainB,c);
c.gridx = 2;
pane.add(rec,c);
c.gridx = 1;
c.gridy = 1;
pane.add(load,c);
c.gridx = 2;
pane.add(stop,c);
c.gridy = 2;
c.gridx = 0;
c.gridwidth = 3;
try
{
sustainB.setIcon(new ImageIcon(ImageIO.read(getClass().getResource("resources/redCir.gif"))));
up.setIcon(new ImageIcon(ImageIO.read(getClass().getResource("resources/up.gif"))));
vUp.setIcon(new ImageIcon(ImageIO.read(getClass().getResource("resources/up.gif"))));
down.setIcon(new ImageIcon(ImageIO.read(getClass().getResource("resources/down.gif"))));
vDown.setIcon(new ImageIcon(ImageIO.read(getClass().getResource("resources/down.gif"))));
stop.setIcon(new ImageIcon(ImageIO.read(getClass().getResource("resources/square.gif"))));
rec.setIcon(new ImageIcon(ImageIO.read(getClass().getResource("resources/rec.gif"))));
iPanel = new ImagePanel("resources/piano.gif");
pane.add(iPanel,c);
}
catch (Exception e)
{
e.printStackTrace();
}
aIcon = new AnimatedIcon(rec,750,1,new ImageIcon(this.getClass().getResource("resources/recOn.gif")),new ImageIcon(this.getClass().getResource("resources/recOff.gif")));
load.setPreferredSize(sustainB.getPreferredSize());
rec.setPreferredSize(stop.getPreferredSize());
octave.setPreferredSize(volumeB.getPreferredSize());
volumeB.setPreferredSize(volumeB.getPreferredSize());
volumeB.setText(setVText(volume));
}
public void rec()
{
recording = true;
rec.setIcon(aIcon);
aIcon.start();
sequencer.startRecording();
}
public void stop()
{
if(recording)
{
aIcon.stop();
rec.setIcon(new ImageIcon(recCir));
sequencer.stop();
if(sequence!=null)
{
file = new File("Song" + df.format(count) + ".midi");
while(file.exists())
{
count++;
file = new File("Song" + df.format(count) + ".midi");
}
try
{
MidiSystem.write(sequence, 1, file);
}
catch (IOException e)
{
JOptionPane.showMessageDialog(null, "Your system is unable to write files.","Error",2);
}
}
else
{
JOptionPane.showMessageDialog(null, "Your system is unable to write files.","Error",2);
}
}
mc[0].allNotesOff();
}
public void actionPerformed(ActionEvent e)
{
if(e.getActionCommand().equals("sustain"))
{
sustain();
}
if(e.getActionCommand().equals("up"))
{
octaveUp();
}
if(e.getActionCommand().equals("down"))
{
octaveDown();
}
if(e.getActionCommand().equals("resetOctave"))
{
freq = 60;
octave.setText("Octave: " + (freq-60)/12);
}
if(e.getActionCommand().equals("load"))
{
this.selectInstrument();
}
if(e.getActionCommand().equals("piano"))
{
mc[0].programChange(instruments[0].getPatch().getProgram());
}
if(e.getActionCommand().equals("stop"))
{
stop();
}
if(e.getActionCommand().equals("vUp"))
{
vUp();
}
if(e.getActionCommand().equals("vDown"))
{
vDown();
}
if(e.getActionCommand().equals("resetVolume"))
{
resetVolume();
}
}
}
I have two SwingWorker class: FileLineCounterThread and FileDivisionThread
I will execute the two threads. When the lines counting thread finishes, it will pass the result to File Division thread.
I do not have an idea on how to pass the result to started thread.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;
public class ExecutorAndSwingWorker2 {
private JFrame frame = new JFrame();
private JButton button1;
private JButton button2;
private JButton button3;
private JButton button4;
private JPanel buttonPanel = new JPanel();
private Executor executor = Executors.newCachedThreadPool();
private javax.swing.Timer timer1;
private javax.swing.Timer timer2;
private javax.swing.Timer timer3;
private javax.swing.Timer timer4;
private Random random = new Random();
public ExecutorAndSwingWorker2() {
button1 = new JButton(" Executor + SwingWorker Thread No.1 ");
button1.setFocusable(false);
button2 = new JButton(" Executor + SwingWorker Thread No.2 ");
button3 = new JButton(" Executor + SwingWorker Thread No.3 ");
button4 = new JButton(" Executor + SwingWorker Thread No.4 ");
buttonPanel = new JPanel();
buttonPanel.setBorder(new EmptyBorder(15, 15, 15, 15));
buttonPanel.setLayout(new GridLayout(2, 2, 20, 20));
buttonPanel.add(button1);
buttonPanel.add(button2);
buttonPanel.add(button3);
buttonPanel.add(button4);
frame.setTitle("Shaking Button Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(buttonPanel);
frame.setPreferredSize(new Dimension(700, 170));
frame.setLocation(150, 100);
frame.pack();
frame.setVisible(true);
executor.execute(new ExecutorAndSwingWorker2.MyTask("startButton1")); // non on EDT
}
private void startButton1() {
System.out.println("Starting long Thread == startButton1()");
try {
Thread.sleep(15000);
} catch (InterruptedException ex) {
}
}
private void startButton2() {
System.out.println("Starting long Thread == startButton2()");
try {
Thread.sleep(17500);
} catch (InterruptedException ex) {
}
}
private void startButton3() {
System.out.println("Starting long Thread == startButton3()");
try {
Thread.sleep(12500);
} catch (InterruptedException ex) {
}
}
private void startButton4() {
System.out.println("Starting long Thread == startButton4()");
try {
Thread.sleep(20000);
} catch (InterruptedException ex) {
}
}
private void colorAction1() {
timer1 = new Timer(1000, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
random = new Random();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
button1.setBackground(new Color(127 + random.nextInt(128), 127 + random.nextInt(128), 127 + random.nextInt(128)));
button1.validate();
button1.repaint();
}
});
}
});
timer1.setDelay(500);
timer1.setRepeats(true);
timer1.start();
}
private void colorAction2() {
timer2 = new Timer(1200, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
random = new Random();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
button2.setBackground(new Color(127 + random.nextInt(128), 127 + random.nextInt(128), 127 + random.nextInt(128)));
button2.validate();
button2.repaint();
}
});
}
});
timer2.setDelay(500);
timer2.setRepeats(true);
timer2.start();
}
private void colorAction3() {
timer3 = new Timer(1400, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
random = new Random();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
button3.setBackground(new Color(127 + random.nextInt(128), 127 + random.nextInt(128), 127 + random.nextInt(128)));
button3.validate();
button3.repaint();
}
});
}
});
timer3.setDelay(500);
timer3.setRepeats(true);
timer3.start();
}
private void colorAction4() {
timer4 = new Timer(1600, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
random = new Random();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
button4.setBackground(new Color(127 + random.nextInt(128), 127 + random.nextInt(128), 127 + random.nextInt(128)));
button4.validate();
button4.repaint();
}
});
}
});
timer4.setDelay(500);
timer4.setRepeats(true);
timer4.start();
}
private void endButton1() {
timer1.stop();
button1.setBackground(null);
System.out.println("Long Thread Ends == startButton1()");
executor.execute(new ExecutorAndSwingWorker2.MyTask("startButton3")); // non on EDT
}
private void endButton2() {
timer2.stop();
button2.setBackground(null);
System.out.println("Long Thread Ends == startButton2()");
}
private void endButton3() {
timer3.stop();
button3.setBackground(null);
System.out.println("Long Thread Ends == startButton3()");
executor.execute(new ExecutorAndSwingWorker2.MyTask("startButton2")); // non on EDT
executor.execute(new ExecutorAndSwingWorker2.MyTask("startButton4")); // non on EDT
}
private void endButton4() {
timer4.stop();
button4.setBackground(null);
System.out.println("Long Thread Ends == startButton4()");
executor.execute(new ExecutorAndSwingWorker2.MyTask("startButton1")); // non on EDT
}
private class MyTask extends SwingWorker<Void, Integer> {
private String str;
private String namePr;
private JDialog dialog = new JDialog();
MyTask(String str) {
this.str = str;
addPropertyChangeListener(new SwingWorkerCompletionWaiter(dialog, str, namePr));
}
#Override
protected Void doInBackground() throws Exception {
if (str.equals("startButton1")) {
colorAction1();
startButton1();
} else if (str.equals("startButton2")) {
colorAction2();
startButton2();
} else if (str.equals("startButton3")) {
colorAction3();
startButton3();
} else if (str.equals("startButton4")) {
colorAction4();
startButton4();
}
return null;
}
#Override
protected void process(List<Integer> progress) {
System.out.println(str + " " + progress.get(progress.size() - 1));
}
#Override
protected void done() {
if (str.equals("startButton1")) {
endButton1();
} else if (str.equals("startButton2")) {
endButton2();
} else if (str.equals("startButton3")) {
endButton3();
} else if (str.equals("startButton4")) {
endButton4();
}
}
}
private class SwingWorkerCompletionWaiter implements PropertyChangeListener {
private JDialog dialog;
private String str;
private String namePr;
SwingWorkerCompletionWaiter(JDialog dialog, String str, String namePr) {
this.dialog = dialog;
this.str = str;
this.namePr = namePr;
}
#Override
public void propertyChange(PropertyChangeEvent event) {
if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.DONE == event.getNewValue()) {
System.out.println("Thread Status with Name :" + str + ", SwingWorker Status is " + event.getNewValue());
} else if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.PENDING == event.getNewValue()) {
System.out.println("Thread Status with Mame :" + str + ", SwingWorker Status is " + event.getNewValue());
} else if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.STARTED == event.getNewValue()) {
System.out.println("Thread Status with Name :" + str + ", SwingWorker Status is " + event.getNewValue());
} else {
System.out.println("Thread Status with Name :" + str + ", Something wrong happends ");
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ExecutorAndSwingWorker2 executorAndSwingWorker = new ExecutorAndSwingWorker2();
}
});
}
}
SwingWorker.execute() is buggy and will only execute tasks serially. Use ExecutorService.execute() for concurrency:
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RunnableFuture;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.WindowConstants;
public class MyFrame extends JFrame implements ActionListener {
/**
* Test Driver
*/
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
MyFrame frame = new MyFrame("Swing Concurrency Test");
frame.setVisible(true);
}
});
}
/**
* Thread Executor
* (must be explicitly shutdown, see WindowAdapter below)
*/
private final ExecutorService exec = Executors.newFixedThreadPool(2);
/**
* Button action
*/
#Override
public void actionPerformed(ActionEvent e) {
button.setEnabled(false);
textArea.append("\nStarting both tasks...\n");
// start both tasks, pass a reference to outer task
FileLineCounterThread counterTask = new FileLineCounterThread();
exec.execute(counterTask);
FileDivisionThread divisionTask = new FileDivisionThread(counterTask);
exec.execute(divisionTask);
}
/**
* Counter task
*/
private class FileLineCounterThread extends SwingWorker<Long, String> {
private String template = "[FileLineCounterThread] %s\n";
#Override
protected Long doInBackground() throws Exception {
// do some work
publish("started...");
Thread.sleep(10000);
// return the result
return 42L;
}
#Override
protected void process(List<String> chunks) {
for (String chunk : chunks) {
textArea.append(String.format(template, chunk));
}
}
#Override
protected void done() {
try {
textArea.append(String.format(
template, "complete. Counted: " + get()));
}
catch (Exception e) {
// catch any exceptions thrown during execution
e.printStackTrace();
}
}
}
/**
* File Division task
*/
private class FileDivisionThread extends SwingWorker<String, String> {
private RunnableFuture<Long> counterTask;
private String template = " [FileDivisionThread] %s\n";
public FileDivisionThread(RunnableFuture<Long> counterTask) {
this.counterTask = counterTask;
}
#Override
protected String doInBackground() throws Exception {
// do some initial work
publish("started...");
Thread.sleep(2000);
// wait for other task to complete and get result
publish("Waiting for line counter to finish...");
long numLines = counterTask.get();
publish("Line count received: " + numLines);
// do the rest of the work and return result
Thread.sleep(5000);
return "complete.";
}
#Override
protected void process(List<String> chunks) {
for (String chunk : chunks) {
textArea.append(String.format(template, chunk));
}
}
#Override
protected void done() {
try {
textArea.append(String.format(template, get()));
button.setEnabled(true);
}
catch (Exception e) {
// catch any exceptions thrown during execution
e.printStackTrace();
}
}
}
/////////////////////////
//// GUI Boilerplate ////
/////////////////////////
private JScrollPane scroller = new JScrollPane();
private JTextArea textArea = new JTextArea();
private JButton button = new JButton("Start");
public MyFrame(String windowTitle) {
super(windowTitle);
initComponents();
}
private void initComponents() {
addWindowListener(new WindowAdapter() {
#Override
public void windowClosed(WindowEvent e) {
exec.shutdownNow();
System.exit(0);
}
});
button = new JButton("Start");
button.addActionListener(this);
textArea = new JTextArea();
textArea.setColumns(35);
textArea.setRows(15);
scroller.setViewportView(textArea);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
getContentPane().setLayout(new GridBagLayout());
GridBagConstraints gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.insets = new Insets(10, 0, 0, 0);
getContentPane().add(button, gridBagConstraints);
gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.fill = GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new Insets(10, 10, 10, 10);
getContentPane().add(scroller, gridBagConstraints);
pack();
}
}
PipedReader/Writer for character data & PipedInput/OutputStream for binary data
in java.io.
Regards,
Stéphane
never hands up, never surrender its possible with Executor and SwingWorker
1/ bug for Executor and SwingWorker
2/ hold and check number of thread started by Executor and live SwingWorkers threads with intentions to avoid caught above mentioned bug
3/ check maximum numbers for Executor or restict that to final munber
EDIT changed by OP's requirements
import java.beans.*;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import javax.swing.JDialog;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
public class ExecutorAndSwingWorker1 {
private static Executor executor = Executors.newCachedThreadPool();
private static void startButton1() {
System.out.println("Starting long Tread == startButton1()");
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
}
private static void startButton2() {
System.out.println("Starting long Tread == startButton2()");
try {
Thread.sleep(3000);
} catch (InterruptedException ex) {
}
}
private static void startButton3() {
System.out.println("Starting long Tread == startButton3()");
try {
Thread.sleep(1500);
} catch (InterruptedException ex) {
}
}
private static void startButton4() {
System.out.println("Starting long Tread == startButton4()");
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
}
}
private static void endButton1() {
System.out.println("Long Tread Ends == startButton1()");
executor.execute(new ExecutorAndSwingWorker1.MyTask("startButton3")); // non on EDT
}
private static void endButton2() {
System.out.println("Long Tread Ends == startButton2()");
executor.execute(new ExecutorAndSwingWorker1.MyTask("startButton4")); // non on EDT
}
private static void endButton3() {
System.out.println("Long Tread Ends == startButton3()");
}
private static void endButton4() {
System.out.println("Long Tread Ends == startButton3()");
}
private static class MyTask extends SwingWorker<Void, Integer> {
private String str;
private String namePr;
private JDialog dialog = new JDialog();
MyTask(String str) {
this.str = str;
addPropertyChangeListener(new SwingWorkerCompletionWaiter(dialog, str, namePr));
}
#Override
protected Void doInBackground() throws Exception {
if (str.equals("startButton1")) {
startButton1();
} else if (str.equals("startButton2")) {
startButton2();
} else if (str.equals("startButton3")) {
startButton3();
} else if (str.equals("startButton4")) {
startButton4();
}
return null;
}
#Override
protected void process(List<Integer> progress) {
System.out.println(str + " " + progress.get(progress.size() - 1));
}
#Override
protected void done() {
if (str.equals("startButton1")) {
endButton1();
} else if (str.equals("startButton2")) {
endButton2();
} else if (str.equals("startButton3")) {
endButton3();
} else if (str.equals("startButton4")) {
endButton4();
}
}
}
private static class SwingWorkerCompletionWaiter implements PropertyChangeListener {
private JDialog dialog;
private String str;
private String namePr;
SwingWorkerCompletionWaiter(JDialog dialog, String str, String namePr) {
this.dialog = dialog;
this.str = str;
this.namePr = namePr;
}
#Override
public void propertyChange(PropertyChangeEvent event) {
if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.DONE == event.getNewValue()) {
System.out.println("Thread Status with Name :" + str + ", SwingWorker Status is " + event.getNewValue());
} else if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.PENDING == event.getNewValue()) {
System.out.println("Thread Status with Mame :" + str + ", SwingWorker Status is " + event.getNewValue());
} else if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.STARTED == event.getNewValue()) {
System.out.println("Thread Status with Name :" + str + ", SwingWorker Status is " + event.getNewValue());
} else {
System.out.println("Thread Status with Name :" + str + ", Something wrong happends ");
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
executor.execute(new ExecutorAndSwingWorker1.MyTask("startButton1")); // non on EDT
executor.execute(new ExecutorAndSwingWorker1.MyTask("startButton2")); // non on EDT
}
});
}
private ExecutorAndSwingWorker1() {
}
}
I am not sure this is a solution you should use, and it undermines the simplicity and safety you get from using SwingWorker, but I'll mention it for completeness.
Put two fields where both threads can see them: one boolean, called hasValue, initialized to false, and one int (or long) called countValue. Both must be declared as volatile. When the counter thread is done, put the count in countValue. Then set hasValue to true. The division thread can then check `hasValue' periodically and grab the count when it is available.
If the division is providing values that will be more accurate once it gets the count, this will do. More likely, it is doing some work, then waiting for the count. In this case, set up a third field called countMonitor, defined as final Object. When it finishes the initial work, have it check hasValue. If it's true, grab the value and continue. If it's false, call the wait method on countMonitor and continue when notified. The counter thread, when done, should always call the notifyAll method on countMonitor after putting values in hasValue and countValue.
I've left out a bit here. The javadoc for Object will tell you about needed synchronization and checked exceptions. Your design is straightforward enough that you won't be troubled with the usual supernatural horror stories multi-threading generates. I hope. But you might want to do a bit of research if you go this route. (If you repeat the whole process in the same session, you will definitely want to do a lot of research.)