I created a little indication of loading using a custom subclass of LayerUI.
The list is and arraylist of StringWorker subclass. Its get method is a blocking call so I assume that's the problem just don't know how to fix it. The layer starts a timer and as far as I know, timers are executed in their own thread so the blocking get shouldn't intefere.
loadingLayer.setVisible(true);
lockComponents();
for(int i = 0; i < list.size(); i++) {
try {
System.out.println("About to check "+i);
if(list.get(i).get() == null) {
}
} catch (InterruptedException e1) {
e1.printStackTrace();
} catch (ExecutionException e1) {
e1.printStackTrace();
}
}
unlockComponents();
loadingLayer.setVisible(false);
The "loadingLayer" appears only after all this code is done.
LoadingLayerUI class:
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComponent;
import javax.swing.Timer;
import javax.swing.plaf.LayerUI;
public class LoadingLayerUI extends LayerUI<JComponent> implements ActionListener {
/**
*
*/
private static final long serialVersionUID = 827885062549399916L;
private boolean isShowing;
private Timer timer;
private String text;
#Override
public void paint(Graphics g, JComponent jc) {
super.paint(g, jc);
if(!isShowing)
return;
Graphics2D g2 = (Graphics2D) g.create();
int w = jc.getWidth();
int h = jc.getHeight();
g2.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, .7f));
g2.setPaint(Color.LIGHT_GRAY);
g2.fillRect(0, 0, w, h);
g2.setColor(Color.BLACK);
Font font = new Font("Sans-Serif",Font.BOLD, 20);
int width = g2.getFontMetrics(font).stringWidth("Loading");
g2.setFont(font);
if(text != null)
g2.drawString(text, (w-width)/2, h/2);
g2.dispose();
jc.repaint();
}
public void setVisible(boolean set) {
this.isShowing = set;
if(isShowing) {
timer = new Timer(200, this);
timer.start();
}
else {
timer.stop();
}
}
#Override
public void actionPerformed(ActionEvent e) {
if(!isShowing && timer.isRunning())
timer.stop();
if(text == null || text.equals("Downloading...")) {
text = "Downloading";
}
else
text += ".";
}
}
When you use Swing you should make your long running tasks in a separate thread.
Here is the tutorial: http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html
I moved the code which uses the blocking method get to a separate thread and made it call a method when it was done. Now it seems to work. The layer appears and disappears when needed.
loadingLayer.setVisible(true);
new Thread(new Runnable() {
public void run() {
for(int i = 0; i < list.size(); i++) {
try {
if(list.get(i).get() == null) {
}
} catch (InterruptedException e1) {
e1.printStackTrace();
} catch (ExecutionException e1) {
e1.printStackTrace();
}
}
downloadComplete();
}
}).start();
The downloadComplete method simply hides the layer.
Related
I'm using SwingWorker and
It perfectly updates JProgressBar WHEN the process is not too heavy (for example "Trames" list containing 62 elements)
It doesn't update JProgressBar when the process is heavy (I tested with 100k elements, it'll finally works with 2M+ elems)
Below my ProgressWorker class
#Override
protected Object doInBackground() throws Exception {
// TODO Auto-generated method stub
// here process i skipped
for (Trame t : trames) {
float progress = (float)FileRW.tramescounter/FileRW.maxtrames;
progress = progress*100;
int p = (int) progress;
setProgress(p);
System.out.println(getProgress()+"+p"+" ---- progress"+p+" ---- double"+progress);
Thread.sleep(25);
FileRW.tramescounter++;
// here process i skipped
}
// here process i skipped
return null;
}
Besides, my controller class:
ProgressWorker pw = new ProgressWorker();
pw.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
String name = evt.getPropertyName();
if (name.equals("progress")) {
int progress = (int) evt.getNewValue();
Vue.bar.setValue(progress);
Vue.bar.repaint();
} else if (name.equals("state")) {
SwingWorker.StateValue state = (SwingWorker.StateValue) evt.getNewValue();
switch (state) {
case DONE:
Vue.lastButton.setEnabled(true);
if (Vue.check.isSelected()) {
if (Desktop.isDesktopSupported()) {
Desktop desktop = Desktop.getDesktop();
try {
desktop.open(new File(Constants.FICHIER_LOG2));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Vue.filesInDirectory = null;
Vue.fileLabel.setText(Constants.PAN1_LABEL);
break;
default:
break;
}
}
}
});
pw.execute();
There's a runnable example (based on your out-of-context code) which works, so my guess is, it's not the SwingWorker which is at fault, but some part of the code you're not sharing.
Consider providing a Minimal, Complete, and Verifiable example which demonstrates your problem, until you do, this is about all the help we can possible give you
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import static javax.swing.SwingWorker.StateValue.DONE;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JProgressBar pb = new JProgressBar(0, 100);
public TestPane() {
setLayout(new GridBagLayout());
add(pb);
BadWorker pw = new BadWorker();
pw.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
String name = evt.getPropertyName();
if (name.equals("progress")) {
int progress = (int) evt.getNewValue();
pb.setValue(progress);
} else if (name.equals("state")) {
SwingWorker.StateValue state = (SwingWorker.StateValue) evt.getNewValue();
switch (state) {
case DONE:
System.out.println("All done where");
break;
}
}
}
});
pw.execute();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.dispose();
}
}
public class BadWorker extends SwingWorker<Object, Object> {
#Override
protected Object doInBackground() throws Exception {
int count = 0;
int max = 10000;
do {
count++;
float progress = (float) count / max;
progress = progress * 100;
int p = (int) progress;
setProgress(p);
System.out.println(getProgress() + "+p" + " ---- progress" + p + " ---- double" + progress);
Thread.sleep(5);
// here process i skipped
} while (getProgress() < 100);
// here process i skipped
return null;
}
}
}
Ok nevermind the problem wasn't the one I expected
Just inside the first part of code I skipped I wrote
Vue.bar.setMaximum(trames.size());
Further,
float progress = (float)FileRW.tramescounter/FileRW.maxtrames;
progress = progress*100;
int p = (int) progress;
setProgress(p);
And in controller class
Vue.bar.setValue(progress);
But progress value set in ProgressWorker is from 0 to 100
My max ProgressBar value was 100K but the 0 < progression value <100,
It was normal that it didn't progress
I am doing animation with Java and I'm using NetBeans. My applet has started but I don't see anything in the applet viewer? Can anybody see any problem with my code and this is my first programming course as U can see =)! Thanks for advance!!
Problem.1 Do animation with 10 gif pictures by using MediaTracker,addImage and thread.sleep.
(Code)
import java.applet.Applet;
import java.awt.*;
public class Animaatio extends Applet implements Runnable
{
Image images[] = null;
MediaTracker tracker = null;
Thread animaatio;
Graphics g;
#Override
public void init()
{
tracker = new MediaTracker(this);
images = new Image[10];
for (int i=0; i < 10; i++)
{
images[i] = getImage( getCodeBase(),"T" + (i+1) + ".gif");
tracker.addImage(images[i],0);
}
try{
tracker.waitForAll();
}catch (InterruptedException e){}
}
#Override
public void start() {
if (animaatio == null) {
animaatio = new Thread(this);
animaatio.start();
}
}
#Override
public void paint (Graphics g)
{
super.paint(g);
g.drawImage(images[10], 0, 0, this);
}
#Override
public void run(){
while(true){
repaint();
try{
Thread.sleep(1000);
}
catch (InterruptedException e) {}
}
}
}
We are using foxtrot package for stop freeze the swing application.
But in this below code it make a deadlock.
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import foxtrot.Task;
import foxtrot.Worker;
public class FoxtrotExample extends JFrame {
public static void main(String[] args) {
FoxtrotExample example = new FoxtrotExample();
example.setVisible(true);
}
boolean st = true;
public FoxtrotExample() {
super("Foxtrot Example");
final JButton button = new JButton("Take a nap !");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Start..");
button.setText("Sleeping...");
String text = null;
try {
text = (String) Worker.post(new Task() {
public Object run() throws Exception {
System.out.println("Inside Worker 1");
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
System.out.println("Inside invokeLater");
Worker.post(new Task() {
#Override
public Object run()
throws Exception {
System.out.println("Inside Worker 2");
st = false;
return null;
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
});
while (st) {
System.out.println("Inside the loop..");
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
return "Slept !";
}
});
} catch (Exception x) {
}
button.setText(text);
System.out.println("Finished.....");
}
});
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
Container c = getContentPane();
c.setLayout(new GridBagLayout());
c.add(button);
setSize(300, 200);
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
Dimension size = getSize();
int x = (screen.width - size.width) >> 1;
int y = (screen.height - size.height) >> 1;
setLocation(x, y);
}
}
If use ConcurrentWorker this will work fine.Can any one explane this.
I am bit confuse how EDT behave here ?
This is the result of my program.
Start 1st worker
In the loop
Start invoke later
In the loop
In the loop
In the loop
In the loop
......
It start the 1st worker.Then part of the code is in invokeLater.So request is enqued in the event queue and start the loop.Later execute the invokeLater but not execute the 2nd worker because first worker still doing some work.Since worker are ruining one after another and it runs on a single worker queue 2nd worker cannot execute and deadlock comes.
Thanks to MadProgrammer i understood this.Hope this is correct.
I made a simple ( I thought) demo that plays music in the background while an animated 128x128 candle Sprite flickers in the background and text is displayed and refreshed every 2 seconds with a TimerTask. This demo works fine in the emulator (MicroEmulator), but failed on all counts but the music on both my LG500G and Motorola EM326G phones. Because they both failed in the same way, I suspect I may be doing something wrong. Neither of the phones will even display any text whatsoever using g.drawString(). Either my phones are severely limited, or I am writing something horribly weirdly:(note I have commented out the code about the Sprite because only one frame displayed)
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.*;
import javax.microedition.media.*;
public class GardenGameCanvas extends GameCanvas implements Runnable {
private Image bgImage;
private Sprite bgSprite;
private boolean stop;
private LayerManager manager;
private int a = 0;
private String[] list;
textTask aTextTask;
Player midiplayer = null;
public GardenGameCanvas() {
super(false);
}
public void start() {
list = new String[] { "As you watch this candle", "It flickers.",
"Against the gale of Life", "It's flickering.", "Persistently" };
try {
midiplayer = Manager.createPlayer(
getClass().getResourceAsStream("/pavane_defunte_mb.mid"),
"audio/midi");
midiplayer.prefetch();
midiplayer.start();
} catch (Exception e) {
}
//try {
//bgImage = Image.createImage("/flame.png");
//bgSprite = new Sprite(bgImage, 128, 128);
//manager = new LayerManager();
//manager.append(bgSprite);
//} catch (IOException ioex) {
// System.err.println(ioex);
//}
stop = false;
Thread runner = new Thread(this);
runner.start();
}
public void run() {
aTextTask = new textTask();
new Timer().schedule(aTextTask, 0, 2000);
while (!stop) {
update(getGraphics());
try {
Thread.currentThread().sleep(30);
} catch (Exception e) {
}
}
}
private void update(Graphics g) {
g.setColor(0xFFFFFF); // white
g.fillRect(0, 0, getWidth(), getHeight());
// bgSprite.setPosition(0, 0);
//bgSprite.nextFrame();
//bgSprite.paint(g);
buildGame(g);
//manager.paint(g, 0, 0);
flushGraphics();
}
private void buildGame(Graphics g) {
g.setColor(0xFFFFFF);
g.fillRect(0, getHeight() / 2, getWidth(), 75);
g.setColor(0x000000);
g.drawString(list[a], 0, getHeight()/2, Graphics.LEFT);
flushGraphics();
}
public class textTask extends TimerTask {
public textTask() {
}
public void run() {
a++;
if (a > 4) {
a = 0;
}
}
}
}
I suspect the error is caused by your multiple calls to flushGraphics()
Your first call to flushGraphics will flush the graphics and display it (except it doesn't get a chance to display anything because of your second call to flushGraphics).
Your second call to flushGraphics right after will flush nothing to the screen, resulting in nothing being displayed.
Try this instead:
(Same code as above, simply with one of the calls to flushGraphics commented out).
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.*;
import javax.microedition.media.*;
public class GardenGameCanvas extends GameCanvas implements Runnable {
private Image bgImage;
private Sprite bgSprite;
private boolean stop;
private LayerManager manager;
private int a = 0;
private String[] list;
textTask aTextTask;
Player midiplayer = null;
public GardenGameCanvas() {
super(false);
}
public void start() {
list = new String[]{"As you watch this candle", "It flickers.",
"Against the gale of Life", "It's flickering.", "Persistently"};
try {
midiplayer = Manager.createPlayer(
getClass().getResourceAsStream("/pavane_defunte_mb.mid"),
"audio/midi");
midiplayer.prefetch();
midiplayer.start();
} catch (Exception e) {
}
//try {
//bgImage = Image.createImage("/flame.png");
//bgSprite = new Sprite(bgImage, 128, 128);
//manager = new LayerManager();
//manager.append(bgSprite);
//} catch (IOException ioex) {
// System.err.println(ioex);
//}
stop = false;
Thread runner = new Thread(this);
runner.start();
}
public void run() {
aTextTask = new textTask();
new Timer().schedule(aTextTask, 0, 2000);
while (!stop) {
update(getGraphics());
try {
Thread.currentThread().sleep(30);
} catch (Exception e) {
}
}
}
private void update(Graphics g) {
g.setColor(0xFFFFFF); // white
g.fillRect(0, 0, getWidth(), getHeight());
// bgSprite.setPosition(0, 0);
//bgSprite.nextFrame();
//bgSprite.paint(g);
buildGame(g);
//manager.paint(g, 0, 0);
flushGraphics();
}
private void buildGame(Graphics g) {
g.setColor(0xFFFFFF);
g.fillRect(0, getHeight() / 2, getWidth(), 75);
g.setColor(0x000000);
g.drawString(list[a], 0, getHeight() / 2, Graphics.LEFT);
//flushGraphics(); // Don't call flushGraphics here, because it'll be called twice then.
}
public class textTask extends TimerTask {
public textTask() {
}
public void run() {
a++;
if (a > 4) {
a = 0;
}
}
}
}
I have made a small program where the user gives the address of an image which is loaded on the ImageIcon and is displayed with a grid on it.
I now wish to get the position or the x,y cordinates of the grid in case of a mouse click on the picture.
Here's my code
import java.awt.*;
import java.awt.image.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.imageio.ImageIO;
import javax.swing.*;
class GridLines {
public static void main(String[] args) throws IOException {
System.out.println("Enter image name\n");
BufferedReader bf=new BufferedReader(new
InputStreamReader(System.in));
String imageName= null;
try {
imageName = bf.readLine();
} catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
File input = new File(imageName);
Dimension imgDim = new Dimension(200,200);
BufferedImage mazeImage = new BufferedImage(imgDim.width, imgDim.height, BufferedImage.TYPE_INT_RGB);
mazeImage = ImageIO.read(input);
Integer k = mazeImage.getHeight();
Integer l = mazeImage.getWidth();
Graphics2D g2d = mazeImage.createGraphics();
g2d.setBackground(Color.WHITE);
//g2d.fillRect(0, 0, imgDim.width, imgDim.height);
g2d.setColor(Color.RED);
BasicStroke bs = new BasicStroke(1);
g2d.setStroke(bs);
// draw the black vertical and horizontal lines
for(int i=0;i<21;i++){
// unless divided by some factor, these lines were being
// drawn outside the bound of the image..
g2d.drawLine((l+2)/4*i, 0, (l+2)/4*i,k-1);
g2d.drawLine(0, (k+2)/5*i, l-1, (k+2)/5*i);
}
ImageIcon ii = new ImageIcon(mazeImage);
JOptionPane.showMessageDialog(null, ii);
}
}
Hope i get some help. Thanks in advance :)
The basic idea is to add a MouseListener to a component. In your case, you used a JOptionPane which does not provide access to the displayed components. Anyway, JOptionPane are not made for that purpose.
So I took the liberty to tackle this with a whole different angle. The code is far from perfect (for example, everything is in a single class), but it gives you a hint on how you could start. I think this will provide a better base to start from.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.IOException;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.filechooser.FileFilter;
class GridLines {
private JFrame frame;
class MyGridPanel extends JPanel {
private static final int ROWS = 4;
private static final int COLS = 5;
class CellPanel extends JPanel {
int x;
int y;
public CellPanel(final int x, final int y) {
setOpaque(false);
this.x = x;
this.y = y;
MouseListener mouseListener = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
JOptionPane.showMessageDialog(CellPanel.this, "You pressed the cell with coordinates: x=" + x + " y=" + y);
}
};
setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.RED));
addMouseListener(mouseListener);
}
}
private final ImageIcon image;
public MyGridPanel(ImageIcon imageIcon) {
super(new GridLayout(ROWS, COLS));
this.image = imageIcon;
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
add(new CellPanel(i, j));
}
}
// Call to setPreferredSize must be made carefully. This case is a good reason.
setPreferredSize(new Dimension(imageIcon.getIconWidth(), imageIcon.getIconHeight()));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image.getImage(), 0, 0, this);
}
}
protected void initUI() {
frame = new JFrame(GridLines.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
File file = selectImageFile();
if (file != null) {
ImageIcon selectedImage = new ImageIcon(file.getAbsolutePath());
frame.add(new MyGridPanel(selectedImage));
frame.pack();
frame.setVisible(true);
} else {
System.exit(0);
}
}
public File selectImageFile() {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
fileChooser.setFileFilter(new FileFilter() {
#Override
public String getDescription() {
return "Images files (GIF, PNG, JPEG)";
}
#Override
public boolean accept(File f) {
if (f.isDirectory()) {
return true;
}
String fileName = f.getName().toLowerCase();
return fileName.endsWith("gif") || fileName.endsWith("png") || fileName.endsWith("jpg") || fileName.endsWith("jpeg");
}
});
int retval = fileChooser.showOpenDialog(frame);
if (retval == JFileChooser.APPROVE_OPTION) {
return fileChooser.getSelectedFile();
}
return null; // Cancelled or closed
}
public static void main(String[] args) throws IOException {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedLookAndFeelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new GridLines().initUI();
}
});
}
}