I've written a test program with making the jButton invisible and visible:
import java.awt.Dimension;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.event.*;
public class Blink
{
private JButton btn;
private static JFrame f;
public static void delay(int ms)
{
try
{
Thread.sleep(ms);
}
catch(InterruptedException ex)
{
Thread.currentThread().interrupt();
}
}
public Blink()
{
f = new JFrame("Blink");
f.setPreferredSize(new Dimension(500, 500));
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
btn = new JButton("Click me and I'll blink!");
f.add(btn);
btn.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
buttonClicked();
}
});
f.pack();
f.setVisible(true);
}
private void buttonClicked()
{
for (int i = 0; i < 5; i++)
{
delay(300);
btn.setVisible(false);
delay(300);
btn.setVisible(true);
}
}
public static void main(String[] args)
{
new Blink();
}
}
Unfortunately, the jButton does not blink. And when the buttonClicked() function is changed, so that the jButton is set invisible 5 times and is not set visible back, the jButton disappears only when the for-loop finishes. How to make the jButton disappear an reappear instantaneously?
You cannot use Thread.sleep method in Swing Thread (all listeners are called in Event Dispatcher Thread - EDT). To achieve blinking you must use javax.swing.Timer class. For more information look here and here
Here is your reworked example:
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Blink {
private JButton btn;
private JFrame f;
public void delay(int ms, boolean show) {
Timer timer = new Timer(ms, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
btn.setVisible(show);
btn.getParent().revalidate();
btn.getParent().repaint();
}
});
timer.setRepeats(false);
timer.start();
}
public Blink() {
f = new JFrame("Blink");
f.setPreferredSize(new Dimension(500, 500));
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
btn = new JButton("Click me and I'll blink!");
f.add(btn);
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
buttonClicked();
}
});
f.pack();
f.setVisible(true);
}
private void buttonClicked() {
for (int i = 1; i <= 10; i += 2) {
delay(300 * i, false);
delay(300 * (i + 1), true);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Blink();
}
});
}
}
For some complicated layouts, call setVisible(false) may have side-effects. In this case the CardLayout with your component and an empty panel should be used.
Here is the variant with CardLayout
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Blink {
private static final String BUTTON_CARD = "button";
private static final String EMPTY_CARD = "empty";
private JButton btn;
private JFrame f;
private final CardLayout cardLayout = new CardLayout();
public void delay(int ms, boolean show) {
Timer timer = new Timer(ms, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
cardLayout.show(btn.getParent(), show ? BUTTON_CARD : EMPTY_CARD);
btn.getParent().revalidate();
btn.getParent().repaint();
}
});
timer.setRepeats(false);
timer.start();
}
public Blink() {
f = new JFrame("Blink");
f.setPreferredSize(new Dimension(500, 500));
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(cardLayout);
btn = new JButton("Click me and I'll blink!");
f.add(btn, BUTTON_CARD);
f.add(new JPanel(), EMPTY_CARD);
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
buttonClicked();
}
});
f.pack();
f.setVisible(true);
}
private void buttonClicked() {
for (int i = 1; i <= 10; i += 2) {
delay(300 * i, false);
delay(300 * (i + 1), true);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Blink();
}
});
}
}
As #Sergiy points out - make sure you're running from the EDT, and don't sleep on the EDT, use a swing timer instead.
To make your jButton appear "invisbile", you can do something like this:
public void setInvisible(jButton jb) {
jb.setOpaque(false);
jb.setContentAreaFilled(false);
jb.setBorderPainted(false);
jb.setText("");
}
// Assuming you have the original text saved in a variable
public void setRevisible(jButton jb) {
jb.setOpaque(true);
jb.setContentAreaFilled(true);
jb.setBorderPainted(true);
jb.setText(originalString);
}
Depending on if you want the button to be clickable when it's invisible, you can also add btn.setEnabled(bool);
Related
I'm trying to move a robot represented by a JLabel into a GridLayout. The move is made but the display of the JLabel is only done for the final finishing square. I would like to see the move from box to box. I try to use javax.swing.Timer but it's not working.
import java.awt.Color;
import java.awt.Component;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.Serializable;
import java.util.Vector;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.LayoutStyle;
import javax.swing.Timer;
// Robot
public class Robot extends Case implements Serializable {
private ImageIcon imageRobot;
private Color couleur;
public Robot () {
imageRobot = new ImageIcon("./assets/balle.png");
setIcon(imageRobot);
}
public void seDeplacer (JPanel panel) {
Robot currentRoot = this;
int delay = 1000; //milliseconds
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
for (int i=0; i<5; i++) {
panel.remove(panel.getComponent(i));
panel.add(currentRoot, i);
panel.doLayout();
}
}
};
new Timer(delay, taskPerformer).start();
}
public void detruire () {
}
public void setCouleur (Color couleur) {
this.couleur=couleur;
}
public Color getCouleur () {
return this.couleur;
}
}
This block
public void seDeplacer (JPanel panel) {
Robot currentRoot = this;
int delay = 1000; //milliseconds
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
for (int i=0; i<5; i++) {
panel.remove(panel.getComponent(i));
panel.add(currentRoot, i);
panel.doLayout();
}
}
};
new Timer(delay, taskPerformer).start();
says literally "move my robot 5 times every second" thus robots moves 5 in blink of an eye every second.
What you wat is to move robot 1 time every second. To do that you need to introduce delay between robot moves.
You & the current commentators are over (or under - shrugs) thinking this. It is not necessary to add or remove components or change Z order to move the robot, just change the label text of the place moved from " " and the new label text to `"🤖".
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class MovingBot {
private JComponent ui = null;
String bot = new String(Character.toChars(129302));
Font font;
JLabel[] labels = new JLabel[100];
MovingBot() {
initUI();
}
public void initUI() {
if (ui!=null) return;
Font[] fonts = GraphicsEnvironment.
getLocalGraphicsEnvironment().getAllFonts();
for (Font font : fonts) {
if (font.canDisplay(129302)) {
this.font = font.deriveFont(20f);
}
}
ui = new JPanel(new GridLayout(0,20,2,2));
ui.setBorder(new EmptyBorder(4,4,4,4));
for (int ii=0; ii<labels.length; ii++) {
JLabel l = new JLabel(" ");
l.setFont(font);
ui.add(l);
labels[ii] = l;
}
labels[0].setText(bot);
ActionListener moveListener = new ActionListener() {
int count = 0;
#Override
public void actionPerformed(ActionEvent e) {
int indexLast = count%100;
labels[indexLast].setText(" ");
count++;
int indexCurrent = count%100;
labels[indexCurrent].setText(bot);
}
};
Timer timer = new Timer(50, moveListener);
timer.start();
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
MovingBot o = new MovingBot();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}
Hi I have the following code where I have a start and stop button . when start is pressed canvas starts painting but I cannot press stop button until the start operation is done . I need to stop and resume the paint on the button press . Once the start button is pressed the other buttons cannot be pressed till the canvas is painted.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Hashtable;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.Timer;
public abstract class JUIApp extends JPanel implements ActionListener {
public static CACanvas cacanvas= null;
public ArrayList<int[]> genL;
public JFrame frame = null;
protected JPanel mainPanel = null;
private JButton btn0 = null;
private JButton btn1 = null;
private JButton btn2 = null;
#SuppressWarnings("rawtypes")
DefaultComboBoxModel rules = null;
#SuppressWarnings("rawtypes")
JComboBox rulesCombo =null;
JScrollPane ruleListScrollPane=null;
JLabel lable=null;
JTextField generation=null;
JLabel gLable=null;
public static String Rule;
public static String Generations;
public boolean isChanged =false;
public int gridCellSize=4;
private static final long serialVersionUID = 1L;
public int genCurrent=0;
public int posCurrent=0;
public int i;
public Color cellColor= null;
public Timer waitTimer;
public static boolean waitFlag;
public static boolean alert1Flag=false;
public boolean stopFlag=false;
public JLabel Alert1=new JLabel();
public int genCheck=0;
//private List<Point> fillCells;
public JUIApp() {
initGUI();
}
public void initGUI() {
//fillCells = new ArrayList<>(25);
frame = new JFrame();
frame.setTitle("Cellular Automata Demo");
frame.setSize(1050, 610);
frame.setResizable(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(getMainPanel(),BorderLayout.NORTH);
frame.setVisible(true);
Toolkit.getDefaultToolkit().setDynamicLayout(false);
cacanvas=new CACanvas();
frame.add(cacanvas);
}
#SuppressWarnings({ "unchecked", "rawtypes" })
public JPanel getMainPanel() {
mainPanel = new JPanel();
mainPanel.setLayout(new FlowLayout());
//cacanvas=new CACanvas();
btn0 = new JButton("Start");
btn0.addActionListener(this);
//waitTimer = new Timer(1000, this);
mainPanel.add(btn0);
JButton btn2 = new JButton("Stop");
btn2.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent s)
{
stopFlag=true;
//cacanvas.repaint();
}
});
mainPanel.add(btn2);
btn1 = new JButton("Clear");
btn1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
CACanvas.clearFlag=true;
generation.setText("");
alert1Flag=true;
rulesCombo.setSelectedIndex(0);
Alert1.setText("Please enter the number of generations");
Alert1.setBounds(30, 20, 5, 5);
Alert1.setVisible(alert1Flag);
mainPanel.add(Alert1);
cacanvas.repaint();
frame.setSize(1060, 610);
}
});
mainPanel.add(btn1);
lable=new JLabel();
lable.setText("Select Rule :");
mainPanel.add(lable);
rules=new DefaultComboBoxModel();
for (int i=0;i<=100;i++)
{
String p=String.valueOf(i);
rules.addElement(p);
}
rules.addElement("250");
rules.addElement("254");
rulesCombo = new JComboBox(rules);
rulesCombo.setSelectedIndex(0);
ruleListScrollPane = new JScrollPane(rulesCombo);
mainPanel.add(ruleListScrollPane);
//mainPanel.revalidate();
gLable=new JLabel();
gLable.setText("Enter the number of Generations (Max 64)");
generation=new JTextField(2);
mainPanel.add(gLable);
mainPanel.add(generation);
// mainPanel.add(cacanvas);
return mainPanel;
}
public abstract void run();
#Override
public void actionPerformed(ActionEvent arg0) {
Alert1.setVisible(false);
waitFlag=false;
System.out.println("We received an ActionEvent " + arg0);
Generations=generation.getText();
System.out.println(Generations);
Rule = "";
if (rulesCombo.getSelectedIndex() != -1) {
Rule =
(String) rulesCombo.getItemAt
(rulesCombo.getSelectedIndex());
}
System.out.println(Rule);
int rule=Integer.parseInt(Rule);
Hashtable<String,Integer> rules= new Hashtable<String,Integer>();
CARule ruleClass=new CARule();
rules=ruleClass.setRule(rule);
CAGenetationSet sa =new CAGenetationSet(100, false,rules);
genL=new ArrayList<int[]>();
genL=sa.runSteps(Integer.parseInt(Generations));
System.out.println("calling pattern set");
for(int i=0;i<=genL.size()-1;i++)
{
System.out.println("Painting generation :"+i);
if(stopFlag==false)
{
cacanvas.repaint();
}
//genPaint();
//sleep();
int[] newCell=genL.get(i);
for(int r=0;r<newCell.length;r++)
{
if(newCell[r]==1)
{
System.out.println("Generaton is"+i+"CellLife is"+r);
cacanvas.fillCell(i,r);
}
}
}
/*cacanvas.patternSet(genL);
waitFlag=true;
System.out.println("run completed");
// cacanvas.clearFlag=true;
*/
}
public void genPaint()
{
cacanvas.repaint();
}
public void sleep()
{
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
public static void main(String[] args) {
JUIApp app = new JUIApp() {
#Override
public void run() {
// TODO Auto-generated method stub
System.out.println("Run method");
}
};
}
}
Seems like you are using the current Thread on that task, you should create another Thread and add one listeners code to the new Thread.
Here is my code:
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
public class wind extends JFrame implements ComponentListener, MouseListener
{
JButton button;
JLabel label;
public wind()
{
// initialise instance variables
setTitle("My First Window!");
setSize(400, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
JPanel content = new JPanel();
content.setLayout(new FlowLayout());
content.addComponentListener(this);
content.addMouseListener(this);
label = new JLabel("My First Window");
content.add(label);
label.addComponentListener(this);
button = new JButton("Click If You Wish To Live!");
button.addMouseListener(this);
content.add(button)
setContentPane(content);
}
public void componentHidden(ComponentEvent e){
try{wait(100);}
catch(InterruptedException error){}
button.setText("Hidden!");
}
public void componentShown(ComponentEvent e){
try{wait(100);}
catch(InterruptedException error){}
button.setText("Shown!");
}
public void componentResized(ComponentEvent e){
try{wait(100);}
catch(InterruptedException error){}
button.setText("Resized!");
}
public void componentMoved(ComponentEvent e){
try{wait(100);}
catch(InterruptedException error){}
button.setText("Moved!");
}
public void mouseExited(MouseEvent e){
try{wait(100);}
catch(InterruptedException error){}
label.setText("Exited!");
}
public void mouseEntered(MouseEvent e){
try{wait(100);}
catch(InterruptedException error){}
label.setText("Entered!");
}
public void mousePressed(MouseEvent e){
try{wait(100);}
catch(InterruptedException error){}
label.setText("pressed at: "+e.getX()+" "+e.getY());
}
public void mouseReleased(MouseEvent e){
try{wait(100);}
catch(InterruptedException error){}
label.setText("Released!");
label.setLocation(e.getX(), e.getY());
}
public void mouseClicked(MouseEvent e){}
}
It won't respond to the mouse or window re-sizing, hiding, or moving. Furthermore the button is not being displayed. fixed! I am just starting to learn about Java's JFrame and other graphics so I have no idea what's wrong with my code, although I suspect it has something to do with the way I made the button and added the listeners to the objects. Could someone please explain why it does this, and how to fix it. Thank you in advance!
Your problem is that you are using the wait function not correctly. Try to use the class javax.swing.Timer also known as a Swing Timer for delays in Swing programs, for simple animations and for repetitive actions. For more information see this example on stackoverflow: Java Wait Function
One possible way to add a ActionListener to a JButton:
// You are adding an ActionListener to the button
//Using the method addActionListener and a anonymous inner class
button.addActionListener(new ActionListener() {//anonymous inner class
#Override
public void actionPerformed(ActionEvent arg0)
{
button.setText("Text modified by an event called ActionEvent!");
}
});
I decided to play with similar code and came up with this bit of code that tries to show the state of things in a status bar at the bottom:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.AbstractAction;
import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
#SuppressWarnings({ "serial"})
// so the compiler won't complain
public class MyWindPanel extends JPanel {
private static final int PREF_W = 1200;
private static final int PREF_H = 600;
private static final String MOUSE_LOCATION = "Mouse Location [%04d, %04d]";
private static final String COMPONENT_STATE = "Component: %-15s";
private static final String TIMER_LABEL = "Elapsed Time: %02d:%02d:%02d:%03d";
private static final int TIMER_DELAY = 20;
private static final String MOUSE_STATE = "Mouse State: %-15s";
public static final String BUTTON_TEXT = "Set MyWindPanel %s";
private JLabel mouseLocation = new JLabel(
String.format(MOUSE_LOCATION, 0, 0));
private JLabel mouseState = new JLabel(String.format(MOUSE_STATE, ""));
private JLabel componentState = new JLabel(
String.format(COMPONENT_STATE, ""));
private JLabel timerLabel = new JLabel(
String.format(TIMER_LABEL, 0, 0, 0, 0));
private long startTime = System.currentTimeMillis();
private Action buttonAction = new MyButtonAction(String.format(BUTTON_TEXT, "Invisible"));
private JPanel statusPanel;
public MyWindPanel() {
setBackground(Color.pink);
Font font = new Font(Font.MONOSPACED, Font.BOLD, 14);
mouseLocation.setFont(font);
mouseState.setFont(font);
componentState.setFont(font);
timerLabel.setFont(font);
statusPanel = new JPanel();
statusPanel.setLayout(new BoxLayout(statusPanel, BoxLayout.LINE_AXIS));
statusPanel.add(mouseLocation);
statusPanel.add(Box.createHorizontalStrut(25));
statusPanel.add(mouseState);
statusPanel.add(Box.createHorizontalStrut(25));
statusPanel.add(componentState);
statusPanel.add(Box.createHorizontalStrut(25));
statusPanel.add(timerLabel);
new Timer(TIMER_DELAY, new TimerListener()).start();
MouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseMotionListener(myMouseAdapter);
addMouseListener(myMouseAdapter);
addComponentListener(new MyComponentListener());
setLayout(new BorderLayout());
// add(statusPanel, BorderLayout.PAGE_END);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public Action getButtonAction() {
return buttonAction;
}
public JComponent getStatusPanel() {
return statusPanel;
}
private class TimerListener implements ActionListener {
private static final int SECONDS_PER_MIN = 60;
private static final int MSEC_PER_SEC = 1000;
private static final int MIN_PER_HOUR = 60;
#Override
public void actionPerformed(ActionEvent evt) {
if (!MyWindPanel.this.isDisplayable()) {
((Timer) evt.getSource()).stop(); // so timer will stop when program
// over
}
long currentTime = System.currentTimeMillis();
long diff = currentTime - startTime;
int hours = (int) (diff / (MIN_PER_HOUR * SECONDS_PER_MIN * MSEC_PER_SEC));
int minutes = (int) (diff / (SECONDS_PER_MIN * MSEC_PER_SEC))
% MIN_PER_HOUR;
int seconds = (int) ((diff / MSEC_PER_SEC) % SECONDS_PER_MIN);
int mSec = (int) diff % MSEC_PER_SEC;
timerLabel.setText(String.format(TIMER_LABEL, hours, minutes, seconds,
mSec));
}
}
private class MyComponentListener extends ComponentAdapter {
#Override
public void componentHidden(ComponentEvent e) {
componentState.setText(String.format(COMPONENT_STATE, "Hidden"));
}
#Override
public void componentMoved(ComponentEvent e) {
componentState.setText(String.format(COMPONENT_STATE, "Moved"));
}
#Override
public void componentResized(ComponentEvent e) {
componentState.setText(String.format(COMPONENT_STATE, "Resized"));
}
#Override
public void componentShown(ComponentEvent e) {
componentState.setText(String.format(COMPONENT_STATE, "Shown"));
}
}
private class MyButtonAction extends AbstractAction {
public MyButtonAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
boolean visible = MyWindPanel.this.isVisible();
String text = visible ? "Visible" : "Invisible";
((AbstractButton) e.getSource()).setText(String.format(BUTTON_TEXT, text));
MyWindPanel.this.setVisible(!MyWindPanel.this.isVisible());
Window win = SwingUtilities.getWindowAncestor(MyWindPanel.this);
win.revalidate();
win.repaint();
}
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mouseMoved(MouseEvent e) {
mouseLocation.setText(String.format(MOUSE_LOCATION, e.getX(), e.getY()));
}
#Override
public void mouseDragged(MouseEvent e) {
mouseState.setText(String.format(MOUSE_STATE, "Dragged"));
mouseLocation.setText(String.format(MOUSE_LOCATION, e.getX(), e.getY()));
}
public void mousePressed(MouseEvent e) {
mouseState.setText(String.format(MOUSE_STATE, "Pressed"));
};
public void mouseReleased(MouseEvent e) {
mouseState.setText(String.format(MOUSE_STATE, "Released"));
};
public void mouseEntered(MouseEvent e) {
mouseState.setText(String.format(MOUSE_STATE, "Entered"));
};
public void mouseExited(MouseEvent e) {
mouseState.setText(String.format(MOUSE_STATE, "Exited"));
};
}
private static void createAndShowGui() {
MyWindPanel mainPanel = new MyWindPanel();
JPanel topPanel = new JPanel();
topPanel.add(new JButton(mainPanel.getButtonAction()));
JFrame frame = new JFrame("MyWind");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.getContentPane().add(topPanel, BorderLayout.PAGE_START);
frame.getContentPane().add(mainPanel.getStatusPanel(), BorderLayout.PAGE_END);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
How can I adjust this Timer code so that it executes four times and then stops?
timer = new Timer(1250, new java.awt.event.ActionListener() {
#Override
public void actionPerformed(java.awt.event.ActionEvent e) {
System.out.println("Say hello");
}
});
timer.start();
You could do:
Timer timercasovac = new Timer(1250, new ActionListener() {
private int counter;
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Say hello");
counter++;
if (counter == 4) {
((Timer)e.getSource()).stop();
}
}
});
timercasovac.start();
You need to count yourself and then stop the Timer manually:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class TestTimer {
private int count = 0;
private Timer timer;
private JLabel label;
private void initUI() {
JFrame frame = new JFrame("test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
label = new JLabel(String.valueOf(count));
frame.add(label);
frame.pack();
frame.setVisible(true);
timer = new Timer(1250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (count < 4) {
count++;
label.setText(String.valueOf(count));
} else {
timer.stop();
}
}
});
timer.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestTimer().initUI();
}
});
}
}
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);
}
}
});
}
}