I’ve written two java desktop applications. One of them(I call it launcher) starts another(client) application.
Both applications were compiled under java 1.6.0_32 [oracle jvm, hot spot].
The Exception handler was specified in the main thread of client app.
When the launcher is started under java 1.6.0_32 everything is OK,
But when it started under 1.7x_xx and later, the exception handler begin work unproperly.
It does not catch any exceptions.
I have write the test example, the source code was listed
The launcher app source:
Start.java:
import javax.swing.*;
import java.io.File;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
public class Start {
private ClassLoader classLoader;
private List<URL> urls = new ArrayList<URL>();
private LauncherFrame launcherFrame = new LauncherFrame();
private Start() {
urls = generateUrls();
}
public static void main(String[] args) {
new Start().initClassLoader(args);
}
public void initClassLoader(String[] args) {
launcherFrame.initComponents();
this.classLoader = new URLClassLoader(urls.toArray(new URL[urls.size()]), Start.class.getClassLoader());
try {
Class<?> mainClass = classLoader.loadClass("my.example.Runner");
Object instance = mainClass.newInstance();
Method runMethod = mainClass.getMethod("run", null);
runMethod.invoke(instance);
} catch (Exception e) {
System.out.println("exception: ");
e.printStackTrace();
}
}
public List<URL> generateUrls() {
File jarFile = new File("prog2.jar");
List<URL> urls = new ArrayList<URL>();
if (jarFile.exists()) {
try {
urls.add(jarFile.toURI().toURL());
} catch (MalformedURLException e) {
}
}
return urls;
}
class LauncherFrame extends JFrame {
public void initComponents() {
// if i comment next line, everything works fine in java 6 and 7
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
}
}
}
The client app source(prog2.jar):
Runner.java:
package my.example;
public class Runner {
public static void main(String args[]) {
new Runner().run();
}
public void run() {
ThreadGroup exceptionHandler = new ThreadGroup("Global Exception Handler") {
#Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("UncaughtException method called");
e.printStackTrace();
}
};
Runnable runnable = new MainThread();
Thread thread = new Thread(exceptionHandler, runnable);
thread.start();
}
}
MainThread.java:
package my.example;
import java.awt.*;
public class MainThread implements Runnable {
public void run() {
Toolkit.getDefaultToolkit().getSystemEventQueue().push(new MyQueue());
MainFrame w = new MainFrame();
w.open();
}
public class MyQueue extends EventQueue {
protected void dispatchEvent(AWTEvent event) {
super.dispatchEvent(event);
}
}
}
MainFrame.java:
package my.example;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
public class MainFrame extends WindowAdapter {
private JFrame frame;
public MainFrame() {
frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(new Dimension(200, 200));
JPanel panel = new JPanel();
JButton button = new JButton("BREAK THIS");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
breakThis();
}
});
panel.add(button);
frame.setContentPane(panel);
}
public void breakThis() {
throw new RuntimeException("EXCEPTION OF CLICK");
}
public void open() {
this.frame.setVisible(true);
}
}
Related
Recently I was doing multithreaded chat application. Now I am struggling with server. I am trying to stop the server by introducing new field online, but it doesn't help.
import view.ChatHub;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Array;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Set;
import java.util.HashSet;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ChatServer extends Thread {
// All client names, so we can check for duplicates upon registration.
private static Set<String> names = new HashSet<>();
// The set of all the print writers for all the clients, used for broadcast.
private static Set<PrintWriter> writers = new HashSet<>();
private ChatHub frame;
private int port;
private boolean online;
private ExecutorService pool;
public ChatServer(int port) throws IOException {
System.out.println("The chat server is running...");
this.frame = new ChatHub(this);
this.port = port;
this.online = true;
this.pool = Executors.newFixedThreadPool(500);
this.start();
}
#Override
public void run() {
while (this.online) {
try (ServerSocket listener = new ServerSocket(this.port)) {
this.pool.execute(new Handler(listener.accept(), this.names, this.writers));
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void stopChatServer() {
this.pool.shutdown();
this.online = false;
}
public Set<String> getNames() {
return this.names;
}
public Set<PrintWriter> getWriters() {
return this.getWriters();
}
public ChatHub getFrame() {
return this.frame;
}
public int getPort() {
return this.port;
}
}
Here I am trying to close the server:
import Client.ChatClient;
import Server.ChatServer;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class ChatHub extends JFrame{
JTextField textField;
JTextArea messageArea;
public ChatHub(ChatServer server) {
new JFrame("Chatter");
this.textField = new JTextField(50);
this.messageArea = new JTextArea(16,50);
this.textField.setEditable(true);
this.messageArea.setEditable(false);
this.getContentPane().add(this.textField, BorderLayout.SOUTH);
this.getContentPane().add(new JScrollPane(this.messageArea), BorderLayout.CENTER);
this.pack();
// this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
server.stopChatServer();
}
});
this.setVisible(true);
}
public void appendMessage(String line) {
messageArea.append(line + "\n");
}
public JTextField getTextField() {
return this.textField;
}
public JTextArea getMessageArea() {
return this.messageArea;
}
public void nameAccepted(String line) {
this.setTitle("Chatter - " + line.substring(13));
textField.setEditable(true);
}
}
Also I tried to have method run with while just printing some String. But when it left run method the program was still working. Any suggestions? Thanks in advance.
Also I tried to implement run() as the following:
#Override
public void run() {
while (this.online) {
System.out.println("Some String");
}
System.out.println(this.isAlive() + "\n");
}
And it does output true in the end.
Maybe you have another problem here (Swing Related):
Your new JFrame("Chatter") just creates a new JFrame and does nothing with it. You have to call super("Chatter"); to call the super constructor
Try
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE)
Have you tried to declare your online property as volatile?
private volatile boolean online = true;
If you do not declare a property as volatile, the JIT compiler can assume that your boolean property will not be changed by another thread. So it may optimize your run method to
public void run() {
if (!online)
return;
while(true) {
try(/*...*/) {
// ...
} catch(/*...*/) {
// ...
}
}
}
I have a method showMessage() that appends a string onto a JTextArea and i want to call it in my "class in the class" (ServerThread). How can i accomplish this without having Main main; or Main main = new Main();
public class Main extends JFrame {
private static final long serialVersionUID = 1L;
private JTextArea chatWindow;
private List<Integer> ports = new ArrayList<Integer>();
public Main() throws IOException {
super("ServerConsole");
chatWindow = new JTextArea();
chatWindow.setEditable(false);
JScrollPane scrollPane = new JScrollPane(chatWindow);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setBounds(0, 20, 596, 200);
add(scrollPane);
setLayout(null);
setSize(600, 300);
setResizable(false);
setVisible(true);
getContentPane().setBackground(Color.white);
Socket s = null;
ServerSocket ss2 = null;
showMessage("Server Listening......\n");
try {
ss2 = new ServerSocket(3175);
} catch (IOException e) {
e.printStackTrace();
showMessage("Server error");
}
while (true) {
try {
s = ss2.accept();
showMessage("connection Established\n");
ports.add(s.getPort());
ServerThread st = new ServerThread(s);
st.start();
}
catch (Exception e) {
e.printStackTrace();
showMessage("Connection Error");
}
}
}
public void showMessage(final String m) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
chatWindow.append(m);
}
});
}
}
class ServerThread extends Thread {
private ObjectOutputStream output;
private ObjectInputStream input;
Socket s = null;
private static LinkedHashMap<Integer, String> playerCoords = new LinkedHashMap<Integer, String>();
public ServerThread(Socket s) {
this.s = s;
}
public void run() {
}
}
Example: in the run method i want to have something like main.showMessage(string) without having a Main object declared.
Just declare your method as static
public static void showMessage(final String m)
That way, you can call it like this -
Main.showMessage("Some String");
declare both showMessage method and chatWindow field static. Then you can call as Main.showMessage("whatever") where you want.
But a more elegant solution will be communicating these two singletons over listeners.
Declare an interface MessageListener with a method say onMessage(String message)
interface MessageListener {
public void onMessage(String message);
}
in ServerThread keep a list of MessageListeners and in run method invoke them
class ServerThread extends Thread {
// class content
static List<MessageListener> messageListeners = new ArrayList<>();
public void run() {
for (MessageListener messageListener : messageListeners) {
messageListener.onMessage("the message");
}
}
}
then make your Main class implementing MessageListener and in onMessage method call showMessage, also do not forget to register ServerThreads listener registry
public class Main extends JFrame implements MessageListener {
// class content
public Main() throws IOException {
super("ServerConsole");
ServerThread.messageListeners.add(this);
// other content
}
// class content
#Override
public void onMessage(String message) {
showMessage(message);
}
}
that's all. then the whole code looks like:
import java.awt.Color;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
public class Main extends JFrame implements MessageListener {
private static final long serialVersionUID = 1L;
private JTextArea chatWindow;
private List<Integer> ports = new ArrayList<Integer>();
public Main() throws IOException {
super("ServerConsole");
ServerThread.messageListeners.add(this);
chatWindow = new JTextArea();
chatWindow.setEditable(false);
JScrollPane scrollPane = new JScrollPane(chatWindow);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setBounds(0, 20, 596, 200);
add(scrollPane);
setLayout(null);
setSize(600, 300);
setResizable(false);
setVisible(true);
getContentPane().setBackground(Color.white);
Socket s = null;
ServerSocket ss2 = null;
showMessage("Server Listening......\n");
try {
ss2 = new ServerSocket(3175);
} catch (IOException e) {
e.printStackTrace();
showMessage("Server error");
}
while (true) {
try {
s = ss2.accept();
showMessage("connection Established\n");
ports.add(s.getPort());
ServerThread st = new ServerThread(s);
st.start();
}
catch (Exception e) {
e.printStackTrace();
showMessage("Connection Error");
}
}
}
public void showMessage(final String m) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
chatWindow.append(m);
}
});
}
#Override
public void onMessage(String message) {
showMessage(message);
}
}
interface MessageListener {
public void onMessage(String message);
}
class ServerThread extends Thread {
private ObjectOutputStream output;
private ObjectInputStream input;
Socket s = null;
private static LinkedHashMap<Integer, String> playerCoords = new LinkedHashMap<Integer, String>();
static List<MessageListener> messageListeners = new ArrayList<>();
public ServerThread(Socket s) {
this.s = s;
}
public void run() {
for (MessageListener messageListener : messageListeners) {
messageListener.onMessage("the message");
}
}
}
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.
I instantiated a button of my class like so:
linkBtn = new LinkButton(
new URI("http://www.example.com"),
"Click me");
Nothing happens when I click it, so I want to add an action listener something like this:
linkBtn.addActionListener(SOMETHING);
I tried things like this:
linkBtn.addActionListener(new LinkButton.OpenUrlAction());
That gives the following error:
an enclosing instance that contains LinkButton.OpenUrlAction is
required
I haven't found the right syntax yet.
Here's my class that extends JButton:
import java.awt.Desktop;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.URI;
import javax.swing.JButton;
public class LinkButton extends JButton
implements ActionListener {
/** The target or href of this link. */
private URI target;
final static private String defaultText = "<HTML>Click the <FONT color=\"#000099\"><U>link</U></FONT>"
+ " to go to the website.</HTML>";
public LinkButton(URI target, String text) {
super(text);
this.target = target;
//this.setText(text);
this.setToolTipText(target.toString());
}
public LinkButton(URI target) {
this( target, target.toString() );
}
public void actionPerformed(ActionEvent e) {
open(target);
}
class OpenUrlAction implements ActionListener {
#Override public void actionPerformed(ActionEvent e) {
open(target);
}
}
private static void open(URI uri) {
if (Desktop.isDesktopSupported()) {
try {
Desktop.getDesktop().browse(uri);
} catch (IOException e) { /* TODO: error handling */ }
} else { /* TODO: error handling */ }
}
}
I'm open to suggestions. I don't like my program structure either...
The answer's provided so far are all excellent.
Hovercraft has suggest the use of Actions, which would simply the structure of your code.
For example...
import java.awt.Desktop;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class LinkButtonExample {
public static void main(String[] args) {
new LinkButtonExample();
}
public LinkButtonExample() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
frame.add(new JButton(new OpenURLAction(new URL("http://stackoverflow.com/"))));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (MalformedURLException ex) {
ex.printStackTrace();
}
}
});
}
public class OpenURLAction extends AbstractAction {
private URL url;
public OpenURLAction(URL url) {
this("<HTML>Click the <FONT color=\\\"#000099\\\"><U>link</U></FONT> to go to the website.</HTML>", url);
}
public OpenURLAction(String text, URL url) {
putValue(NAME, text);
setURL(url);
}
public void setURL(URL url) {
this.url = url;
setEnabled(
url != null
&& Desktop.isDesktopSupported()
&& Desktop.getDesktop().isSupported(Desktop.Action.BROWSE));
putValue(SHORT_DESCRIPTION, url == null ? null : url.toString());
}
public URL getURL() {
return url;
}
#Override
public void actionPerformed(ActionEvent e) {
if (isEnabled()) {
URL url = getURL();
if (url != null && Desktop.isDesktopSupported()
&& Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
try {
Desktop.getDesktop().browse(url.toURI());
} catch ( IOException | URISyntaxException ex) {
ex.printStackTrace();
}
}
}
}
}
}
Check out How to use Actions for more details
You could do this:
linkBtn.addActionListener(linkBtn.new OpenUrlAction());
But your program structure makes me wince. Myself I'd try to get Actions separate from views. I also much prefer extension by composition rather than inheritance.
I don't understand why you extends a JButton but you can add by default this listener in constructor.
public LinkButton(URI target, String text) {
super(text);
this.target = target;
//this.setText(text);
this.setToolTipText(target.toString());
this.addActionListener(this);
//this.addActionListener(new OpenUrlAction());
}
Or you can do this.
linkBtn.addActionListener(linkBtn.new OpenUrlAction());
outerObject.new InnerClass()
Or you can modify your inner class with a constructor injection
class OpenUrlAction implements ActionListener{
private URI target;
OpenUrlAction(URI target){
this.target=target;
}
#Override
public void actionPerformed(ActionEvent evt){
open(this.target);
}
}
In client code:
`linkBtn.addActionListener(linkBtn.new OpenUrlAction(lninkBtn.getTarget)); // or the target that you want`
Here what I came up with so far. I added this method to my LinkButton class:
public void init() {
this.addActionListener(this);
}
Then I added this code to add the action listener:
linkBtnDonate.init();
It's working. I'm open to other suggestions.
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.