I would like to make my JToolBar impossible to detach from its container but still let the user drag it to one of the container's sides.
I know about
public void setFloatable( boolean b )
but this won't allow the user to move the JToolBar at all.
Is there any way of doing this without overwriting ToolBarUI?
Also, is there an option to highlight its new position before dropping it?
It's not the most elegant solution, but it works.
public class Example extends JFrame {
BasicToolBarUI ui;
Example() {
JToolBar tb = new JToolBar();
tb.add(new JButton("AAAAA"));
tb.setBackground(Color.GREEN);
ui = (BasicToolBarUI) tb.getUI();
getContentPane().addContainerListener(new Listener());
getContentPane().add(tb, BorderLayout.PAGE_START);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(300, 300);
setLocationRelativeTo(null);
setVisible(true);
}
class Listener implements ContainerListener {
#Override
public void componentAdded(ContainerEvent e) {}
#Override
public void componentRemoved(ContainerEvent e) {
if (ui.isFloating()) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ui.setFloating(false, null);
}
});
}
}
}
public static void main(String[] args) {
new Example();
}
}
Explanation:
Whenever the toolbar is moving to a floating state, it is instructed not do so. The only problem is that you have to wait for the EDT to finish the process for creating the floating window, and only then can you tell it not to float. The result is that you actually see the window created and then hidden.
Note:
I think that overriding the UI for the toolbar is a better solution, though it's possible that with a more intricate approach doing something similar to what I did will also work well.
works for me quite correctly on WinOS, old code from SunForum
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class CaptiveToolBar {
private Robot robot;
private JDialog dialog;
private JFrame frame;
public static void main(String[] args) {
//JFrame.setDefaultLookAndFeelDecorated(true);
//JDialog.setDefaultLookAndFeelDecorated(true);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new CaptiveToolBar().makeUI();
}
});
}
public void makeUI() {
try {
robot = new Robot();
} catch (AWTException ex) {
ex.printStackTrace();
}
final JToolBar toolBar = new JToolBar();
for (int i = 0; i < 3; i++) {
toolBar.add(new JButton("" + i));
}
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.add(toolBar, BorderLayout.NORTH);
final ComponentListener dialogListener = new ComponentAdapter() {
#Override
public void componentMoved(ComponentEvent e) {
dialog = (JDialog) e.getSource();
setLocations(false);
}
};
toolBar.addHierarchyListener(new HierarchyListener() {
#Override
public void hierarchyChanged(HierarchyEvent e) {
Window window = SwingUtilities.getWindowAncestor(toolBar);
if (window instanceof JDialog) {
boolean listenerAdded = false;
for (ComponentListener listener : window.getComponentListeners()) {
if (listener == dialogListener) {
listenerAdded = true;
break;
}
}
if (!listenerAdded) {
window.addComponentListener(dialogListener);
}
}
}
});
frame.addComponentListener(new ComponentAdapter() {
#Override
public void componentMoved(ComponentEvent e) {
if (dialog != null && dialog.isShowing()) {
setLocations(true);
}
}
});
frame.setVisible(true);
}
private void setLocations(boolean moveDialog) {
int dialogX = dialog.getX();
int dialogY = dialog.getY();
int dialogW = dialog.getWidth();
int dialogH = dialog.getHeight();
int frameX = frame.getX();
int frameY = frame.getY();
int frameW = frame.getWidth();
int frameH = frame.getHeight();
boolean needToMove = false;
if (dialogX < frameX) {
dialogX = frameX;
needToMove = true;
}
if (dialogY < frameY) {
dialogY = frameY;
needToMove = true;
}
if (dialogX + dialogW > frameX + frameW) {
dialogX = frameX + frameW - dialogW;
needToMove = true;
}
if (dialogY + dialogH > frameY + frameH) {
dialogY = frameY + frameH - dialogH;
needToMove = true;
}
if (needToMove) {
if (!moveDialog && robot != null) {
robot.mouseRelease(InputEvent.BUTTON1_MASK);
}
dialog.setLocation(dialogX, dialogY);
}
}
}
Related
I have form that button can auto re-size their size when mouse hover on button and default their size when mouse is exited. It work normally first time but after i try it more than one time their size is enlarged that i can not control normally.
ImageIcon ima=new ImageIcon("C:\\Users\\chen rina\\Pictures\\win.png");
ImageIcon icon;
Thread thr;
Runnable r=new Runnable() {
#Override
public void run() {
int i=40;
while(i!=80){
try{
Thread.sleep(20);
Image scale=ima.getImage().getScaledInstance(i,i,Image.SCALE_FAST);
icon=new ImageIcon(scale);
btn2.setIcon(icon);
i=i+5;
}
catch(Exception ex){}
}
}
};
private void btn2MouseEntered(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
thr=new Thread(r);
thr.start();
}
Runnable res=new Runnable() {
int i;
#Override
public void run() {
int i=80;
while(i!=40){
try{
Thread.sleep(20);
Image scale=ima.getImage().getScaledInstance(i,i,Image.SCALE_AREA_AVERAGING);
icon=new ImageIcon(scale);
btn2.setIcon(icon);
i=i-5;
}
catch(Exception ex){}
}
}
};
private void btn2MouseExited(java.awt.event.MouseEvent evt) {
thr=new Thread(res);
thr.start();
}
Your code violates Swing thread integrity rules by making Swing calls, here setIcon(...) from within a background state. Having said that, why not simplify all of this by:
Reading in and creating and storing your ImageIcons once and only once
Never ignore exceptions as you're doing. That's unsafe coding.
Most important, use a Swing Timer to simply swap icons every 20 msec, and have no fear about violating Swing threading rules.
Your grow Timer's ActionListener could be as simple as this:
// a private inner class
private class GrowListener implements ActionListener {
private int index = 0;
#Override
public void actionPerformed(ActionEvent e) {
// assuming the button is called button and the list iconList
button.setIcon(iconList.get(index));
index++;
if (index >= iconList.size()) {
((Timer) e.getSource()).stop();
}
}
}
The iconList would look something like:
private List<Icon> iconList = new ArrayList<>();
And you could fill it with code looking something like:
for (int i = startLength; i <= endLength; i += step) {
Image img = originalImg.getScaledInstance(i, i, Image.SCALE_FAST);
iconList.add(new ImageIcon(img));
}
And a more complete and runnable example:
import java.awt.Dimension;
import java.awt.Image;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class ResizeIconTest extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final int START_LENGTH = 40;
private static final int END_LENGTH = 120;
private static final int STEP = 5;
private static final int TIMER_DELAY = 20;
private static final String URL_SPEC = "https://upload.wikimedia.org/wikipedia/commons/"
+ "thumb/2/2b/Oryx_gazella_-_Etosha_2014_square_crop.jpg/"
+ "600px-Oryx_gazella_-_Etosha_2014_square_crop.jpg";
private JButton button = new JButton();
private ResizeIcon resizeIcon;
public ResizeIconTest() throws IOException {
add(button);
URL imageUrl = new URL(URL_SPEC);
BufferedImage originalImg = ImageIO.read(imageUrl);
resizeIcon = new ResizeIcon(button, originalImg, START_LENGTH,
END_LENGTH, STEP, TIMER_DELAY);
button.setIcon(resizeIcon.getSmallestIcon());
button.addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
resizeIcon.grow();
}
#Override
public void mouseExited(MouseEvent e) {
resizeIcon.shrink();
}
});
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
ResizeIconTest mainPanel = null;
try {
mainPanel = new ResizeIconTest();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
JFrame frame = new JFrame("ResizeIconTest");
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();
}
});
}
}
class ResizeIcon {
private List<Icon> iconList = new ArrayList<>();
private AbstractButton button;
private int delayTime;
private Timer growTimer;
private Timer shrinkTimer;
public ResizeIcon(AbstractButton button, BufferedImage originalImg,
int startLength, int endLength, int step, int delayTime) {
this.button = button;
this.delayTime = delayTime;
for (int i = startLength; i <= endLength; i += step) {
Image img = originalImg.getScaledInstance(i, i, Image.SCALE_FAST);
iconList.add(new ImageIcon(img));
}
}
public Icon getSmallestIcon() {
return iconList.get(0);
}
public void grow() {
if (growTimer != null && growTimer.isRunning()) {
return; // let's not run this multiple times
}
if (button.getIcon() == iconList.get(iconList.size() - 1)) {
return; // don't run if already at largest size
}
growTimer = new Timer(delayTime, new GrowListener());
growTimer.start();
}
public void shrink() {
if (shrinkTimer != null && shrinkTimer.isRunning()) {
return; // let's not run this multiple times
}
if (button.getIcon() == iconList.get(0)) {
return; // don't run if already at smallest size
}
shrinkTimer = new Timer(delayTime, new ShrinkListener());
shrinkTimer.start();
}
private class GrowListener implements ActionListener {
private int index = 0;
#Override
public void actionPerformed(ActionEvent e) {
button.setIcon(iconList.get(index));
index++;
if (index >= iconList.size()) {
((Timer) e.getSource()).stop();
}
}
}
private class ShrinkListener implements ActionListener {
private int index = iconList.size() - 1;
#Override
public void actionPerformed(ActionEvent e) {
button.setIcon(iconList.get(index));
index--;
if (index < 0) {
((Timer) e.getSource()).stop();
}
}
}
}
I have added a simple program to illustrate.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SimpleInternalFrame extends Frame
{
private static final long serialVersionUID = 1L;
static JLayeredPane desktop;
JInternalFrame internalFrame;
public SimpleInternalFrame()
{
super("Internal Frame Demo");
setSize(500, 400);
Panel p = new Panel();
add(p, BorderLayout.SOUTH);
addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
desktop = new JDesktopPane();
desktop.setOpaque(true);
add(desktop, BorderLayout.CENTER);
}
public static void main(String args[])
{
SimpleInternalFrame sif = new SimpleInternalFrame();
sif.setVisible(true);
final JInternalFrame internalFrame = new JInternalFrame("Internal Frame 1", true, true, true, true);
internalFrame.setBounds(50, 50, 300, 200);
desktop.add(internalFrame, new Integer(1));
JTextField tf = new JTextField();
tf.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent evt)
{
System.out.println("Text Field " + evt.getClickCount());
}
});
internalFrame.add(tf);
internalFrame.setVisible(true);
final JInternalFrame internalFrame2 = new JInternalFrame("Internal Frame 1", true, true, true, true);
internalFrame2.setBounds(50, 50, 200, 100);
desktop.add(internalFrame2, new Integer(1));
JButton jb = new JButton("click me");
jb.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent evt)
{
if (evt.getClickCount() == 1)
{
System.out.println("Button " + evt.getClickCount());
internalFrame2.setVisible(false);
}
}
});
internalFrame2.add(jb);
internalFrame2.setVisible(true);
}
}
When running the code it will open a two internal frames.One has button.One has text field.Button will close the first Internal frame for single click.
Double click the button.It will show click count 2 as in text field.
This is the problem we have currently in the project.Thing is second frame dose not has text field in actual project.It has click-able item that work in double click event.
This is the problem we have currently.Please help.
tf.addMouseListener(new MouseAdapter() {
int cc;
public void mouseClicked(MouseEvent evt) {
int ccount = evt.getClickCount();
if(ccount == 1 || ccount == cc+1) {
cc = ccount;
System.out.println("Text Field " + evt.getClickCount());
}
}
});
This will work more than once.
Another possibility is to use components with overriden processMouseEvent():
public class SimpleInternalFrame extends Frame {
...
private MouseEvent lastMouseEvent;
public boolean checkEvent(MouseEvent e) {
if(lastMouseEvent != null) {
if(lastMouseEvent.getSource() != e.getSource()) {
if(e.getClickCount() != 1) {
return false;
}
}
}
lastMouseEvent = e;
return true;
}
class MTextField extends JTextField {
protected void processMouseEvent(MouseEvent e) {
if (checkEvent(e)) {
super.processMouseEvent(e);
}
}
}
class MButton extends JButton {
protected void processMouseEvent(MouseEvent e) {
if (checkEvent(e)) {
super.processMouseEvent(e);
}
}
}
public JTextField createText() {
return new MTextField();
}
public MButton createButton() {
return new MButton();
}
} //end of SimpleInternalFrame
create components:
final JTextField tf = sif.createText();
tf.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent evt) {
System.out.println("Text Field " + evt.getClickCount());
}
});
JButton jb = sif.createButton();
jb.setText("click me");
jb.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent evt) {
if (evt.getClickCount() == 1) {
internalFrame2.setVisible(false);
}
}
});
You can use a static boolean called myTurn initialized to false and then in the textfield mouseClicked:
tf.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent evt)
{
if (evt.getClickCount() >= 2 && !myTurn) {
myTurn = true;
evt.consume();
} else {
myTurn = true; //Initial one click on me
System.out.println("Text Field " + evt.getClickCount());
evt.consume();
}
}
});
This solves your problem in this basic case, but I don't know if it will in your application. The problem is that if you click the TextField before the Button, you can experience the same problem. However, if that isn't possible, this will solve it.
While searching on internet and reading some documents i was able get a solution.
int timerinterval = (int) Toolkit.getDefaultToolkit().
getDesktopProperty("awt.multiClickInterval");
final Timer timer = new Timer(timerinterval, new ActionListener()
{
public void actionPerformed(ActionEvent acEvt)
{
internalFrame2.setVisible(false);
}
});
jb.addMouseListener(new MouseAdapter()
{
public void mouseClicked(final MouseEvent evt)
{
System.out.println("Button " + evt.getClickCount());
timer.setRepeats(false);
timer.start();
if (evt.getClickCount() > 1)
{
timer.restart();
}
}
});
One draw back of this solution is if user do a single click he need to wait
timerinterval unnecessarily.Any one has better solution please post.
import java.awt.Graphics;
import javax.swing.*;
public class Demo
{
JFrame jf;
JLabel[] labels;
JPanel panel;
public Demo()
{
jf = new JFrame();
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
labels = new JLabel[10];
Box vbox = Box.createVerticalBox();
for (int i = 0; i < 10; i++)
{
labels[i] = new JLabel();
vbox.add(labels[i]);
}
panel = new JPanel();
panel.add(vbox);
jf.add(panel);
jf.setSize(300, 250);
jf.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new DemoRunnable());
}
public void updateState()
{
for (JLabel l : labels)
{
if (Math.random() > 0.5)
l.setText("777777777777777777777777777777777777");
else
l.setText("10000000000000000000000000000000000000");
}
}
}
class DemoRunnable implements Runnable
{
Demo demo;
DemoRunnable()
{
this.demo = new Demo();
}
#Override
public void run()
{
Thread t = new Thread(new Runnable()
{
#Override
public void run()
{
while (true)
{
try
{
Thread.sleep(0);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
demo.updateState();
}
}
});
t.start();
}
}
I see such effect when this program is perfomed. Is it possible to eliminate it(zeroes must be instead dots)?
Instead of setSize() use pack() to take advantage of the component's carefully calculated preferred size. You'll also need to initialize your label:
labels[i] = new JLabel("10000000000000000000000000000000000000");
Also consider javax.swing.Timer instead of a separate thread.
Addendum: Conveniently, each Swing Timer shares a common background thread, and the actionPerformed() is called on the event dispatch thread. An alternative is SwingWorker, illustrated here.
my code in answer is example only,
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.*;
public class Demo {
private JFrame jf;
private JLabel[] labels;
private JPanel panel;
public Demo() {
labels = new JLabel[10];
Box vbox = Box.createVerticalBox();
for (int i = 0; i < 10; i++) {
labels[i] = new JLabel();
labels[i].setText("10000000000000000000000000000000000000");
vbox.add(labels[i]);
}
panel = new JPanel();
panel.setLayout(new GridLayout());
panel.add(vbox);
jf = new JFrame();
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.add(panel);
jf.pack();
jf.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new DemoRunnable());
}
public void updateState() {
for (final JLabel l : labels) {
if (Math.random() > 0.5) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
l.setText("777777777777777777777777777777777777");
}
});
} else {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
l.setText("10000000000000000000000000000000000000");
}
});
}
}
}
}
class DemoRunnable implements Runnable {
private Demo demo;
DemoRunnable() {
this.demo = new Demo();
}
#Override
public void run() {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
try {
Thread.sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
demo.updateState();
}
}
});
t.start();
}
}
When setting a busy cursor on the glass pane of the application frame after closing a modal dialog, the busy cursor is not always displayed. Sometimes it works (the first time it is mostly always working), sometimes not.
Even better, when setting the busy cursor before opening the dialog. The busy cursor get displayed but when moving the mouse inside and then outside the dialog the busy cursor is not displayed anymore.
Note that I observe the following bug on Linux only. On Mac OS X or Windows the behavior is deterministic and consistent.
Another hint, in the first case of the code sample, when the mouse is NOT entering the dialog and the YES_OPTION is selected using the keyboard, the busy mouse cursor is always shown. Also in this case, the "Please wait..." label on the glass pane get never painted.
Here a SSCCE demonstrating these bugs:
import java.awt.event.*;
import javax.swing.*;
public class TestFrame extends JFrame {
private JPanel panel;
private JPanel glassPane;
public TestFrame() {
final JButton button1 = new JButton(new AbstractAction("Start activity indicator after closing the dialog") {
#Override
public void actionPerformed(ActionEvent e) {
doAction1();
}
});
final JButton button2 = new JButton(new AbstractAction("Start activity indicator before opening the dialog") {
#Override
public void actionPerformed(ActionEvent e) {
doAction2();
}
});
panel = new JPanel();
panel.add(button1);
panel.add(button2);
getContentPane().add(panel, BorderLayout.NORTH);
glassPane = (JPanel) getGlassPane();
glassPane.setLayout(new BorderLayout());
glassPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
glassPane.add(new JLabel("Please Wait..."), BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800, 600);
setVisible(true);
}
public void doAction1() {
System.out.println("IsStartingInEDT?: "+ SwingUtilities.isEventDispatchThread());
final int response = JOptionPane.showConfirmDialog(this, "Click on the YES_OPTION, busy indicator must start (if it does, try again).");
if (JOptionPane.YES_OPTION == response) {
startActivity();
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}
}
stopActivity();
}
}
public void doAction2() {
startActivity();
System.out.println("IsStartingInEDT?: "+ SwingUtilities.isEventDispatchThread());
final int response = JOptionPane.showConfirmDialog(this, "Move the mouse inside the dialog (me) and then outside, the busy indicator is not shown anymore");
if (JOptionPane.YES_OPTION == response) {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}
}
}
stopActivity();
}
public void startActivity() {
System.out.println("TestFrame.startActivity()");
glassPane.setVisible(true);
}
public void stopActivity() {
System.out.println("TestFrame.stopActivity()");
glassPane.setVisible(false);
}
/**
* #param args
*/
public static void main(String[] args) {
new TestFrame();
}
}
At the moment I did not find any related issues in the JavaBug parade. I will search further before opening a new one.
I also already read the following article but it is not very convenient as making a good modal dialog from a non-modal one is not straightforward:
http://www.javaspecialists.eu/archive/Issue065.html
Can anyone provide some help?
Thanks in advance, Pierre
You have some threading issue here.
Is IsStartingInEDT true?
If yes, you are doing it wrong because:
You should not sleep in UI thread. This would stop the screen update.
If no, you are doing it wrong because:
OptionPane.showConfirmDialog() must be called from the UI thread.
you should do something like this:
public void doAction1() {
if (!SwingUtilities.isEventDispatchThread()) {
System.err.println("error, must be edt");
return;
}
final int response = JOptionPane.showConfirmDialog(this, "Click on the YES_OPTION, busy indicator must start (if it does, try again).");
if (JOptionPane.YES_OPTION == response) {
startActivity(); // change glass panel in edt
// new thread for long standing task
new Thread( new Runnable() { public void run() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}
}
SwingUtilities.invokeAndWait(new Runnable(){ public void run() {
// changing glass panel need edt
stopActivity();
});
}).start();
}
}
1st. by using Tread.sleep(int) pretty sure to block EDT, with all issues desribed about Concurrency in Swing
2.nd works because initializations for JOptionPane create a new EDT
here is simple demonstrations about ...., please that only example and be sure that is against all Swing rules, but demostrated lock and unlock EDT by usage Tread.sleep(int) during EDT
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class ShakeComponents1 {
private JFrame frame = new JFrame();
private final String items[] = {"One", "Two", "Three"};
private Timer timer;
private JPanel panel = new JPanel();
private JPanel buttonPanel = new JPanel();
private JButton button = new JButton(" Exit ");
private boolean repeats = true;
private boolean runs = false;
private Color clr[] = {Color.red, Color.blue, Color.magenta};
private Insets initMargin;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ShakeComponents1().makeUI();
}
});
}
public void makeUI() {
buttonPanel = new JPanel();
buttonPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
buttonPanel.setLayout(new BorderLayout());
button.setPreferredSize(new Dimension(100, 45));
button.setForeground(Color.darkGray);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
Runnable doRun = new Runnable() {
#Override
public void run() {
System.exit(0);
}
};
SwingUtilities.invokeLater(doRun);
}
});
button.addMouseListener(new java.awt.event.MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
if (runs) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
runs = false;
timer.stop();
changePnlBorder(new EmptyBorder(5, 5, 5, 5));
changeBtnForegroung(Color.darkGray);
}
});
}
}
#Override
public void mouseExited(MouseEvent e) {
if (!runs) {
timer.start();
runs = true;
}
}
});
buttonPanel.add(button);
final Insets margin = button.getMargin();
panel.add(buttonPanel);
for (int i = 0; i < 2; i++) {
JComboBox combo = new JComboBox(items);
combo.setMinimumSize(new Dimension(50, 25));
combo.setMaximumSize(new Dimension(150, 25));
combo.setPreferredSize(new Dimension(100, 25));
combo.addActionListener(new ShakeAction());
panel.add(combo);
}
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.pack();
frame.setLocation(50, 50);
frame.setVisible(true);
timer = new Timer(500, new ShakeAction());
timer.setRepeats(repeats);
initMargin = button.getMargin();
}
private class ShakeAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private int noColor = 0;
private Border border;
private int count = 0;
#Override
public void actionPerformed(ActionEvent e) {
timer.start();
if (count > 5) {
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(500);
changeBtnForegroung(Color.darkGray);
Thread.sleep(500);
count = 0;
Thread.sleep(750);
} catch (Exception e) {
System.out.println(e);
}
}
}).start();
} else {
new Thread(new Runnable() {
#Override
public void run() {
try {
runs = true;
if (noColor < 2) {
noColor++;
changeBtnForegroung(clr[noColor]);
} else {
noColor = 0;
changeBtnForegroung(clr[noColor]);
}
changeBtnMargin(new Insets(initMargin.top, initMargin.left + 10, initMargin.bottom, initMargin.right - 10));
border = new EmptyBorder(0, 5, 10, 5);
changePnlBorder(border);
Thread.sleep(100);
changeBtnMargin(new Insets(initMargin.top, initMargin.left - 10, initMargin.bottom, initMargin.right + 10));
border = new EmptyBorder(0, 0, 10, 10);
changePnlBorder(border);
Thread.sleep(100);
changeBtnMargin(new Insets(initMargin.top, initMargin.left + 10, initMargin.bottom, initMargin.right - 10));
border = new EmptyBorder(5, 10, 5, 0);
changePnlBorder(border);
Thread.sleep(100);
changeBtnMargin(new Insets(initMargin.top, initMargin.left - 10, initMargin.bottom, initMargin.right + 10));
border = new EmptyBorder(10, 10, 0, 0);
changePnlBorder(border);
Thread.sleep(100);
changeBtnMargin(new Insets(initMargin.top, initMargin.left, initMargin.bottom, initMargin.right));
border = new EmptyBorder(5, 5, 5, 5);
changePnlBorder(border);
Thread.sleep(100);
count++;
} catch (Exception e) {
System.out.println(e);
}
}
}).start();
}
}
}
private void changePnlBorder(final Border b) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
buttonPanel.setBorder(b);
buttonPanel.revalidate();
buttonPanel.repaint();
}
});
}
private void changeBtnForegroung(final Color c) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
button.setForeground(c);
}
});
}
private void changeBtnMargin(final Insets margin) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
button.setMargin(margin);
}
});
}
}
conclusion -> you can create new Thread as BackGroung Task(s) wrapped into Runnable, if you wnat to simulate LongRunning Task and with Thread.sleep(int), maybe answer to your question is here
sure correct way would be by using SwingWorker for that, with Thread.sleep(int) too
This is the complete code :
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.lang.Thread;
class jProgressBar {
JProgressBar pb;
JButton start;
int i;
jProgressBar() {
buildGUI();
hookUpEvents();
}
public void buildGUI() {
JFrame fr=new JFrame("Progress Bar");
JPanel p=new JPanel();
p.setLayout(new FlowLayout(FlowLayout.CENTER));
JPanel barPanel=new JPanel();
barPanel.setLayout(new GridLayout(2,0,50,50));
pb=new JProgressBar(0,10);
start=new JButton("Start Demo");
fr.add(p);
barPanel.add(start);
barPanel.add(pb);
p.add(barPanel);
fr.setSize(500,500);
fr.setVisible(true);
}
public void hookUpEvents() {
start.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
try {
Runnable r=new Runnable() {
public void run() {
action(ae); // LINE 39
}
};
Thread th=new Thread(r);
th.start();
} catch(Exception exc) {
System.out.println(exc);
}
}
});
}
public void action(ActionEvent ae) {
start.setVisible(false);
try {
Runnable rp=new Runnable() {
public void run() {
i++;
pb.setValue(i);
try {
Thread.sleep(2000);
} catch(Exception exc) {
System.out.println(exc);
}
if(i==5) {
pb.setString("Half Done!");
}
else if(i==10) {
pb.setString("Completed!");
}
}
};
Thread th=new Thread(rp);
th.start();
} catch(Exception exc) {
System.out.println(exc);
}
}
public static void main(String args[]) {
new jProgressBar();
}
}
This is the error produced on cmd:
d:\UnderTest>javac jProgressBar.java
jProgressBar.java:39: local variable ae is accessed from within inner class; needs to be declared fina
l
action(ae);
^
1 error
What is this error and how can I solve this error?
Declare the variable ae as final:
public void actionPerformed(final ActionEvent ae) {
This means that it cannot be assigned a new value, which should be fine according to your current code.
a very nice example for SwingWorker
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
public class SwingWorkerExample extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
private final JButton startButton, stopButton;
private JScrollPane scrollPane = new JScrollPane();
private JList listBox = null;
private DefaultListModel listModel = new DefaultListModel();
private final JProgressBar progressBar;
private mySwingWorker swingWorker;
public SwingWorkerExample() {
super("SwingWorkerExample");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(new GridLayout(2, 2));
startButton = makeButton("Start");
stopButton = makeButton("Stop");
stopButton.setEnabled(false);
progressBar = makeProgressBar(0, 99);
listBox = new JList(listModel);
scrollPane.setViewportView(listBox);
getContentPane().add(scrollPane);
//Display the window.
pack();
setVisible(true);
}
//Class SwingWorker<T,V> T - the result type returned by this SwingWorker's doInBackground
//and get methods V - the type used for carrying out intermediate results by this SwingWorker's
//publish and process methods
private class mySwingWorker extends javax.swing.SwingWorker<ArrayList<Integer>, Integer> {
//The first template argument, in this case, ArrayList<Integer>, is what s returned by doInBackground(),
//and by get(). The second template argument, in this case, Integer, is what is published with the
//publish method. It is also the data type which is stored by the java.util.List that is the parameter
//for the process method, which recieves the information published by the publish method.
#Override
protected ArrayList<Integer> doInBackground() {
//Returns items of the type given as the first template argument to the SwingWorker class.
if (javax.swing.SwingUtilities.isEventDispatchThread()) {
System.out.println("javax.swing.SwingUtilities.isEventDispatchThread() returned true.");
}
Integer tmpValue = new Integer(1);
ArrayList<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < 100; i++) {
for (int j = 0; j < 100; j++) { //find every 100th prime, just to make it slower
tmpValue = FindNextPrime(tmpValue.intValue());
//isCancelled() returns true if the cancel() method is invoked on this class. That is the proper way
//to stop this thread. See the actionPerformed method.
if (isCancelled()) {
System.out.println("SwingWorker - isCancelled");
return list;
}
}
//Successive calls to publish are coalesced into a java.util.List, which is what is received by process,
//which in this case, isused to update the JProgressBar. Thus, the values passed to publish range from
//1 to 100.
publish(new Integer(i));
list.add(tmpValue);
}
return list;
}//Note, always use java.util.List here, or it will use the wrong list.
#Override
protected void process(java.util.List<Integer> progressList) {
//This method is processing a java.util.List of items given as successive arguments to the publish method.
//Note that these calls are coalesced into a java.util.List. This list holds items of the type given as the
//second template parameter type to SwingWorker. Note that the get method below has nothing to do with the
//SwingWorker get method; it is the List's get method. This would be a good place to update a progress bar.
if (!javax.swing.SwingUtilities.isEventDispatchThread()) {
System.out.println("javax.swing.SwingUtilities.isEventDispatchThread() + returned false.");
}
Integer percentComplete = progressList.get(progressList.size() - 1);
progressBar.setValue(percentComplete.intValue());
}
#Override
protected void done() {
System.out.println("doInBackground is complete");
if (!javax.swing.SwingUtilities.isEventDispatchThread()) {
System.out.println("javax.swing.SwingUtilities.isEventDispatchThread() + returned false.");
}
try {
//Here, the SwingWorker's get method returns an item of the same type as specified as the first type parameter
//given to the SwingWorker class.
ArrayList<Integer> results = get();
for (Integer i : results) {
listModel.addElement(i.toString());
}
} catch (Exception e) {
System.out.println("Caught an exception: " + e);
}
startButton();
}
boolean IsPrime(int num) { //Checks whether a number is prime
int i;
for (i = 2; i <= num / 2; i++) {
if (num % i == 0) {
return false;
}
}
return true;
}
protected Integer FindNextPrime(int num) { //Returns next prime number from passed arg.
do {
if (num % 2 == 0) {
num++;
} else {
num += 2;
}
} while (!IsPrime(num));
return new Integer(num);
}
}
private JButton makeButton(String caption) {
JButton b = new JButton(caption);
b.setActionCommand(caption);
b.addActionListener(this);
getContentPane().add(b);
return b;
}
private JProgressBar makeProgressBar(int min, int max) {
JProgressBar progressBar1 = new JProgressBar();
progressBar1.setMinimum(min);
progressBar1.setMaximum(max);
progressBar1.setStringPainted(true);
progressBar1.setBorderPainted(true);
getContentPane().add(progressBar1);
return progressBar1;
}
private void startButton() {
startButton.setEnabled(true);
stopButton.setEnabled(false);
System.out.println("SwingWorker - Done");
}
#Override
public void actionPerformed(ActionEvent e) {
if ("Start" == null ? e.getActionCommand() == null : "Start".equals(e.getActionCommand())) {
startButton.setEnabled(false);
stopButton.setEnabled(true);
// Note that it creates a new instance of the SwingWorker-derived class. Never reuse an old one.
(swingWorker = new mySwingWorker()).execute(); // new instance
} else if ("Stop" == null ? e.getActionCommand() == null : "Stop".equals(e.getActionCommand())) {
startButton.setEnabled(true);
stopButton.setEnabled(false);
swingWorker.cancel(true); // causes isCancelled to return true in doInBackground
swingWorker = null;
}
}
public static void main(String[] args) {
// Notice that it kicks it off on the event-dispatching thread, not the main thread.
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
SwingWorkerExample swingWorkerExample = new SwingWorkerExample();
}
});
}
}
There are some counterproductive issues present.
Swing is single-thread based, and all actions must be done on the EDT. For that reason, your JProgressBar doesn't update correctly. See also Concurrency in Swing.
Don't use Thread.sleep(int) in Swing, and certainly not in an action listener.
By using Runnable, it is possible to update JProgressBar; but as mentioned, the method must be run from invokeLater().
For that, SwingWorker would be better, as shown below and here.
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
public class TestProgressBar {
private static void createAndShowUI() {
JFrame frame = new JFrame("TestProgressBar");
frame.getContentPane().add(new TestPBGui().getMainPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowUI();
}
});
}
private TestProgressBar() {
}
}
class TestPBGui {
private JPanel mainPanel = new JPanel();
public TestPBGui() {
JButton yourAttempt = new JButton("Your attempt to show Progress Bar");
JButton myAttempt = new JButton("My attempt to show Progress Bar");
yourAttempt.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
yourAttemptActionPerformed();
}
});
myAttempt.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
myAttemptActionPerformed();
}
});
mainPanel.add(yourAttempt);
mainPanel.add(myAttempt);
}
private void yourAttemptActionPerformed() {
Window thisWin = SwingUtilities.getWindowAncestor(mainPanel);
JDialog progressDialog = new JDialog(thisWin, "Uploading...");
JPanel contentPane = new JPanel();
contentPane.setPreferredSize(new Dimension(300, 100));
JProgressBar bar = new JProgressBar(0, 100);
bar.setIndeterminate(true);
contentPane.add(bar);
progressDialog.setContentPane(contentPane);
progressDialog.pack();
progressDialog.setLocationRelativeTo(null);
Task task = new Task("Your attempt");
task.execute();
progressDialog.setVisible(true);
while (!task.isDone()) {
}
progressDialog.dispose();
}
private void myAttemptActionPerformed() {
Window thisWin = SwingUtilities.getWindowAncestor(mainPanel);
final JDialog progressDialog = new JDialog(thisWin, "Uploading...");
JPanel contentPane = new JPanel();
contentPane.setPreferredSize(new Dimension(300, 100));
final JProgressBar bar = new JProgressBar(0, 100);
bar.setIndeterminate(true);
contentPane.add(bar);
progressDialog.setContentPane(contentPane);
progressDialog.pack();
progressDialog.setLocationRelativeTo(null);
final Task task = new Task("My attempt");
task.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equalsIgnoreCase("progress")) {
int progress = task.getProgress();
if (progress == 0) {
bar.setIndeterminate(true);
} else {
bar.setIndeterminate(false);
bar.setValue(progress);
progressDialog.dispose();
}
}
}
});
task.execute();
progressDialog.setVisible(true);
}
public JPanel getMainPanel() {
return mainPanel;
}
}
class Task extends SwingWorker<Void, Void> {
private static final long SLEEP_TIME = 4000;
private String text;
public Task(String text) {
this.text = text;
}
#Override
public Void doInBackground() {
setProgress(0);
try {
Thread.sleep(SLEEP_TIME);// imitate a long-running task
} catch (InterruptedException e) {
}
setProgress(100);
return null;
}
#Override
public void done() {
System.out.println(text + " is done");
Toolkit.getDefaultToolkit().beep();
}
}