The problem is this:
I've a swing application running, at a certain point a dialog requires to insert username and password and to press "ok".
I would like that when the user press "ok" the swing application does in this order:
Open a "Please wait" JDialog
Make some operation(eventually displaying some other JDialog or JOptionPane)
When it finishes with the operation close the "please wait" JDialog
This is the code that I wrote in the okButtonActionPerformed():
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {
//This class simply extends a JDialog and contains an image and a jlabel (Please wait)
final WaitDialog waitDialog = new WaitDialog(new javax.swing.JFrame(), false);
waitDialog.setVisible(true);
... //Do some operation (eventually show other JDialogs or JOptionPanes)
waitDialog.dispose()
}
This code obviously doesn't works because when I call the waitDialog in the same thread it blocks all till I don't close it.
So I tried to run it in a different thread:
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {
//This class simply extends a JDialog and contains an image and a jlabel (Please wait)
final WaitDialog waitDialog = new WaitDialog(new javax.swing.JFrame(), false);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
waitDialog.setVisible(true);
}
});
... //Do some operation (eventually show other JDialogs or JOptionPanes)
waitDialog.dispose()
}
But also this doesn't work because the waitDialog is not displayed immediately but only after that the operation completed their work (when they show a joption pane "You are logged in as...")
I also tried to use invokeAndWait instead of invokeLater but in this case it throws an exception:
Exception in thread "AWT-EventQueue-0" java.lang.Error: Cannot call invokeAndWait from the event dispatcher thread
How can I do?
Consider using a SwingWorker to do your background work, and then closing the dialog either in the SwingWorker's done() method or (my preference) in a PropertyChangeListener that is added to the SwingWorker.
e.g.,
import java.awt.BorderLayout;
import java.awt.Dialog.ModalityType;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
public class PleaseWaitEg {
public static void main(String[] args) {
JButton showWaitBtn = new JButton(new ShowWaitAction("Show Wait Dialog"));
JPanel panel = new JPanel();
panel.add(showWaitBtn);
JFrame frame = new JFrame("Frame");
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class ShowWaitAction extends AbstractAction {
protected static final long SLEEP_TIME = 3 * 1000;
public ShowWaitAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent evt) {
SwingWorker<Void, Void> mySwingWorker = new SwingWorker<Void, Void>(){
#Override
protected Void doInBackground() throws Exception {
// mimic some long-running process here...
Thread.sleep(SLEEP_TIME);
return null;
}
};
Window win = SwingUtilities.getWindowAncestor((AbstractButton)evt.getSource());
final JDialog dialog = new JDialog(win, "Dialog", ModalityType.APPLICATION_MODAL);
mySwingWorker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("state")) {
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
dialog.dispose();
}
}
}
});
mySwingWorker.execute();
JProgressBar progressBar = new JProgressBar();
progressBar.setIndeterminate(true);
JPanel panel = new JPanel(new BorderLayout());
panel.add(progressBar, BorderLayout.CENTER);
panel.add(new JLabel("Please wait......."), BorderLayout.PAGE_START);
dialog.add(panel);
dialog.pack();
dialog.setLocationRelativeTo(win);
dialog.setVisible(true);
}
}
Notes:
A key concept is to set everything up, add the PropertyChangeListener, get the SwingWorker running, all before displaying the modal dialog, because once the modal dialog is shown, all code flow from the calling code is frozen (as you've found out).
Why do I prefer the PropertyChangeListener to using the done method (as Elias demonstrates in his decent answer here, which I've up-voted) -- using the listener provides more separation of concerns, looser coupling. This way the SwingWorker has to know nothing of the GUI code that is using it.
public void okButtonActionPerformed(ActionEvent e) {
final JDialog loading = new JDialog(parentComponent);
JPanel p1 = new JPanel(new BorderLayout());
p1.add(new JLabel("Please wait..."), BorderLayout.CENTER);
loading.setUndecorated(true);
loading.getContentPane().add(p1);
loading.pack();
loading.setLocationRelativeTo(parentComponent);
loading.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
loading.setModal(true);
SwingWorker<String, Void> worker = new SwingWorker<String, Void>() {
#Override
protected String doInBackground() throws InterruptedException
/** Execute some operation */
}
#Override
protected void done() {
loading.dispose();
}
};
worker.execute();
loading.setVisible(true);
try {
worker.get();
} catch (Exception e1) {
e1.printStackTrace();
}
}
A variation of the above answer
It's an easy and replicable way to do...
//This code goes inside your button action
DialogWait wait = new DialogWait();
SwingWorker<Void, Void> mySwingWorker = new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
//Here you put your long-running process...
wait.close();
return null;
}
};
mySwingWorker.execute();
wait.makeWait("Test", evt);
//end
//Create this class on your project
class DialogWait {
private JDialog dialog;
public void makeWait(String msg, ActionEvent evt) {
Window win = SwingUtilities.getWindowAncestor((AbstractButton) evt.getSource());
dialog = new JDialog(win, msg, Dialog.ModalityType.APPLICATION_MODAL);
JProgressBar progressBar = new JProgressBar();
progressBar.setIndeterminate(true);
JPanel panel = new JPanel(new BorderLayout());
panel.add(progressBar, BorderLayout.CENTER);
panel.add(new JLabel("Please wait......."), BorderLayout.PAGE_START);
dialog.add(panel);
dialog.pack();
dialog.setLocationRelativeTo(win);
dialog.setVisible(true);
}
public void close() {
dialog.dispose();
}
}
Related
I have a JFrame. in the JFrame is a JDesktopPane, JComboBox, several JLabels, and a JProgressBar. I am facing two challenges:
I want to update/change the text in one of the JLabels in the JFrame by clicking a JButton that is on a JInternalFrame (the button does some calculations).
Upon clicking a JButton that is on another JInternalFrame (the button performs a small task), I want to use the JProgressBar (progressbar is in JFrame) to show the progress of work done.
I use SwingUtilities.invokelater() to perform the tasks done by the buttons.
am using NetBeans as my IDE.
Hard to know what is happening without code, but probably the Event Dispatch Thread (EDT) is being blocked (or terminated?), e.g. by code being called by invokeLater. The EDT is used to update the GUI and should not be used for (slow) non-GUI related calculations. See tutorial The Event Dispatch Thread and subsequent for more details.
Example (without blocking):
import java.awt.*;
import java.awt.event.ActionEvent;
import java.time.LocalTime;
import javax.swing.*;
public class LabelProgress {
public static void main(String[] args) {
LabelProgress main = new LabelProgress();
SwingUtilities.invokeLater(() -> main.showInternal1());
SwingUtilities.invokeLater(() -> main.showInternal2());
}
private JFrame frame;
private JLabel label;
private JDesktopPane desktop;
private JProgressBar bar;
private int progress = 0;
private LabelProgress() {
label = new JLabel("Label: ");
desktop = new JDesktopPane();
bar = new JProgressBar(0, 100);
bar.setStringPainted(true);
frame = new JFrame();
frame.setLayout(new BorderLayout());
frame.add(label, BorderLayout.BEFORE_FIRST_LINE);
frame.add(desktop, BorderLayout.CENTER);
frame.add(bar, BorderLayout.AFTER_LAST_LINE);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setSize(600, 400);
frame.validate();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private void showInternal1() {
JButton change = new JButton("Change");
change.addActionListener(this::doChange);
JInternalFrame internal = new JInternalFrame("Change Label");
internal.setLayout(new FlowLayout());
internal.add(change);
internal.setBounds(20, 20, 200, 150);
internal.setVisible(true);
desktop.add(internal);
}
private void showInternal2() {
JButton task = new JButton("Task");
task.addActionListener(this::doTask);
JInternalFrame internal = new JInternalFrame("Small Task");
internal.setLayout(new FlowLayout());
internal.add(task);
internal.setBounds(150, 100, 200, 150);
internal.setVisible(true);
desktop.add(internal);
}
private void doChange(ActionEvent ev) {
// using a SwingWorker:
// for demonstration I used an anonymous class, maybe a own class is better
SwingWorker<LocalTime , Void> worker = new SwingWorker<LocalTime , Void>() {
#Override
protected LocalTime doInBackground() throws Exception {
// not executed on the EDT - just get the current time
LocalTime someCalculation = LocalTime.now();
return someCalculation;
}
#Override
protected void done() {
// executed on EDT
try {
LocalTime resultOfSomeCalculation = get();
label.setText("Label: " + resultOfSomeCalculation.toString());
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
worker.execute();
}
private void doTask(ActionEvent ev) {
// no need to use SwingWorker
Thread thread = new Thread(this::slowTask);
thread.start();
}
private void slowTask() {
// not really that slow, just for demonstration
progress += 10;
if (progress > 100) progress = 100;
// and now switching to the EDT
SwingUtilities.invokeLater(() -> bar.setValue(progress));
}
}
My application is created using Netbeans IDE (8.0.2).
I have created a JFrame which contains a JTable bound to a Database (using JPA).
I have added a "Refresh" button which is used to "refresh" the JTable data directly from the database.
I want a "Please wait" message to be displayed while data is being fetched.
For this I implemented a JDialog_PleaseWait class which extends JDialog.
For some strange reason, although the JDialog is shown the jLabel it includes does not show up...
The JDialog_PleaseWait class is :
public class JDialog_PleaseWait extends javax.swing.JDialog {
//constructor for PleaseWait jDialogs
public JDialog_PleaseWait(String messageToDisplay){
initComponents();
this.jLabel_WaitMessage.setText(messageToDisplay);
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jLabel_WaitMessage = new javax.swing.JLabel();
setTitle("Please wait...");
setAlwaysOnTop(true);
setBackground(new java.awt.Color(227, 248, 115));
setModalityType(java.awt.Dialog.ModalityType.MODELESS);
setResizable(false);
setType(java.awt.Window.Type.POPUP);
jLabel_WaitMessage.setBackground(new java.awt.Color(242, 253, 153));
jLabel_WaitMessage.setText("WaitMessage");
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jLabel_WaitMessage, javax.swing.GroupLayout.PREFERRED_SIZE, 271, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel_WaitMessage)
);
pack();
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel jLabel_WaitMessage;
// End of variables declaration//GEN-END:variables
}
The refresh JButton calls a method named "reload" which initially it must display the jDialog and perform the rest of its tasks afterwards.
More specifically :
public void reload(){
jTable_Activities.setEnabled(false); // freezes the JTable
JDialog_PleaseWait pleaseWaitDialog = new JDialog_PleaseWait("Communicating with database server...."); // create a new PleaseWait JDialog
pleaseWaitDialog.pack();
pleaseWaitDialog.setLocationRelativeTo(this); //relative to this frame
pleaseWaitDialog.setVisible(true); //display the JDialog
.... ....
// runs a DB query and updates a JTable
.... ....
So, for some reason the JDialog window pops up but the jLabel is not shown...
I(think I) have done the (exact?) same thing with other JDialogs which work fine but for some strange reason this JDialog does not work properly...
Any hint?
Your likely problem is that you're fetching your data on the Swing event thread (I don't see any code above where you use Thread/Runnable/SwingWorker or the like, and hence my assumption), and that this is tying up the event thread and preventing it from doing its chores -- including drawing the label to the JDialog. The solution: do the data fetching in a background thread such as by using a SwingWorker.
Here's an example that demonstrates what I mean. The code creates two JButtons, one which displays a JDialog for 2 seconds with a Thread.sleep(...) running on the Swing event thread during that 2 seconds, the other with the Thread.sleep(...) running in a background thread. Compile and run the code to see what happens.
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.Window;
import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class PleaseWaitDialogTest extends JPanel {
protected static final long SLEEP_TIME = 2000L;
public PleaseWaitDialogTest() {
add(new JButton(new ShowWaitDialog("Without Thread", KeyEvent.VK_O, false)));
add(new JButton(new ShowWaitDialog("With BG Thread", KeyEvent.VK_W, true)));
}
private class ShowWaitDialog extends AbstractAction {
private boolean useBackgroundThread;
private JDialog dialog;
public ShowWaitDialog(String name, int mnemonic,
boolean useBackgroundThread) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
this.useBackgroundThread = useBackgroundThread;
}
#Override
public void actionPerformed(ActionEvent e) {
// create dialog in a lazy way
if (dialog == null) {
Window ancestorWindow = SwingUtilities
.getWindowAncestor(PleaseWaitDialogTest.this);
String title = "Dialog: " + getValue(NAME);
dialog = new JDialog(ancestorWindow, title,
ModalityType.MODELESS);
dialog.getContentPane().setLayout(new GridBagLayout());
dialog.add(new JLabel("Please Wait"));
dialog.setPreferredSize(new Dimension(250, 150));
dialog.pack();
dialog.setLocationByPlatform(true);
}
dialog.setVisible(true);
// since the dialog is non-modal, this code will run immediately after
// the dialog has been set visible
CloseRunnable closeRunnable = new CloseRunnable(dialog, SLEEP_TIME);
if (useBackgroundThread) {
// run the Runnable in a background thread
new Thread(closeRunnable).start();
} else {
// run the Runnable directly on the Swing event thread
closeRunnable.run();
}
}
}
private class CloseRunnable implements Runnable {
protected JDialog dialog;
private long sleepTime;
public CloseRunnable(JDialog dialog, long sleepTime) {
this.dialog = dialog;
this.sleepTime = sleepTime;
}
#Override
public void run() {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
// the dialog *must* be closed on the Swing event thread
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (dialog != null) {
dialog.setVisible(false);
}
}
});
}
}
private static void createAndShowGui() {
PleaseWaitDialogTest mainPanel = new PleaseWaitDialogTest();
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_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();
}
});
}
}
Maybe I just don't know where to look or don't exactly understand how threads work, but I have two different JFrames (J1, J2). J1 is the main JFrame that has a drop down menu that will select J2. When this J2 becomes visible I need J1 to wait until J2's foobar value to become something other than -1. I have tried to skin this cat several different ways without success.
What I am trying right now...
// located in J1
J2 otherFrame = new J2();
....
private synchronized void getNum() {
try {
while (otherFrame.returnNum() == -1) wait();
}
catch (Exception e) {}
Long myResult = otherFrame.returnNum();
...
}
// located in J2
public synchronized Long returnNum() {
try {
while (someNum == -1) wait();
}
catch (Exception e) {}
notify();
return someNum;
}
I am sure this looks dumb, but I need J1 to wait until J2 has a value assigned to someNum. The value will be assigned when the user clicks submit. It isn't doing the job. What am I doing wrong here and (more importantly), if this is a thread thing, where is my concept of threads failing?
The solution is not to use a JFrame for your 2nd window but rather a modal dialog such as a modal JDialog. This is exactly what this type of top-level window was built for.
This issue is another reason why one should avoid writing Swing classes that extend JFrame, since doing so paints the coder into a corner and limits their options. Much better is to create classes that either extend or are built to create JPanels, since then the JPanel can be placed in a JFrame or modal JDialog if needed, or in another JPanel, or swapped in a CardLayout, or...
Note that use of a JDialog is very similar to that of a JFrame except for a few differences. You should pass into the dialog a reference to the calling window (here your first JFrame), and you should use the constructor that makes the dialog modal, but the API can help you with all of this.
When you make the modal window visible, the code flow in the calling code stops, and does not resume until the JDialog is no longer visible. At that time you can query the components of the JDialog for there state and use it in the calling code.
For example:
import java.awt.Window;
import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class DialogEg {
private static void createAndShowGui() {
// create JFrame for application
JFrame frame = new JFrame("Dialog Eg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MainPanel());
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 MainPanel extends JPanel {
private JTextField valueField = new JTextField(5);
public MainPanel() {
valueField.setFocusable(false); // so user can't interact with it
add(new JLabel("Value:"));
add(valueField);
add(new JButton(new GetValueAction("Get Value")));
}
private class GetValueAction extends AbstractAction {
private SecondPanel secondPanel = new SecondPanel();
public GetValueAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
// get JPanel's top level window
Window win = SwingUtilities.getWindowAncestor(MainPanel.this);
// create jdialog that is modal
JDialog dialog = new JDialog(win, "Get Value", ModalityType.APPLICATION_MODAL);
dialog.add(secondPanel);
// so the submit button will be activated when enter pressed:
dialog.getRootPane().setDefaultButton(secondPanel.getSubmitButton());
dialog.pack();
dialog.setLocationRelativeTo(win);
dialog.setVisible(true); // **** code flow stops here
// and resumes here once dialog is no longer visible
int value = secondPanel.getSpinnerValue();
valueField.setText("" + value);
}
}
}
#SuppressWarnings("serial")
class SecondPanel extends JPanel {
private SpinnerModel spinModel = new SpinnerNumberModel(-1, -1, 100, 1);
private JSpinner spinner = new JSpinner(spinModel);
private JButton submitButton = new JButton(new SubmitAction("Submit"));
public SecondPanel() {
add(spinner);
add(submitButton);
}
public int getSpinnerValue() {
return (Integer) spinner.getValue();
}
public JButton getSubmitButton() {
return submitButton;
}
private class SubmitAction extends AbstractAction {
public SubmitAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
int value = getSpinnerValue();
// get JPanel's top level window
Window win = SwingUtilities.getWindowAncestor(SecondPanel.this);
if (value < 0) {
String msg = "Submitted value must cannot be negative. Please try again";
JOptionPane.showMessageDialog(win, msg, "Invalid Entry", JOptionPane.ERROR_MESSAGE);
spinner.requestFocusInWindow(); // bring focus back to spinner
} else {
spinner.requestFocusInWindow();
win.dispose(); // get rid of dialog
}
}
}
}
I have an annoying issue with my desktop app that I am just unable to figure out. I have isolated the problem into the following example. What I am trying to do....
I have a jframe and 5 jpanels, each panel has a different picture. When launched, the user will see panel A with a button all inside my jframe. When the button is pressed I would like panel A to dissappear and panel B,C,D and E become visible after one another but each panel to be displayed for different lengths of time...
B visible for 3 secs, B invisible, C visible for 5 seconds, C invisible... and so on.
I have tried javax.Timer, Thread.sleep(3000) and even for statements and none seem to achieve what I want. How would you guys achieve this and what is the method I need to be looking at?
Thanks in advance.
Using a Swing Timer sounds like a reasonable approach. When the user clicks the JButton, show B and start the Timer, which should have an interval of 3 seconds. When the Timer fires, show C and change the Timer's interval to 5 seconds. When it fires again, show C and set the interval for however long you want to show C.
If that isn't working, please post an MCVE showing what you've tried, and we'll go from there.
Here I have done an example which shows:
How to use a Swing timer
How to add images on JLabel without freezing the program
Swapping the pics with the help of an timing array
After timer starts its starts changing :
My SSCCE:
/**
*
* #author rohan
*/
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class TestSwapPics {
public TestSwapPics() {
initComponents();
}
private void initComponents() {
JFrame f =new JFrame();
Panel = new javax.swing.JPanel();
Panel.setLayout(new BorderLayout(5,5));
jLabel1 = new javax.swing.JLabel();
jButton1 = new javax.swing.JButton();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
jLabel1.setIcon(new ImageIcon(getClass().getResource("/images.jpg")));
jButton1.setText("Start");
Panel.add(jLabel1, BorderLayout.NORTH);
Panel.add(jButton1, BorderLayout.SOUTH);
f.add(Panel);
f.pack();
f.setVisible(true);
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
startPicsChange();
}
private void startPicsChange() {
new Thread(new Runnable() {
#Override
public void run() {
Timer t = createAndStartTimer(timings[count],count);
while (t.isRunning()) {//wait for timer to be done
try {
Thread.sleep(1);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
count++;
if (count == timings.length) {
JOptionPane.showMessageDialog(null, "Done");
} else {
startPicsChange();
}
}
});
}
}).start();
}
private Timer createAndStartTimer(int delay, final int count) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
if(count==0)
jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/p3.PNG")));
if(count==1)
jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/p6.PNG")));
System.out.println("yes! reached here");
}
});
Timer t = new Timer(delay, new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
System.out.println("here 2!!");
}
});
t.setRepeats(false);
t.start();
return t;
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new TestSwapPics();
}
});
}
private JButton jButton1;
private JLabel jLabel1;
private JPanel Panel;
private int[] timings = {2000, 1000, 4000,5000,2000};
private int count=0;
}
I'm working on this program and I ran into another issue. I have a Jframe with a JLabel that I wish for it to change text from one thing to another. However, when I try to do that it doesnt show me the text changing, rather the last text I set it to.
How do I get my JLabel to cycle through text SLOWLY?
I'm trying a wait method to make the program go slowly so I can see if I can make it cycle through, but that doesnt seem to be working.
it would be helpful if someone could edit my code or make their own example of how to do this, THANKS!
public class CreditGraphics {
public String cardNum;
public JFrame frame;
public JPanel panel;
public JLabel label;
public JTextField text;
public CreditGraphics() {
synchronized(this){
try {
frame = new JFrame("HI");
panel = new JPanel();
label = new JLabel();
text = new JTextField(16);
panel.add(label);
panel.add(text);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.setPreferredSize(new Dimension(500, 500));
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
wait(4000);
label.setText("Hi");
wait(4000);
frame.revalidate();
frame.repaint();
label.setText("Hello");
frame.revalidate();
frame.repaint();
text.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cardNum = text.getText();
}
});
}
catch(InterruptedException e) {
e.printStackTrace();
}}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new CreditGraphics();
}
});
}
public void checkCard(){
}
}
As suggested by #trashgod use Swing Timer that is more suitable for swing application to perform a task once, after a delay or to perform a task repeatedly.
sample code:
private Timer timer;
...
label.setText("Hi");
// delay of 4 seconds
timer=new Timer(4000,new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
label.setText("Hello");
// timer.stop(); // stop the timer if repeated mode is on
}
});
timer.setRepeats(false); // you can turn-on it if needed
timer.start();
Note:
There is no need to call frame.repaint() and frame.revalidate() in this case.
Override getPreferredSize() to set the preferred size of the JPanel in case of custom painting.
sample code:
JPanel panel = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(..., ...);
}
};
read more...
Do not use Thread.sleep() or wait() as it will freeze your Swing application.
Instead you should use a javax.swing.Timer
See the Java tutorial How to Use Swing Timers and Lesson: Concurrency in Swing for more information and examples.