I'm developing a Java Swing app for an award winning password protection system, and I need a large custom cursor [ 80 x 80 ], you might ask why so large, there is an online web demo you may look at to learn why it needs to be so large : http://gatecybertech.net
That large cursor is used on the login page in the above link. Of course you need to create a test password first before you can try the login process.
But anyway, in my Swing app, I hit a limit of 32 x 32 for the largest possible custom cursor, my code looks like the following :
Image cursorImage = toolkit.getImage("Cursor_Crosshair.PNG");
Tabular_Panel.setCursor(Toolkit.getDefaultToolkit().createCustomCursor(cursorImage,new Point(0,0),"custom cursor"));
The image size of Cursor_Crosshair.PNG is : 80 x 80
But what shows up in the screen is a shrinked version of it at : 32 x 32
So my question is : how can I bypass the size limit on customer cursor image, and make the cursor to show up at the size of 80 x 80 ?
I know the OS might be the reason for the limit, is there a way to overcome it ?
Here's my take on the glass pane painting approach. This is set up to behave pretty much like setting a custom cursor. The default "arrow" cursor is hidden while the custom cursor is shown, and the custom cursor is hidden when a component has some other cursor set, such as a text box.
Unfortunately, it ended up seeming to require quite a bit of Swing black magic, so I don't like it very much, but it does seem to work correctly. I've done a cursor like this before, but it was for something simpler, so I didn't run in to these issues.
Some of the problems I ran in to are:
The glass pane intercepts cursor changes (described e.g. on SO here). The only solution I've been able to find is to override Component.contains(int,int) to return false (described here, shown here), but why that works and doesn't seem to break anything else is mysterious.
Mouse exit events sometimes return a location inside the bounds of the component, so I don't think there's a reliable way to know when the mouse leaves the window except to use a timer.
package mcve;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.imageio.*;
import java.net.*;
import java.io.*;
public class LargeCursor {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame();
JPanel glass = new CustomGlassPane();
glass.add(new CursorPanel(), BorderLayout.CENTER);
frame.setGlassPane(glass);
// This next call is necessary because JFrame.setGlassPane delegates to the root pane:
// - https://docs.oracle.com/javase/9/docs/api/javax/swing/RootPaneContainer.html#setGlassPane-java.awt.Component-
// - http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/javax/swing/JFrame.java#l738
// And JRootPane.setGlassPane may call setVisible(false):
// - https://docs.oracle.com/javase/9/docs/api/javax/swing/JRootPane.html#setGlassPane-java.awt.Component-
// - http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/javax/swing/JRootPane.java#l663
glass.setVisible(true);
JPanel content = createTestPanel();
content.setCursor(BlankCursor.INSTANCE);
frame.setContentPane(content);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
});
}
static class CustomGlassPane extends JPanel {
CustomGlassPane() {
super(new BorderLayout());
super.setOpaque(false);
}
#Override
public boolean contains(int x, int y) {
return false;
}
}
static class CursorPanel extends JPanel {
final BufferedImage cursorImage;
Point mouseLocation;
CursorPanel() {
try {
cursorImage = createTransparentImage(
ImageIO.read(new URL("https://i.stack.imgur.com/9h2oI.png")));
} catch (IOException x) {
throw new UncheckedIOException(x);
}
setOpaque(false);
long mask = AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK;
Toolkit.getDefaultToolkit().addAWTEventListener((AWTEvent e) -> {
switch (e.getID()) {
case MouseEvent.MOUSE_ENTERED:
case MouseEvent.MOUSE_EXITED:
case MouseEvent.MOUSE_MOVED:
case MouseEvent.MOUSE_DRAGGED:
capturePoint((MouseEvent) e);
break;
}
}, mask);
// This turned out to be necessary, because
// the 'mouse exit' events don't always have
// a Point location which is outside the pane.
Timer timer = new Timer(100, (ActionEvent e) -> {
if (mouseLocation != null) {
Point p = MouseInfo.getPointerInfo().getLocation();
SwingUtilities.convertPointFromScreen(p, this);
if (!contains(p)) {
setMouseLocation(null);
}
}
});
timer.setRepeats(true);
timer.start();
}
void capturePoint(MouseEvent e) {
Component comp = e.getComponent();
Point onThis = SwingUtilities.convertPoint(comp, e.getPoint(), this);
boolean drawCursor = contains(onThis);
if (drawCursor) {
Window window = SwingUtilities.windowForComponent(this);
if (window instanceof JFrame) {
Container content = ((JFrame) window).getContentPane();
Point onContent = SwingUtilities.convertPoint(comp, e.getPoint(), content);
Component deepest = SwingUtilities.getDeepestComponentAt(content, onContent.x, onContent.y);
if (deepest != null) {
if (deepest.getCursor() != BlankCursor.INSTANCE) {
drawCursor = false;
}
}
}
}
setMouseLocation(drawCursor ? onThis : null);
}
void setMouseLocation(Point mouseLocation) {
this.mouseLocation = mouseLocation;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (mouseLocation != null) {
int x = mouseLocation.x - (cursorImage.getWidth() / 2);
int y = mouseLocation.y - (cursorImage.getHeight() / 2);
g.drawImage(cursorImage, x, y, this);
}
}
}
static final class BlankCursor {
static final Cursor INSTANCE =
Toolkit.getDefaultToolkit().createCustomCursor(
new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB),
new Point(),
"BLANK");
}
static JPanel createTestPanel() {
JPanel panel = new JPanel(new GridLayout(3, 3));
panel.setBorder(BorderFactory.createEmptyBorder(100, 100, 100, 100));
for (int i = 0; i < 9; ++i) {
if ((i % 2) == 0) {
JTextField field = new JTextField("Text Field");
field.setHorizontalAlignment(JTextField.CENTER);
panel.add(field);
} else {
panel.add(new JButton("Button"));
}
}
return panel;
}
static BufferedImage createTransparentImage(BufferedImage img) {
BufferedImage copy =
GraphicsEnvironment.getLocalGraphicsEnvironment()
.getDefaultScreenDevice()
.getDefaultConfiguration()
.createCompatibleImage(img.getWidth(),
img.getHeight(),
Transparency.TRANSLUCENT);
for (int x = 0; x < img.getWidth(); ++x) {
for (int y = 0; y < img.getHeight(); ++y) {
int rgb = img.getRGB(x, y) & 0x00FFFFFF;
int bright = (((rgb >> 16) & 0xFF) + ((rgb >> 8) & 0xFF) + (rgb & 0xFF)) / 3;
int alpha = 255 - bright;
copy.setRGB(x, y, (alpha << 24) | rgb);
}
}
return copy;
}
}
OK, after some research and modification, I found the answer :
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.event.MouseInputAdapter;
public class Demo_Large_Custom_Cursor
{
static private MyGlassPane myGlassPane;
// Create the GUI and show it. For thread safety, this method should be invoked from the event-dispatching thread.
private static void createAndShowGUI()
{
//Create and set up the window.
JFrame frame=new JFrame("Demo_Large_Custom_Cursor");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Start creating and adding components.
JCheckBox changeButton=new JCheckBox("Custom Cursor \"visible\"");
changeButton.setSelected(false);
//Set up the content pane, where the "main GUI" lives.
Container contentPane=frame.getContentPane();
contentPane.setLayout(new FlowLayout());
contentPane.add(changeButton);
JButton Button_1=new JButton("<Html><Table Cellpadding=7><Tr><Td>A</Td><Td>B</Td></Tr><Tr><Td>C</Td><Td>D</Td></Tr></Table></Html>");
Button_1.setPreferredSize(new Dimension(80,80));
Button_1.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { Out("Button 1"); } });
contentPane.add(Button_1);
JButton Button_2=new JButton("<Html><Table Cellpadding=7><Tr><Td>1</Td><Td>2</Td></Tr><Tr><Td>3</Td><Td>4</Td></Tr></Table></Html>");
Button_2.setPreferredSize(new Dimension(80,80));
Button_2.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { Out("Button 2"); } });
contentPane.add(Button_2);
//Set up the menu bar, which appears above the content pane.
JMenuBar menuBar=new JMenuBar();
JMenu menu=new JMenu("Menu");
menu.add(new JMenuItem("Do nothing"));
menuBar.add(menu);
frame.setJMenuBar(menuBar);
//Set up the glass pane, which appears over both menu bar
//and content pane and is an item listener on the change
//button.
myGlassPane=new MyGlassPane(changeButton,menuBar,frame.getContentPane());
changeButton.addItemListener(myGlassPane);
frame.setGlassPane(myGlassPane);
//Show the window.
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
private static void out(String message) { System.out.print(message); }
private static void Out(String message) { System.out.println(message); }
public static void main(String[] args)
{
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
/**
We have to provide our own glass pane so that it can paint.
*/
class MyGlassPane extends JComponent implements ItemListener
{
Point point;
//React to change button clicks.
public void itemStateChanged(ItemEvent e)
{
setVisible(e.getStateChange()==ItemEvent.SELECTED);
}
protected void paintComponent(Graphics g)
{
try
{
if (point!=null)
{
// g.setColor(Color.red);
// g.fillOval(point.x-10,point.y-10,20,20);
BufferedImage image=ImageIO.read(new File("C:/Cursor_Crosshair.PNG"));
g.drawImage(image,point.x-39,point.y-39,null);
}
}
catch (Exception e) { }
}
public void setPoint(Point p)
{
point=p;
}
public MyGlassPane(AbstractButton aButton,JMenuBar menuBar,Container contentPane)
{
CBListener listener=new CBListener(aButton,menuBar,this,contentPane);
addMouseListener(listener);
addMouseMotionListener(listener);
}
}
/**
Listen for all events that our check box is likely to be interested in. Redispatch them to the check box.
*/
class CBListener extends MouseInputAdapter
{
Toolkit toolkit;
Component liveButton;
JMenuBar menuBar;
MyGlassPane glassPane;
Container contentPane;
public CBListener(Component liveButton,JMenuBar menuBar,MyGlassPane glassPane,Container contentPane)
{
toolkit=Toolkit.getDefaultToolkit();
this.liveButton=liveButton;
this.menuBar=menuBar;
this.glassPane=glassPane;
this.contentPane=contentPane;
}
public void mouseMoved(MouseEvent e)
{
// redispatchMouseEvent(e,false);
redispatchMouseEvent(e,true);
}
public void mouseDragged(MouseEvent e)
{
redispatchMouseEvent(e,false);
}
public void mouseClicked(MouseEvent e)
{
redispatchMouseEvent(e,false);
}
public void mouseEntered(MouseEvent e)
{
redispatchMouseEvent(e,false);
}
public void mouseExited(MouseEvent e)
{
redispatchMouseEvent(e,false);
}
public void mousePressed(MouseEvent e)
{
redispatchMouseEvent(e,false);
}
public void mouseReleased(MouseEvent e)
{
redispatchMouseEvent(e,true);
}
//A basic implementation of redispatching events.
private void redispatchMouseEvent(MouseEvent e,boolean repaint)
{
Point glassPanePoint=e.getPoint();
Container container=contentPane;
Point containerPoint=SwingUtilities.convertPoint(glassPane,glassPanePoint,contentPane);
if (containerPoint.y<0)
{ //we're not in the content pane
if (containerPoint.y+menuBar.getHeight()>=0)
{
//The mouse event is over the menu bar.
//Could handle specially.
}
else
{
//The mouse event is over non-system window
//decorations, such as the ones provided by
//the Java look and feel.
//Could handle specially.
}
}
else
{
//The mouse event is probably over the content pane.
//Find out exactly which component it's over.
Component component=SwingUtilities.getDeepestComponentAt(container,containerPoint.x,containerPoint.y);
// if ((component!=null) && (component.equals(liveButton)))
if ((component!=null))
{
//Forward events over the check box.
Point componentPoint=SwingUtilities.convertPoint(glassPane,glassPanePoint,component);
component.dispatchEvent(new MouseEvent(component,e.getID(),e.getWhen(),e.getModifiers(),componentPoint.x,componentPoint.y,e.getClickCount(),e.isPopupTrigger()));
}
}
//Update the glass pane if requested.
if (repaint)
{
glassPane.setPoint(glassPanePoint);
glassPane.repaint();
}
}
}
And the Cursor_Crosshair.PNG is like this :
I am trying to write application which will create new window when pressing button, show current window count and close window and thread on closing the window.
So basically, functionality is like this (and some of them are working):
Show window on launching application (OK)
Create new window on pressing button (OK)
Display current window count on pressing button (OK on creating, NOK on closing windows)
Destroy window when pressed "X" (OK)
Destroy main thread when original window is closed (NOK)
Here is my code:
package projectpackage;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JOptionPane;
import java.awt.*;
import java.awt.event.*;
class MyMouseEvent extends MouseAdapter
{
public void mousePressed(MouseEvent me)
{
MyWindowThread.incrementMyWindowThreadCount();
MyWindowThread obj1 = new MyWindowThread();
Thread thr1 = new Thread(obj1);
thr1.start();
}
}
class MyWindowThread extends JFrame implements Runnable
{
private int height;
private int width;
private static int MyWindowThreadCount = 1;
public static int getMyWindowThreadCount()
{
return MyWindowThreadCount;
}
public static void incrementMyWindowThreadCount()
{
MyWindowThreadCount++;
}
public static void decrementMyWindowThreadCount()
{
MyWindowThreadCount--;
}
public MyWindowThread()
{
super("Frame "+getMyWindowThreadCount());
this.setHeight(300);
this.setWidth(400);
this.setBounds(100,100,getWidth(),getHeight());
this.addWindowListener(new WindowAdapter()
{
#Override
public void windowClosing(WindowEvent e)
{
MyWindowThread.decrementMyWindowThreadCount();
//Thread.currentThread().interrupt();
return;
}
}
);
JPanel panel1 = new JPanel();
JButton button1 = new JButton("New window");
JButton button2 = new JButton("Count running windows");
this.getContentPane().add(panel1);
panel1.add(button1);
panel1.add(button2);
button1.addMouseListener(new MyMouseEvent());
button2.addMouseListener(new MouseAdapter()
{
public void mousePressed(MouseEvent me)
{
javax.swing.JOptionPane.showMessageDialog(null,"Window count = " + MyWindowThread.getMyWindowThreadCount());
}
}
);
this.setVisible(true); // show frame
}
public int getHeight()
{
return this.height;
}
public void setHeight(int h)
{
this.height = h;
}
public int getWidth()
{
return this.width;
}
public void setWidth(int w)
{
this.width = w;
}
public void run()
{
}
}
public class MyApp
{
public static void main(String[] args)
{
// Creating objects START
MyWindowThread obj1 = new MyWindowThread();
Thread thr1 = new Thread(obj1);
thr1.start();
}
}
manifest.mf:
Manifest-Version: 1.0
Main-Class: projectpackage.MyApp
I hope you know how to compile and run Java application in console. In case you don't, here it is:
(navigate in CLI to directory with "projectpackage" directory inside. *.java file must be inside "projectpackage" directory)
javac projectpackage\*.java
jar cfm MyApp.jar manifest.mf projectpackage\*
java -jar MyApp.jar
Can anyone enlighten me what am I doing wrong or just what I need to do to make the code work? Or am I just having fundamental misconception?
JFrame frame = new JFrame();
This is your problem, you extend the JFrame-class but try to use a new object.
You should replace this line by super(); or super("Frame " + getMyThreadCount()); if you want so.
Edit: Another issue to mention: you named your class MyThread, this is a quite irritating class-name for a window ;)
Edit 2: Few other things:
public void run() has no content, so why does MyThread implement Runnable?
You create some threads, but if I got that right, you do not start any of them.
If you simply want your application to exit when the JFrame is closed, then you are going about this all wrong. Get rid of all the Thread objects and Runnables. Swing applications run in the event dispatch thread (EDT). You should only use background threads if you need to do something like disk or network I/O.
Create/show the JFrame in the EDT. If you set the default close operation on the JFrame to DISPOSE_ON_CLOSE, then when all of the windows have been closed, the main thread will terminate normally.
public class MyApp {
public static void main( String[] args ) {
EventQueue.invokeLater( new Runnable() {
public void run() {
MyWindow w = new MyWindow();
w.setVisible( true );
}
} );
}
private static class MyWindow extends JFrame {
// Simplified reference counting
private static AtomicInteger frameCount = new AtomicInteger( 0 );
public MyWindow() {
super("Frame " + frameCount.incrementAndGet() );
this.setSize( 400, 300 );
this.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
JButton button = new JButton("New Window");
button.addActionListener( new ActionListener() {
#Override
public void actionPerformed( ActionEvent e ) {
MyWindow w = new MyWindow();
w.setVisible( true );
}
} );
this.getContentPane().add( button );
// ignore reference count button for now
}
}
}
This question already has answers here:
Make splash screen with progress bar like Eclipse
(2 answers)
Closed 9 years ago.
i get this source code for creating splash screen and thread management in Java. But i don't know how to implement it.
public class SplashWindow extends JWindow {
public SplashWindow(String filename, Frame f, int waitTime)
{
super(f);
JLabel l = new JLabel(new ImageIcon(filename));
getContentPane().add(l, BorderLayout.CENTER);
pack();
Dimension screenSize =
Toolkit.getDefaultToolkit().getScreenSize();
Dimension labelSize = l.getPreferredSize();
setLocation(screenSize.width/2 - (labelSize.width/2),
screenSize.height/2 - (labelSize.height/2));
addMouseListener(new MouseAdapter()
{
public void mousePressed(MouseEvent e)
{
setVisible(false);
dispose();
}
});
final int pause = waitTime;
final Runnable closerRunner = new Runnable()
{
public void run()
{
setVisible(false);
dispose();
}
};
Runnable waitRunner = new Runnable()
{
public void run()
{
try
{
Thread.sleep(pause);
SwingUtilities.invokeAndWait(closerRunner);
}
catch(Exception e)
{
e.printStackTrace();
// can catch InvocationTargetException
// can catch InterruptedException
}
}
};
setVisible(true);
Thread splashThread = new Thread(waitRunner, "SplashThread");
splashThread.start();
}
}
I try to implement like this :
...
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(500, 500);
SplashWindow window = new SplashWindow("splash-scren.jpg", frame, 1000);
}
...
But nothing to show.
Please help me, thank you :)
Dont put :
"setVisible(true);"
In the constructor , after
SplashWindow window = new SplashWindow("splash-scren.jpg", frame, 1000);
write:
window.setVisible(true);
I am creating a simple console application in which I can use keyboard arrow keys as an input like a typical remote of a toy. When I press arrow up the console will print the output text "UP" or if I press arrow down it will print "down".
I want to press the arrow key only once, i.e. I am not needed to press enter afterwards to accept my input. I want the input to be accepted automatically on pressing the arrow key.
I already tried some code but this is still not happening and I still need to press enter to accept my input. If you have any idea how I can achieve this as simple as possible, I would really appreciate it.
This sample code will helps you to get the Left Arrow Key Event. You can refer this,
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class Test2 extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final int TIMER_DELAY = 50;
private Timer leftKeyTimer = new Timer(TIMER_DELAY , new TimerListener());
public Test2() {
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition );
ActionMap actionMap = getActionMap();
String leftDownKey = "Left Down";
String leftUpKey = "Left Up";
KeyStroke leftDown = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT , 0, false);
KeyStroke leftUp = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT , 0, true);
inputMap.put(leftDown, leftDownKey);
inputMap.put(leftUp, leftUpKey);
actionMap.put(leftDownKey, new LeftKeyAction(false));
actionMap.put(leftUpKey, new LeftKeyAction(true));
leftKeyTimer.setActionCommand("Left Key");
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private class LeftKeyAction extends AbstractAction {
private boolean onKeyRelease;
public LeftKeyAction(boolean onKeyRelease) {
this.onKeyRelease = onKeyRelease;
}
#Override
public void actionPerformed(ActionEvent e) {
if (onKeyRelease) {
if (leftKeyTimer != null && leftKeyTimer.isRunning()) {
leftKeyTimer.stop();
}
} else {
if (leftKeyTimer != null && !leftKeyTimer.isRunning()) {
leftKeyTimer.start();
}
}
}
}
private class TimerListener implements ActionListener {
public void actionPerformed(ActionEvent actEvt) {
System.out.println(actEvt.getActionCommand());
}
}
private static void createAndShowGui() {
Test2 mainPanel = new Test2();
JFrame frame = new JFrame("Test2");
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();
}
});
}
}
This is actually a surprisingly complicated problem.
If you want a true console app (no GUI elements) you have to sacrifice portability.
Most consoles are line buffered by default, so Java won't get any input until enter is pressed. Most can be switched to a character mode, but there is no OS independent way to do this. For more information see http://www.darkcoding.net/software/non-blocking-console-io-is-not-possible/
i want to show modal dialog, which will block my main window and i want to control it from outside by methods showLoadingDialog(), hideLoadingDialog() and setLoadingMessage(String message) - i tried this code, but its not working - Loading dialog is visible, but without message
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class LoadingExample {
private static class LoadingDialog extends JDialog {
private JLabel label = new JLabel("working");
public LoadingDialog(JFrame owner) {
super(owner, ModalityType.APPLICATION_MODAL);
setUndecorated(true);
add(label);
pack();
// move window to center of owner
int x = owner.getX()
+ (owner.getWidth() - getPreferredSize().width) / 2;
int y = owner.getY()
+ (owner.getHeight() - getPreferredSize().height) / 2;
setLocation(x, y);
repaint();
}
public void setMessage(String message) {
label.setText(message);
}
}
private static LoadingDialog loadingDialog;
public static void main(String[] args) {
final JFrame mainWindow = new JFrame("Main frame");
mainWindow.setLayout(new GridLayout(3, 3));
for (int i = 1; i <= 9; i++) {
final int workTime = i;
JButton workButton = new JButton("work for " + i + " second");
//action listener, which had to show loading dialog and countdown seconds before finish
workButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
showLoadingDialog(mainWindow);
for (int j = 0; j < workTime; j++)
try {
// ... do some work here
setLoadingMessage("remain " + (workTime - j)
+ " second(s)");
loadingDialog.repaint();
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
hideLoadingDialog();
}
});
mainWindow.add(workButton);
}
mainWindow.pack();
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWindow.setLocationRelativeTo(null);
mainWindow.setVisible(true);
}
public static void showLoadingDialog(JFrame owner) {
if (loadingDialog != null)
loadingDialog.dispose();
loadingDialog = new LoadingDialog(owner);
new Thread() {
#Override
public void run() {
loadingDialog.setVisible(true);
};
}.start();
}
public static void setLoadingMessage(String message) {
loadingDialog.setMessage(message);
}
public static void hideLoadingDialog() {
if (loadingDialog != null) {
loadingDialog.setVisible(false);
loadingDialog.dispose();
loadingDialog = null;
}
}
}
thanks for any suggestions
You cannot make changes to the GUI from a different thread than the dispatcher thread associated to the control you are trying to change. To do this correctly you can use SwingUtilities.InvokeLater:
new Thread() {
#Override
public void run() {
SwingUtilities.InvokeLater(new Runnable() {
public void run() {
loadingDialog.setVisible(true);
}
});
};
}.start();
I wanted to write some sample code, but before firing up my IDE I did a small search in the excellent Swing concurrency tutorial and behold, it contains exactly the sample code you are looking for. What you have is a 'task that has interim results'. So when you have intermediate results, you call the SwingWorker#publish method. In the SwingWorker#process method, you update the modal dialog with the new message you just published. The SwingWorker#done method allows you to remove the modal dialog afterwards.
But I suggest you read that whole concurrency tutorial from start to finish as your sample code shows you lack some basic Swing threading knowledge.