I have to change the icon of a label every 2 seconds. I have 3 pictures in src folder. To change them i use a thread. The code i wrote:
private Thread t;
private int indexIcon;
public ImageIcon[] icons = {new ImageIcon(this.getClass().getResource("orange.jpg")),
new
ImageIcon(this.getClass().getResource("cosmote.jpg")), new
ImageIcon(this.getClass().getResource("vodafone.jpg"))};
public void run() {
while (true) {
try {
Thread.sleep(2000);
if (Thread.interrupted()) {
return;
}
indexIcon++;
if (indexIcon > 2) {
indexIcon = 0;
}
jLabel8.setIcon(icons[indexIcon]);
} catch (InterruptedException ex) {
Logger.getLogger(CarteDeTelefonGUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
And in the class constructor:
t = new Thread(this);
t.start();
It works fine, but the problem is that when i run the program on a different computer it doesn't read the images, i get a nullpointer exception.
How could i solve this problem?
Related
I am trying to achieve a slideshow, gif etc. I have listed images read from a folder and make them a sequence for displaying in a SWT dialog. now I have a trouble with thread access. What is the way of making slideshow in SWT. thanks for any advice and correction.
here is the implementation:
public class ImageShowDialog extends Dialog {
Shell dialog;
private Label labelImage;
private Canvas canvas;
int numberImage = 0;
private volatile boolean running = true;
ImageShowDialog(Shell parent) {
super(parent);
}
public String open() {
Shell parent = getParent();
dialog = new Shell(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL);
dialog.setSize(600, 400);
dialog.setText("Show Begins!!!");
dialog.setLayout(new FillLayout());
this.func();
dialog.open();
Display display = parent.getDisplay();
while (!dialog.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
return "After Dialog";
}
public void func() {
final List<byte[]> imageCollection = new ArrayList<byte[]>();
File path = new File("..\\folder");
File[] files = path.listFiles();
for (int i = 0; i < files.length; i++) {
if (files[i].isFile()) { // this line weeds out other
// directories/folders
try {
imageCollection.add(loadImage(files[i]));
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
new Thread(new Runnable() {
#Override
public void run() {
while (running) {
ImageData imageData = new ImageData(
new ByteArrayInputStream(
imageCollection.get(numberImage)));
final Image image = new Image(Display.getDefault(),
imageData);
canvas = new Canvas(dialog, SWT.NONE);
canvas.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
e.gc.setAlpha(255);
e.gc.drawImage(image, 0, 0);
}
});
numberImage++;
if (numberImage == imageCollection.size())
try {
running = false;
} catch (Exception e) {
e.printStackTrace();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
public byte[] loadImage(File file) throws IOException {
BufferedImage image = ImageIO.read(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageIO.write(image, "jpg", bos);
return bos.toByteArray();
}
and exception:
Exception in thread "Thread-45" org.eclipse.swt.SWTException: Invalid thread access
at org.eclipse.swt.SWT.error(SWT.java:4282)
at org.eclipse.swt.SWT.error(SWT.java:4197)
at org.eclipse.swt.SWT.error(SWT.java:4168)
at org.eclipse.swt.widgets.Widget.error(Widget.java:468)
at org.eclipse.swt.widgets.Widget.checkWidget(Widget.java:359)
at org.eclipse.swt.widgets.Widget.checkParent(Widget.java:279)
at org.eclipse.swt.widgets.Widget.<init>(Widget.java:149)
at org.eclipse.swt.widgets.Control.<init>(Control.java:110)
at org.eclipse.swt.widgets.Scrollable.<init>(Scrollable.java:75)
at org.eclipse.swt.widgets.Composite.<init>(Composite.java:95)
at org.eclipse.swt.widgets.Canvas.<init>(Canvas.java:79)
You can only create and access SWT controls in the main UI thread, any attempt to do so in other threads will give the 'invalid thread access' error you are getting.
You can use the asyncExec or syncExec method of Display in your background thread to run code in the main thread:
Display.getDefault().asyncExec(() ->
{
... code accessing the UI
});
(Java 8/9 code using a lambda, use a Runnable for old Java).
asyncExec runs the code asynchronously, syncExec waits for the UI thread to run the code before returning.
SWT is singlethreaded, as described by Riduidel in this post: Updating SWT objects from another thread
So, instead of doing what you do, try the below:
Display.getDefault().asyncExec(new Runnable() {
public void run() {
ImageData imageData = new ImageData(
new ByteArrayInputStream(
imageCollection.get(numberImage)));
final Image image = new Image(Display.getDefault(),
imageData);
canvas = new Canvas(dialog, SWT.NONE);
...
}
});
I'm new in Java (still learning) all the other works have gone well but only this animation gives my headache and the coffee won't even help=(!
I should make an animation of Javaman (10 gif pictures named as T1, T2,...T10) I should use Thread, MediaTracker-class and addImage-method. Then I should specify the speed of the animation by using sleep-method (I used join-method if that's right??).
(MY JAVA CODE GOES LIKE THIS)
import java.applet.Applet;
import java.awt.*;
public class Animaatio extends Applet implements Runnable {
Image[] images = null;
MediaTracker tracker = null;
int current = 0;
Thread animThread;
#Override
public void init() {
// Creating a new media tracker, to track loading images
tracker = new MediaTracker(this);
// Creating an array of ten images
images = new Image[10];
// Downloading the images
for (int i = 0; i < 10; i++) {
// Loading the images
images[i] = getImage(getCodeBase(), (i + 1) + "T.gif");
tracker.addImage(images[i], 0);
}
try {
tracker.waitForAll();
} catch (InterruptedException e) {
}
}
#Override
public void start() {
if (animThread == null) {
animThread = new Thread(this);
animThread.start();
}
try {
animThread.join();
} catch (InterruptedException e) {
}
}
#Override
public void paint(Graphics g) {
g.drawImage(images[current++], 0, 0, this);
}
#Override
public void run() {
while (true) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
}
}
The problem is that I don't see any animation just an empty applet viewer which just keeps running. Problem might be caused if the images are storaged in the wrong place? If someone could wreally help me, I would be really thankful for my knight=).
Trying to get an image from another application sending an array of bytes through socket, translating it to a BufferedImage and setting a JLabel in the GUI that updates every 3 seconds.
I tried looking it up on forums but questions regarding graphical update are recurrent to me and I never seem to get it right -- there's at least 6 update methods in java for graphical interface and every one I tried won't work.
I know the problem isn't in the connection to the client because I can easily save the image I receive with ImageIO.write() and it updates every 3 seconds to the image I was expecting to receive. I just can't have Java updating the JLabel correctly without having to go to forums and ask people. Such a complex task I guess. Here is the code: http://pastebin.com/95nMGLvZ. I am doing this project in Netbeans so there's a lot of stuff in there that is unnecessary to read as it does not directly relate to the problem.
I think the answer lies in creating a separate thread to update my JLabel from the ever-changing BufferedImage that is received from the ObjectInputStream. Anyone mind giving me a hand at this? What is better for my code? SwingWorker, Threading (wtf is setDaemon(flag)?), Runnable, Timer, invokeLater? Tried all of this. Not correctly apparently.
EDIT1:
Tried your answer immibis:
public void startRunning() {
try {
server = new ServerSocket(666, 10);
connection = server.accept();
networkStatus("Connected to " + connection.getInetAddress().getHostName());
Thread thr = new Thread(new Runnable() {
#Override
public void run() {
try {
input = new ObjectInputStream(connection.getInputStream());
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, ex.toString());
}
}
});
thr.start();
System.out.println(!connection.isInputShutdown());
while (connection.isConnected()) {
try {
byte[] byteImage = (byte[]) input.readObject();
InputStream in = new ByteArrayInputStream(byteImage);
final BufferedImage bi = ImageIO.read(in);
jLabel_screen.setIcon(new ImageIcon(bi));
ImageIO.write(bi, "jpg", new File("C:\\Users\\User\\Desktop\\test.jpg"));
System.out.println("i'm working");
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, ex.toString());
} catch (ClassNotFoundException ex) {
Logger.getLogger(SpyxServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, ex.toString());
}
}
It does not work. It says byte[] byteImage = (byte[]) input.readObject(); line has a NullPointerException. The only value that can be null is the return from readObject(), meaning either the input was not initialized correctly or the connection is not synchronized. I hope it's the first option because I wouldn't know how to handle the last.
EDIT2:
Tried your answer blazetopher:
public void startRunning() throws IOException {
server = new ServerSocket(666, 10);
try {
connection = server.accept();
networkStatus("Connected to " + connection.getInetAddress().getHostName());
input = new ObjectInputStream(connection.getInputStream());
while (true) {
try {
byte[] byteImage = (byte[]) input.readObject();
InputStream in = new ByteArrayInputStream(byteImage);
final BufferedImage bi = ImageIO.read(in);
SwingUtilities.invokeLater(new Runnable() {//<-----------
#Override
public void run() {
jLabel_screen.setIcon(new ImageIcon(bi));
}
});
ImageIO.write(bi, "jpg", new File("C:\\Users\\User\\Desktop\\test.jpg"));
System.out.println("i'm working");
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, ex.toString());
} catch (ClassNotFoundException ex) {
Logger.getLogger(SpyxServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
} catch (EOFException eofException) {
networkStatus("Connection Closed. :(");
} finally {
input.close();
connection.close();
}
}
Using SwingUtilities.invokeLater didn't work either. At least the program runs and can even save the image but still can't update the JLabel. Am I running out of options here?
EDIT3:
Tried Jordan's code:
#Override
public void paint(Graphics g) {
g.drawImage(biGlobal, 0, 0, null);
}
The GUI kind of crashed and was "drawing" the components just when I had my mouse cursor hovering it. When I started the code, it did not crashed (+1) but it did not draw anything, even when I try to hover the cursor into where the BufferedImage should be painted. Maybe I should add revalidate() or repaint after calling the Overwritten paint(getGraphics()) inside the startRunning() method?
EDIT4: the while(true) that the code is actually in may be the problem but when I use a SwingTimer it gets out of sync with the client and crashes after first cycle. Any alternatives to this?
Generally speaking you have a producer/consumer pattern. Something is producing images and something wants to consume images. Normally, the consumer would wait on the producer to tell it something has been produced, but in this case, we can use a observer pattern instead, having the producer notify the consumer that something was been produced (instead of waiting for it)
We need someway for the producer to communicate with the consumer...
public interface PictureConsumer {
public void newPicture(BufferedImage img);
}
You would create an implementation of this in your UI code, this would then set the icon property of the JLabel
Now, we need something to produce the images...
public class PictureProducer extends SwingWorker<Object, BufferedImage> {
private PictureConsumer consumer;
public PictureProducer(PictureConsumer consumer) {
this.consumer = consumer;
}
#Override
protected void process(List<BufferedImage> chunks) {
// Really only interested in the last image
BufferedImage img = chunks.get(chunks.size() - 1);
consumer.newPicture(img);
}
#Override
protected Object doInBackground() throws Exception {
/*
This whole setup worries me. Why is this program acting as the
server? Why aren't we pooling the image producer?
*/
try (ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(666, 10)) {
try (Socket socket = server.accept()) {
try (ObjectInputStream ois = new ObjectInputStream(socket.getInputStream())) {
// Using `while (true)` is a bad idea, relying on the fact
// that an exception would be thrown when the connection is closed is
// a bad idea.
while (!socket.isClosed()) {
// Generally, I'd discourage using an ObjectInputStream, this
// is just me, but you could just as easily read directly from
// the ByteArrayInputStream...assuming the sender was sending
// the data as a byte stream ;)
byte[] bytes = (byte[]) ois.readObject();
try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes)) {
BufferedImage img = ImageIO.read(bis);
publish(img);
}
}
}
}
}
return null;
}
#Override
protected void done() {
try {
get();
} catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null, "Image Producer has failed: " + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
}
}
}
See Worker Threads and SwingWorker for more details
You can a reverse example of this (where some server is producing images and a client is consuming them) here
To update your label, you want to ensure you're using the EDT thread, so use SwingUtilities.invokeLater from the code where you're receiving the BufferedImage (which would ideally be in a separate "worker" thread:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
// Update your label here
}
});
What is it you are attempting to accomplish.there might be a better way all together.
For example replace the JLabel with a JPanel then use that JPanel paint method
#Override
public void paint(Graphics g) {
g.drawImage(Img, xcord, ycord, null);
}
Then make that JPanel implement runnable and do your updates in that run method.
JPanel class
public class GraphicsPanel extends JPanel{
private BufferedImage img;
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D G2D = (Graphics2D) g;
G2D.drawImage(img, 0, 0, null);
}
public void setImg(BufferedImage img) {
this.img = img;
}
}
then make sure this panel is visible from wherever you wish to call its methods.
this will look something like this
GraphicsPanel graphicsPanel = new GraphicsPanel();
boolean running;
BufferedImage srcImage;
public void run(){
while(running){
graphicsPanel.setImg(srcImage);
graphicsPanel.repaint();
try {
Thread.sleep(300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I made a simple programm to let java play some .mp3 files.
Using JLayer to get this right.
The problem is that i can't interrupt my player after pushing a button.
my code in actionperformed:
class MyThread extends Thread {
#Override
public void run() {
try {
File file = new File(source);
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
try {
Thread.sleep(1);
try {
Player player = new Player(bis);
player.play();
} catch (JavaLayerException ex) {
}
} catch (InterruptedException e) {
System.out.println("Came");
}
} catch (IOException e) {
lab2.setText("error, is the pathway correct?");
}
}
}
MyThread mythread = new MyThread();
if (event.getSource() == input) {
source = input.getText();
source = source.replace("\\", "\\\\");
lab1.setText(source);
}
if (event.getSource() == but1) {
mythread.start();
}
if (event.getSource() == but2) {
but2.setLabel("stop");
mythread.interrupt();
but2.setLabel("stopped");
}
}
}
When I add the mythread.interrupt(); directly behind the interrupt works and my system gives me the "came" output.
But if I use my button called input, it wont work.
Seems that player class doesnt have a stop method, but you can try with AdvancedPlayer:
http://www.javazoom.net/javalayer/docs/docs1.0/javazoom/jl/player/advanced/AdvancedPlayer.html
and the stop() method.
I am following a guide that shows how to create a Pong game. There is a part, where I am supposed to create a Thread, and call a function that moves the ball.
This is the code I created:
package com.ozadari.pingpong;
public class PingPongGame extends Thread {
private Ball gameBall;
private PingPongView gameView;
public PingPongGame(Ball theBall,PingPongView mainView)
{
this.gameBall = theBall;
this.gameView = mainView;
}
#Override
public void run()
{
while(true)
{
this.gameBall.moveBall();
this.gameView.postInvalidate();
try
{
PingPongGame.sleep(5);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}}
The thread is called and working, but it doesn't print anything. I tried to cancel the infinte loop and make the loop run 100 times. After I wait a while, it prints to the screen as it should be after 100 runs, but it doesn't print anything in the middle.
What is the problem? How can I fix it?
Unsure from the code you've posted but anyway, you can use a handler and have it run once every second like so (change the time to what you want):
Handler handler = new Handler();
final Runnable r = new Runnable()
{
public void run()
{
//do your stuff here
handler.postDelayed(this, 1000);
}
};
handler.postDelayed(r, 1000);
http://developer.android.com/reference/android/os/Handler.html
You can also use a normal thread, and call start at the end.
Thread thread = new Thread()
{
#Override
public void run() {
try {
while(true) {
sleep(1000);
handler.post(r);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();