drawing image in jframe game - java

I'm having some trouble getting an image drawn in java. There are no console errors and it prints 'drawing'. I believe I am loading the image wrong but I can't figure out the right way. If someone could tell me the correct way that would be great.
package platformer;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.util.List;
import java.util.ArrayList;
import javax.swing.Timer;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.awt.Image;
public class test2 extends JPanel implements KeyListener, ActionListener {
int Width = 1000;
int Height = 600;
private static Image offScreenBuffer;// needed for double buffering graphics
private Graphics offScreenGraphics;// needed for double buffering graphics
private BufferedImage[] img = new BufferedImage[1];
public test2() {
}
public void paint(Graphics g) {
super.paint(g);
g.drawImage(img[0],0,0,null);
}
public void timer1() {
int delay = 30; // milliseconds
new Timer(delay, this).start();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void actionPerformed(ActionEvent evt) {
}
public static void main(String args[]) throws InterruptedException, Exception {
test2 test2 = new test2();
JFrame frame = new JFrame("platformer");
frame.setSize(test2.Width, test2.Height);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setBackground(Color.green);
frame.add(test2);
frame.setResizable(false);
frame.addKeyListener(test2);
test2.init();
test2.timer1();
// What to do after the program starts
while (true) {
test2.repaint();
}
}
public void init() {
try {
URL url = new URL("platform.png");
img[0] = ImageIO.read(url);
} catch (IOException e) {
}
}
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
}

Swing has an infinite loop that does event handling for you. You don't need the while(true) loop. You should call frame.setVisible(true) after all of your UI is configured. I mean that it should be the last thing in main(). Also, you should do this on the UI thread with
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
So main() should look like
public static void main(String args[]) throws InterruptedException, Exception {
test2 test2 = new test2();
JFrame frame = new JFrame("platformer");
frame.setSize(test2.Width, test2.Height);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setBackground(Color.green);
frame.add(test2);
frame.setResizable(false);
frame.addKeyListener(test2);
test2.init();
test2.timer1();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
}
However, the main problem is the try... catch in init() which ignores exceptions. You should never leave a catch empty. At the very least you should print a stacktrace. Better yet, add the appropriate exceptions to the methods throws clause like this:
public void init() throws IOException {
URL url = new URL("platform.png");
img[0] = ImageIO.read(url);
}
Note if a problem occurs, you will know about it immediately.

Related

I am using ffmpeg java library to convert captured screenshots to video. Video output is blurry

I am using ffmpeg java library to convert captured screenshots to video. Video which is generated as output is blurry.
I am using bit rate as 9000, frames per sec as 25 and video size as that of desktop screen size.
Any suggestions on how to solve this issue.
P.S. I cannot use ffmpeg.exe and command line due to certain restrictions and hence I am opting for ffmpeg java library.
Any suggestions on the issue or suggestions on any better approach will be helpful.
import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import org.bytedeco.javacpp.avcodec;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.OpenCVFrameConverter;
public class ScreenRecorder{
public static boolean videoComplete=false;
public static String inputImageDir="inputImgFolder"+File.separator;
public static String inputImgExt="png";
public static String outputVideo="recording.mp4";
public static int counter=0;
public static int imgProcessed=0;
public static FFmpegFrameRecorder recorder=null;
public static int videoWidth=1920;
public static int videoHeight=1080;
public static int videoFrameRate=3;
public static int videoQuality=0; // 0 is the max quality
public static int videoBitRate=9000;
public static String videoFormat="mp4";
public static int videoCodec=avcodec.AV_CODEC_ID_MPEG4;
public static Thread t1=null;
public static Thread t2=null;
public static JFrame frame=null;
public static boolean isRegionSelected=false;
public static int c1=0;
public static int c2=0;
public static int c3=0;
public static int c4=0;
public static void main(String[] args) {
try {
if(getRecorder()==null)
{
System.out.println("Cannot make recorder object, Exiting program");
System.exit(0);
}
if(getRobot()==null)
{
System.out.println("Cannot make robot object, Exiting program");
System.exit(0);
}
File scanFolder=new File(inputImageDir);
scanFolder.delete();
scanFolder.mkdirs();
createGUI();
} catch (Exception e) {
System.out.println("Exception in program "+e.getMessage());
}
}
public static void createGUI()
{
frame=new JFrame("Screen Recorder");
JButton b1=new JButton("Select Region for Recording");
JButton b2=new JButton("Start Recording");
JButton b3=new JButton("Stop Recording");
JLabel l1=new JLabel("<html><br/>If you dont select a region then full screen recording <br/> will be made when you click on Start Recording</html>");
l1.setFont (l1.getFont ().deriveFont (20.0f));
b1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
JOptionPane.showMessageDialog(frame, "A new window will open. Use your mouse to select the region you like to record");
new CropRegion().getImage();
} catch (Exception e1) {
// TODO Auto-generated catch block
System.out.println("Issue while trying to call the module to crop region");
e1.printStackTrace();
}
}
});
b2.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
counter=0;
startRecording();
}
});
b3.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
stopRecording();
System.out.print("Exiting...");
System.exit(0);
}
});
frame.add(b1);
frame.add(b2);
frame.add(b3);
frame.add(l1);
frame.setLayout(new FlowLayout(0));
frame.setVisible(true);
frame.setSize(1000, 170);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void startRecording()
{
t1=new Thread()
{
public void run() {
try {
takeScreenshot(getRobot());
} catch (Exception e) {
JOptionPane.showMessageDialog(frame, "Cannot make robot object, Exiting program "+e.getMessage());
System.out.println("Cannot make robot object, Exiting program "+e.getMessage());
System.exit(0);
}
}
};
t2=new Thread()
{
public void run() {
prepareVideo();
}
};
t1.start();
t2.start();
System.out.println("Started recording at "+new Date());
}
public static Robot getRobot() throws Exception
{
Robot r=null;
try {
r = new Robot();
return r;
} catch (AWTException e) {
JOptionPane.showMessageDialog(frame, "Issue while initiating Robot object "+e.getMessage());
System.out.println("Issue while initiating Robot object "+e.getMessage());
throw new Exception("Issue while initiating Robot object");
}
}
public static void takeScreenshot(Robot r)
{
Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
Rectangle rec=new Rectangle(size);
if(isRegionSelected)
{
rec=new Rectangle(c1, c2, c3-c1, c4-c2);
}
while(!videoComplete)
{
counter++;
BufferedImage img = r.createScreenCapture(rec);
try {
ImageIO.write(img, inputImgExt, new File(inputImageDir+counter+"."+inputImgExt));
} catch (IOException e) {
JOptionPane.showMessageDialog(frame, "Got an issue while writing the screenshot to disk "+e.getMessage());
System.out.println("Got an issue while writing the screenshot to disk "+e.getMessage());
counter--;
}
}
}
public static void prepareVideo()
{
File scanFolder=new File(inputImageDir);
while(!videoComplete)
{
File[] inputFiles=scanFolder.listFiles();
try {
getRobot().delay(500);
} catch (Exception e) {
}
//for(int i=0;i<scanFolder.list().length;i++)
for(int i=0;i<inputFiles.length;i++)
{
//imgProcessed++;
addImageToVideo(inputFiles[i].getAbsolutePath());
//String imgToAdd=scanFolder.getAbsolutePath()+File.separator+imgProcessed+"."+inputImgExt;
//addImageToVideo(imgToAdd);
//new File(imgToAdd).delete();
inputFiles[i].delete();
}
}
File[] inputFiles=scanFolder.listFiles();
for(int i=0;i<inputFiles.length;i++)
{
addImageToVideo(inputFiles[i].getAbsolutePath());
inputFiles[i].delete();
}
}
public static FFmpegFrameRecorder getRecorder() throws Exception
{
if(recorder!=null)
{
return recorder;
}
recorder = new FFmpegFrameRecorder(outputVideo,videoWidth,videoHeight);
try
{
recorder.setFrameRate(videoFrameRate);
recorder.setVideoCodec(videoCodec);
recorder.setVideoBitrate(videoBitRate);
recorder.setFormat(videoFormat);
recorder.setVideoQuality(videoQuality); // maximum quality
recorder.start();
}
catch(Exception e)
{
JOptionPane.showMessageDialog(frame, "Exception while starting the recorder object "+e.getMessage());
System.out.println("Exception while starting the recorder object "+e.getMessage());
throw new Exception("Unable to start recorder");
}
return recorder;
}
public static OpenCVFrameConverter.ToIplImage getFrameConverter()
{
OpenCVFrameConverter.ToIplImage grabberConverter = new OpenCVFrameConverter.ToIplImage();
return grabberConverter;
}
public static void addImageToVideo(String imgPath)
{
try {
getRecorder().record(getFrameConverter().convert(cvLoadImage(imgPath)));
} catch (Exception e) {
JOptionPane.showMessageDialog(frame, "Exception while adding image to video "+e.getMessage());
System.out.println("Exception while adding image to video "+e.getMessage());
}
}
public static void stopRecording()
{
try {
videoComplete=true;
System.out.println("Stopping recording at "+new Date());
t1.join();
System.out.println("Screenshot thread complete");
t2.join();
System.out.println("Video maker thread complete");
getRecorder().stop();
System.out.println("Recording has been saved successfully at "+new File(outputVideo).getAbsolutePath());
JOptionPane.showMessageDialog(frame, "Recording has been saved successfully at "+new File(outputVideo).getAbsolutePath());
} catch (Exception e) {
System.out.println("Exception while stopping the recorder "+e.getMessage());
}
}
}
Imagepanel.java
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
class ImagePanel
extends JPanel
{
private Image img;
public ImagePanel(String img)
{
this(new ImageIcon(img).getImage());
}
public ImagePanel(Image img)
{
this.img = img;
Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
setPreferredSize(size);
setMinimumSize(size);
setMaximumSize(size);
setSize(size);
setLayout(null);
}
public void paintComponent(Graphics g)
{
g.drawImage(this.img, 0, 0, null);
}
}
CropRegion.java
import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
public class CropRegion implements MouseListener,
MouseMotionListener {
int drag_status = 0;
int c1;
int c2;
int c3;
int c4;
JFrame frame=null;
static int counter=0;
JLabel background=null;
public void getImage() throws AWTException, IOException, InterruptedException {
Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
Robot robot = new Robot();
BufferedImage img = robot.createScreenCapture(new Rectangle(size));
ImagePanel panel = new ImagePanel(img);
frame=new JFrame();
frame.add(panel);
frame.setLocation(0, 0);
frame.setSize(size);
frame.setLayout(new FlowLayout());
frame.setUndecorated(true);
frame.setVisible(true);
frame.addMouseListener(this);
frame.addMouseMotionListener(this);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
public void draggedScreen() throws Exception {
ScreenRecorder.c1=c1;
ScreenRecorder.c2=c2;
ScreenRecorder.c3=c3;
ScreenRecorder.c4=c4;
ScreenRecorder.isRegionSelected=true;
JOptionPane.showMessageDialog(frame, "Region Selected.Please click on Start Recording button to record the selected region.");
frame.dispose();
}
public void mouseClicked(MouseEvent arg0) {
}
public void mouseEntered(MouseEvent arg0) {
}
public void mouseExited(MouseEvent arg0) {
}
public void mousePressed(MouseEvent arg0) {
paint();
this.c1 = arg0.getX();
this.c2 = arg0.getY();
}
public void mouseReleased(MouseEvent arg0) {
paint();
if (this.drag_status == 1) {
this.c3 = arg0.getX();
this.c4 = arg0.getY();
try {
draggedScreen();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void mouseDragged(MouseEvent arg0) {
paint();
this.drag_status = 1;
this.c3 = arg0.getX();
this.c4 = arg0.getY();
}
public void mouseMoved(MouseEvent arg0) {
}
public void paint() {
Graphics g = frame.getGraphics();
frame.repaint();
int w = this.c1 - this.c3;
int h = this.c2 - this.c4;
w *= -1;
h *= -1;
if (w < 0) {
w *= -1;
}
g.drawRect(this.c1, this.c2, w, h);
}
}

Why isn't the paintComponent method being called?

The messages that ought to be printed in the printComponent method are not printed. I am having the impression that the paint method is not called. If not, why not?
import java.util.*;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.swing.*;
import javax.imageio.*;
public class Main extends JFrame{
CustomComponent cc;
public static void main(String[] args) {
Main m = new Main();
}
public Main(){
setTitle( "Diverse Testari 7");
setLayout(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(600, 400);
cc = new CustomComponent();
cc.setImage("rgbcmy.jpg");
add(cc);
pack();
setVisible( true );
}
}
class CustomComponent extends JPanel{
BufferedImage img = null;
public void setImage( String str ){
try {
img = ImageIO.read( new File( str ) );
System.out.println("SUCCESS!");
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
protected void paintComponent(Graphics g) {
// TODO Auto-generated method stub
System.out.println("altceva");
super.paintComponent(g);
System.out.println("ceva");
}
}
Add this code in your Main constructor:
new Thread(new Runnable() {
public void run() {
repaint();
try {
Thread.sleep(20);
} catch (InterruptedException e) {}
}
}).start();
paintComponent will only be called when you repaint();.
Also, NEVER NEVER NEVER use setLayout(null);. See here.
This code will continually repaint the panel, so it will continually call paintComponent. This is good because it will always keep the panel updated. You could also just call repaint(); when you change what's in the panel.

Wait cursor and disable java application

I want to have the user press a button to kick off a background thread.
While the thread is processing, I want two things to happen:
1) A WAIT_CURSOR should be displayed.
2) The application should not respond to mouse events.
As per the setCursor documentation "This cursor image is displayed when the contains method for this component returns true for the current cursor location, and this Component is visible, displayable, and enabled. ".
I want my application to be disabled while this background thread is processing.
Any ideas how to get the functionality I want?
import java.awt.Component;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class WaitCursor extends JFrame
{
private static final long serialVersionUID = 1L;
public WaitCursor()
{
setResizable(false);
setName(getClass().getSimpleName());
setTitle("My Frame");
setSize(300, 300);
getContentPane().add(new MyButtonPanel());
}
private class MyButtonPanel extends JPanel
{
private static final long serialVersionUID = 1L;
public MyButtonPanel()
{
JButton btnStart = new JButton("Start");
btnStart.addActionListener(new BtnStartActionListener());
add(btnStart);
}
private class BtnStartActionListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
// Change to WAIT_CURSOR
Component root = SwingUtilities.getRoot((JButton) e.getSource());
JOptionPane.showMessageDialog(root, "Wait 10 seconds");
root.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
// TODO: Disabling the root component prevents the WAIT_CURSOR from being displayed
root.setEnabled(false);
new Thread(new TimeKiller(root)).start();
}
}
}
private class TimeKiller implements Runnable
{
Component _root;
public TimeKiller(Component root)
{
_root = root;
}
public void run()
{
try
{
Thread.sleep(10 * 1000);
}
catch (InterruptedException e)
{
// Ignore it
}
// Change back to DEFAULT CURSOR
JOptionPane.showMessageDialog(_root, "Done waiting");
_root.setCursor(Cursor.getDefaultCursor());
_root.setEnabled(true);
}
}
private static void createAndShowGUI()
{
// Create and set up the window.
WaitCursor frame = new WaitCursor();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
try
{
createAndShowGUI();
}
catch (Exception e)
{
e.printStackTrace();
System.exit(0);
}
}
});
}
}
One way to disable it is to use the glass pane to block mouse input.
For example:
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import javax.swing.*;
#SuppressWarnings("serial")
public class WaitCursor2 extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private JComponent glassPane;
private JButton runBackgroundProcBtn;
private JTextArea textarea = new JTextArea(15, 30);
public WaitCursor2(JComponent glassPane) {
this.glassPane = glassPane;
glassPane.setFocusable(true);
glassPane.addMouseListener(new MouseAdapter() {
}); // so it will trap mouse events.
add(new JTextField(10));
add(runBackgroundProcBtn = new JButton(new AbstractAction(
"Run Background Process") {
#Override
public void actionPerformed(ActionEvent arg0) {
runBackgroundProcessAction();
}
}));
add(new JScrollPane(textarea));
}
private void runBackgroundProcessAction() {
disableSystem(true);
glassPane.setVisible(true);
new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
long sleepTime = 5000;
Thread.sleep(sleepTime);
return null;
}
#Override
protected void done() {
disableSystem(false);
}
}.execute();
}
public void disableSystem(boolean disable) {
glassPane.setVisible(disable);
runBackgroundProcBtn.setEnabled(!disable);
if (disable) {
System.out.println("started");
glassPane.requestFocusInWindow(); // so can't add text to text components
glassPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
} else {
System.out.println("done");
glassPane.setCursor(Cursor.getDefaultCursor());
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("WaitCursor2");
WaitCursor2 mainPanel = new WaitCursor2((JComponent) frame.getGlassPane());
frame.setDefaultCloseOperation(JFrame.EXIT_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();
}
});
}
}
The glass pane will trap mouse events if it set visible and given a MouseListener. It will lose t his ability if it is set invisible. Likewise it will pull the caret from text components if you make it focusable and give it focus.
added a field current_active and at method actionPerformed, do a simple check. Albeit it is not perfect but for simple app, i think this do the trick. A crude way of solving your two requirement. :-) Hope it works for you too.
import java.awt.Component;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class WaitCursor extends JFrame
{
private static boolean current_active = false;
public WaitCursor()
{
setResizable(false);
setName(getClass().getSimpleName());
setTitle("My Frame");
setSize(300, 300);
getContentPane().add(new MyButtonPanel());
}
private class MyButtonPanel extends JPanel
{
public MyButtonPanel()
{
JButton btnStart = new JButton("Start");
btnStart.addActionListener(new BtnStartActionListener());
add(btnStart);
}
private class BtnStartActionListener implements ActionListener
{
// change to wait_cursor
public void actionPerformed(ActionEvent e)
{
if (!current_active)
{
Component root = SwingUtilities.getRoot((JButton) e.getSource());
JOptionPane.showMessageDialog(root, "Wait 10 seconds");
root.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
// TODO: Disabling the root component prevents the WAIT_CURSOR from being displayed
//root.setEnabled(false);
current_active = true;
new Thread(new TimeKiller(root)).start();
}
}
}
}
private class TimeKiller implements Runnable
{
Component m_root;
public TimeKiller(Component p_root)
{
m_root = p_root;
}
#Override
public void run()
{
try
{
Thread.sleep(10 * 1000);
}
catch (InterruptedException e)
{
//Ignore it
}
// Change back to DEFAULT CURSOR
JOptionPane.showMessageDialog(m_root, "Done waiting");
m_root.setCursor(Cursor.getDefaultCursor());
current_active = false;
}
}
// create and setup the window.
public static void createAndShowGUI()
{
WaitCursor frame = new WaitCursor();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
try
{
createAndShowGUI();
}
catch (Exception e)
{
e.printStackTrace();
System.exit(0);
}
}
});
}
}

Good way to set/refresh information with thread in java swing app

I'm not a Java programmer and I'm not sure if what I'm doing is correct or not, or if exist a better way to do this.
I'm making a swing Java app with multi-threading.
I have many swing component (textfield, texarea, label, list, ...) which are set and refresh with many threads.
For all my component I use something like the code below (it's just a tiny example) for set/refresh it.
Is Main.mainUI.setThumbLbl(image); for set/refresh my component a good way or not ? (I use something like this in other threads for all component)
And is there another better way to do this ?
Main :
public class Main {
public static MyMainUI mainUI;
public static void main(String args[]) {
mainUI = new mainUI();
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
mainUI.setVisible(true);
}
});
}
}
Jframe :
public class MyMainUI extends JFrame {
private JLabel thumbLbl;
private JButton thumbBtn;
public MyMainUI(){
// add thumbLbl, thumBtn
...
thumBtn.addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent evt) {
new MyThread().start();
}
});
}
public void setThumbLbl(final Image image) {
SwingUtilities.invokeLater(new Thread() {
#Override
public void run() {
thumbLbl.setIcon(new ImageIcon(image.getScaledInstance(thumbLblDim.width,
thumbLblDim.height, Image.SCALE_DEFAULT)));
}
});
}
}
Thread :
public class MyThread extends Thread {
#Override
public void run() {
//Get image from web server
...
Main.mainUI.setThumbLbl(image);
}
}
NB: I wrote this sample code in a text editor very quickly, maybe there are some mistakes but it's not what I'm asking for ^^.
NB2: Sorry for my bad English.
An example of what I meant is something like this:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.ExecutionException;
import javax.imageio.ImageIO;
import javax.swing.*;
public class Main {
private static void createAndShowGui() {
JFrame frame = new JFrame("Main");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MyMainUI());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class MyMainUI extends JPanel {
public static final String IMG_URL_PATH = "http://duke.kenai.com/Oracle/OracleStrat.png";
private static final int PREF_W = 900;
private static final int PREF_H = 650;
private JLabel thumbLbl = new JLabel();
private JButton thumbBtn = new JButton("Get Image");
public MyMainUI() {
thumbBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
thumbBtn.setEnabled(false);
final ImageDownloader imgDownLoader = new ImageDownloader(IMG_URL_PATH);
imgDownLoader.execute();
imgDownLoader.addPropertyChangeListener(new ImgDownLoaderListener(imgDownLoader));
}
});
JPanel btnPanel = new JPanel();
btnPanel.add(thumbBtn);
setLayout(new BorderLayout());
add(new JScrollPane(thumbLbl), BorderLayout.CENTER);
add(btnPanel, BorderLayout.PAGE_END);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private class ImgDownLoaderListener implements PropertyChangeListener {
ImageDownloader imgDownLoader;
public ImgDownLoaderListener(ImageDownloader imgDownLoader) {
this.imgDownLoader = imgDownLoader;
}
#Override
public void propertyChange(PropertyChangeEvent evt) {
// swing worker is done
if (evt.getNewValue().equals(SwingWorker.StateValue.DONE)) {
thumbBtn.setEnabled(true);
try {
ImageIcon icon = imgDownLoader.get();
if (icon != null) {
thumbLbl.setIcon(icon);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
}
class ImageDownloader extends SwingWorker<ImageIcon, Void> {
private String imageUrlPath;
public ImageDownloader(String imageUrlPath) {
this.imageUrlPath = imageUrlPath;
}
#Override
protected ImageIcon doInBackground() throws Exception {
try {
URL imgUrl = new URL(imageUrlPath);
BufferedImage img = ImageIO.read(imgUrl);
return new ImageIcon(img); // return the ImageIcon
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null; // or return null if an error occurs
}
}
The background worker thread in this example has no knowledge about the structure of the GUI. All it does is download an image -- that's it, and then the GUI which listens for completion with a PropertyChangeListener gets the image by calling get() on the worker, and decides what it wants to do with it.

Problems with a SwingWorker

I'm trying to get a SwingWorker to work.
I've the following code at the moment:
public class ImageWorker extends SwingWorker<Void, Void> implements KeyListener
{
private JLabel imageLabel;
private ImageIcon basicImage;
private ImageIcon whiteImage;
public static void main(String[] args)
{
new ImageWorker();
}
public ImageWorker()
{
final JFrame frame = new JFrame();
imageLabel = new JLabel();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.getContentPane().add(imageLabel);
frame.setVisible(true);
try
{
basicImage = new ImageIcon(ImageIO.read(new File("src\\img\\basis1.jpg")).getScaledInstance(1024, 768, Image.SCALE_SMOOTH));
whiteImage = new ImageIcon(ImageIO.read(new File("src\\img\\wit.jpg")).getScaledInstance(1024, 768, Image.SCALE_SMOOTH));
}
catch(IOException ex)
{
ex.getMessage();
}
this.execute();
}
#Override
protected Void doInBackground()
{
try
{
while (true)
{
displayImage(basicImage);
Thread.sleep(1000L);
if(isCancelled())
return null;
}
}
catch(InterruptedException e)
{
e.getMessage();
}
return null;
}
private void displayImage(final Icon image)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
imageLabel.setIcon(image);
}
});
}
I was expecting the images to appear in the JLabel, but I only see the JFrame popping up. The files are loaded correctly Ive tested that in another setup.
Any pointers?
Here is an example using a Timer rather than using the SwingWorker which really isn't appropriate to your situation. Note that it's not too different from your existing code.
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
public class ImageWorker implements KeyListener
{
private JLabel imageLabel;
private ImageIcon basicImage;
private ImageIcon whiteImage;
private boolean isBasic = true;
private int delay = 1000; //milliseconds
private Timer timer;
public static void main(String[] args)
{
new ImageWorker();
}
public ImageWorker()
{
final JFrame frame = new JFrame();
imageLabel = new JLabel();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.getContentPane().add(imageLabel);
frame.setVisible(true);
try
{
basicImage = new ImageIcon(ImageIO.read(new File("src\\img\\basis1.jpg")).getScaledInstance(1024, 768, Image.SCALE_SMOOTH));
whiteImage = new ImageIcon(ImageIO.read(new File("src\\img\\wit.jpg")).getScaledInstance(1024, 768, Image.SCALE_SMOOTH));
}
catch (IOException ex)
{
ex.getMessage();
ex.printStackTrace();
}
frame.addKeyListener(this);
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if(isBasic) {
//display basic image
imageLabel.setIcon(basicImage);
}
else {
//display white image
imageLabel.setIcon(whiteImage);
}
//toggle the flag
isBasic = !isBasic;
}
};
//use a timer instead of SwingWorker
timer = new Timer(delay, taskPerformer);
timer.start();
}
#Override
public void keyPressed(KeyEvent e)
{
//key pressed, we want to stop toggling so stop the timer
timer.stop();
//do whatever else you were doing to set the value for isCancelled();
}
#Override
public void keyReleased(KeyEvent e)
{
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e)
{
// TODO Auto-generated method stub
}
}
A SwingWorker is not appropriate for your situation look into a Timer in the swing package. Here is a link to the API: http://download.oracle.com/javase/6/docs/api/javax/swing/Timer.html
You have the timer run and change an image every second since that is what you need.
Also, whenever you have exceptions, print out a stacktrace or the message at least. Otherwise you won't know if an exception occurs and is caught.

Categories