Why done() is not called until modal dialog closed? - java

In an example below, an attempt made to open dialog on worker start and to close it on worker end.
Unfortunately, done() is not executed until dialog closed manually.
Why?
package tests.javax.swing;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Try_SwingWorker_Modality {
private static final Logger log = LoggerFactory.getLogger(Try_SwingWorker_Modality.class);
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
AbstractAction popupAction = new AbstractAction("popup") {
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(null, "popup");
}
};
final JDialog dialog = new JDialog((JFrame)null, true);
dialog.setLayout(new FlowLayout());
dialog.add(new JButton(popupAction));
dialog.pack();
dialog.setLocationRelativeTo(null);
SwingWorker<Object,Object> swingWorker = new SwingWorker<Object,Object>() {
#Override
protected Object doInBackground() throws Exception {
log.debug("doInBackground()");
return null;
}
#Override
protected void done() {
log.debug("done");
//dialog.dispose();
}
};
swingWorker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
log.debug("event = {}", evt);
if( "state".equals(evt.getPropertyName())) {
if( SwingWorker.StateValue.STARTED == evt.getNewValue() ) {
dialog.setVisible(true);
log.debug("after setVisible()");
}
else if( SwingWorker.StateValue.DONE == evt.getNewValue() ) {
dialog.dispose();
}
}
}
});
swingWorker.execute();
}
});
}
}

You're freezing your SwingWorker's PropertyChangeListener with that code. I would never set the dialog visible from within the PCL.
Rather, I'd do it here:
swingWorker.execute();
dialog.setVisible(true);

Related

Reminder using JOptionPane

I am designing one reminder type application using java swing.
In this I am giving two options to user, using JOptionPane YES_NO_OPTION. But what i want is if user not given any input within 10 minutes it should choose YES as default option.
what i have to do for that?
Please check below code...
public void snooze()
{
int action = JOptionPane.showConfirmDialog(null, "Yes = close citrix and Aventail \n No = snooze after 30min", "Close", JOptionPane.YES_NO_OPTION);
if(action == 0){
killcitrix();
endaventail();
}
else{
JOptionPane.showMessageDialog(null, "Will snooze after 30min");
try {
TimeUnit.SECONDS.sleep(30);
} catch (InterruptedException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
snooze();
}
}
As user1803551 already mentioned, use a Timer. Here is an example:
after 10 seconds of inactivity (if the user didn't press any button), the dialog will automatically dispose and the selected option will be JOptionPane.YES_OPTION
If the user pressed 'No', a new JOptionPane with the same functionalities will appear after 5 seconds.
Preview
Code:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.Timer;
import javax.swing.border.TitledBorder;
public class Example {
private int choice;
private JTextArea log;
public Example() {
log = new JTextArea();
log.setEditable(false);
JFrame frame = new JFrame();
frame.add(log);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 600);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
showConfirmDialog(frame);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Example();
}
});
}
public void showConfirmDialog(Component parent) {
Timer timer = new Timer(0, null);
Timer timer2 = new Timer(0, null);
log.append("Will automatically press 'Yes' after 10 seconds.\n");
timer.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (Window window : Window.getWindows()) {
if (window instanceof JDialog) {
JDialog dialog = (JDialog) window;
if (dialog.getContentPane().getComponentCount() == 1
&& dialog.getContentPane().getComponent(0) instanceof JOptionPane
&& dialog.getTitle().equals("Dialog")) {
dialog.dispose();
choice = JOptionPane.YES_OPTION;
log.append("Programmatically pressed 'Yes' on the JOptionPane due to inactivity of user\n");
}
}
}
timer.stop();
timer2.stop();
}
});
timer.setInitialDelay(10 * 1000);
timer.start();
choice = JOptionPane.showConfirmDialog(parent, "", "Dialog", JOptionPane.YES_NO_CANCEL_OPTION);
if (choice == JOptionPane.NO_OPTION) {
log.append("Dialog will reappear in 5 seconds\n");
timer2.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
log.append("Dialog reappeared\n");
showConfirmDialog(parent);
timer2.stop();
}
});
timer2.setInitialDelay(5 * 1000);
timer2.start();
}
timer.stop();
}
}

Message box without any buttons at all

I want to create auto-disposing message dialog. Everything works beside that there is still an ok button to click.
I want to get read the button.
Please check out this code -> works perfectly:
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class CloseOptionPane {
#SuppressWarnings("serial")
private static void createAndShowGui() {
final JLabel label = new JLabel();
int timerDelay = 1000;
new Timer(timerDelay, new ActionListener() {
int timeLeft = 3;
#Override
public void actionPerformed(ActionEvent e) {
if(timeLeft > 0) {
label.setText("Human player. It is your move!");
timeLeft--;
} else {
((Timer) e.getSource()).stop();
Window win = SwingUtilities.getWindowAncestor(label);
win.setVisible(false);
}
}
}) {
{
setInitialDelay(0);
}
}.start();
JOptionPane.showMessageDialog(null, label);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Adding copy action in windows to java app

I want to get the event like crtl+c or right click copy in windows , that could do the event to java application running ,
that means if someone copies some text , that should be pasted into the java application textarea...
i have made the java application and it can accept arguments through main method.
but how to trigger event from windows to java..
The simplest way is to monitor changes to the Toolkit.getSystemClipboard
There are two ways to do this. You can monitor changes to the DataFlavour, but this will only help if the data flavor changes, not the content and/or you could monitor the contents of the clipboard and update your view when it's content changes...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.FlavorEvent;
import java.awt.datatransfer.FlavorListener;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ClipboardMonitor {
public static void main(String[] args) {
new ClipboardMonitor();
}
public ClipboardMonitor() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextArea textArea;
public TestPane() {
textArea = new JTextArea(10, 10);
setLayout(new BorderLayout());
add(new JScrollPane(textArea));
Toolkit.getDefaultToolkit().getSystemClipboard().addFlavorListener(new FlavorListener() {
#Override
public void flavorsChanged(FlavorEvent e) {
setText(getClipboardContents());
}
});
Thread t = new Thread(new ContentsMonitor());
t.setDaemon(true);
t.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected String getClipboardContents() {
String text = null;
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
if (clipboard.isDataFlavorAvailable(DataFlavor.stringFlavor)) {
try {
Transferable contents = clipboard.getContents(TestPane.this);
text = (String) contents.getTransferData(DataFlavor.stringFlavor);
} catch (UnsupportedFlavorException | IOException ex) {
ex.printStackTrace();
}
}
return text;
}
protected void setText(final String text) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
textArea.setText(text);
}
});
}
public class ContentsMonitor implements Runnable {
#Override
public void run() {
String previous = getClipboardContents();
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
String text = getClipboardContents();
if (text != null && !text.equals(previous)) {
setText(text);
previous = text;
}
}
}
}
}
}

Customizing JComboBox: "infinite loops event" when LAF is system LAF

I customize my JComboBox as follow.
The program ran ok with default LAF, but whenever i changed the LAF to System LAF (another LAF, Nimbus, is ok), there was an infinite loop after the button was clicked. I saw that the actionPerformed method was called infinitely.
Please help me solving this problem. I use jdk 1.6.0_33
I'm so sorry if there is any unclear mean. My English is not good
Thanks in advance.
package sig.dw.ui;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ComboBoxEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
//import javax.swing.event.EventListenerList;
/**
*
* #author congnh
*/
public class ButtonableComboBox extends JComboBox{
private ButtonableComboBoxEditor comboBoxEditor;
public ButtonableComboBox(){
super();
comboBoxEditor = new ButtonableComboBoxEditor();
// eventListenerList = new EventListenerList();
setEditable(true);
setEditor(comboBoxEditor);
}
public ButtonableComboBox(Object[] items){
this();
setModel(new DefaultComboBoxModel(items));
}
public void addButtonListener(ActionListener listener){
comboBoxEditor.addActionListener(listener);
}
public void removeButtonListener(ActionListener listener){
comboBoxEditor.removeActionListener(listener);
}
class ButtonableComboBoxEditor implements ComboBoxEditor{
private JButton button;
public ButtonableComboBoxEditor(){
button = new JButton();
}
#Override
public Component getEditorComponent() {
return button;
}
#Override
public void setItem(Object anObject) {
if(anObject!=null){
button.setText(anObject.toString());
}
}
#Override
public Object getItem() {
return button.getText();
}
#Override
public void selectAll() {
throw new UnsupportedOperationException("Not supported yet.");
}
#Override
public void addActionListener(ActionListener l) {
System.out.println("add new listener");
button.addActionListener(l);
}
#Override
public void removeActionListener(ActionListener l) {
button.removeActionListener(l);
}
}
public static void main(String args[]){
javax.swing.SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
String[] comboBoxItems = {"Browse","Explorer","Firefox","IE","Chrome","Opera"};
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
ButtonableComboBox bcb = new ButtonableComboBox(comboBoxItems);
bcb.addButtonListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.getActionCommand());
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.add(bcb);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
For reference, I see StackOverflowError for MotifLookAndFeel on Mac OS X / Java 1.6.0_37, but not MetalLookAndFeel, NimbusLookAndFeel, or AquaLookAndFeel. Using the example below and the L&F selector seen here, I get the follwing stack trace as the UI delegate recursively invokes doClick(). I don't see an obvious workaround.
Addendum: I see a similar StackOverflowError for MotifLookAndFeel on Ubuntu 12 / Java 1.6.0_24, but not MetalLookAndFeel, NimbusLookAndFeel, or GTKLookAndFeel.
Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
at sun.font.FontManager.getFont2D(Native Method)
at sun.java2d.SunGraphics2D.checkFontInfo(SunGraphics2D.java:780)
at sun.java2d.SunGraphics2D.getFontInfo(SunGraphics2D.java:941)
at sun.java2d.pipe.GlyphListPipe.drawString(GlyphListPipe.java:32)
at sun.java2d.SunGraphics2D.drawString(SunGraphics2D.java:3054)
at sun.swing.SwingUtilities2.drawString(SwingUtilities2.java:517)
at sun.swing.SwingUtilities2.drawStringUnderlineCharAt(SwingUtilities2.java:538)
at javax.swing.plaf.basic.BasicButtonUI.paintText(BasicButtonUI.java:294)
at javax.swing.plaf.basic.BasicButtonUI.paintText(BasicButtonUI.java:319)
at javax.swing.plaf.basic.BasicButtonUI.paint(BasicButtonUI.java:207)
at com.sun.java.swing.plaf.motif.MotifButtonUI.paint(MotifButtonUI.java:91)
at javax.swing.plaf.ComponentUI.update(ComponentUI.java:153)
at javax.swing.JComponent.paintComponent(JComponent.java:760)
at javax.swing.JComponent.paint(JComponent.java:1037)
at javax.swing.JComponent.paintChildren(JComponent.java:870)
at javax.swing.JComponent.paint(JComponent.java:1046)
at javax.swing.JComponent.paintChildren(JComponent.java:870)
at javax.swing.JComponent.paint(JComponent.java:1046)
at javax.swing.JComponent._paintImmediately(JComponent.java:5106)
at javax.swing.JComponent.paintImmediately(JComponent.java:4890)
at javax.swing.JComponent.paintImmediately(JComponent.java:4902)
at javax.swing.AbstractButton.doClick(AbstractButton.java:352)
at javax.swing.plaf.basic.BasicRootPaneUI$Actions.actionPerformed(BasicRootPaneUI.java:191)
at javax.swing.plaf.basic.BasicComboBoxUI$Actions.actionPerformed(BasicComboBoxUI.java:1575)
at javax.swing.plaf.basic.BasicComboBoxUI$Handler.actionPerformed(BasicComboBoxUI.java:1904)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2028)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2351)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
at javax.swing.AbstractButton.doClick(AbstractButton.java:389)
...
at javax.swing.plaf.basic.BasicRootPaneUI$Actions.actionPerformed(BasicRootPaneUI.java:191)
at javax.swing.plaf.basic.BasicComboBoxUI$Actions.actionPerformed(BasicComboBoxUI.java:1575)
at javax.swing.plaf.basic.BasicComboBoxUI$Handler.actionPerformed(BasicComboBoxUI.java:1904)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2028)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2351)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
at javax.swing.AbstractButton.doClick(AbstractButton.java:389)
at javax.swing.plaf.basic.BasicRootPaneUI$Actions.actionPerformed(BasicRootPaneUI.java:191)
at javax.swing.plaf.basic.BasicComboBoxUI$Actions.actionPerformed(BasicComboBoxUI.java:1575)
SSCCE:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.ComboBoxEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
public class ButtonableComboBox extends JComboBox {
private ButtonableComboBoxEditor comboBoxEditor;
public ButtonableComboBox() {
comboBoxEditor = new ButtonableComboBoxEditor();
setEditor(comboBoxEditor);
setEditable(true);
}
public ButtonableComboBox(Object[] items) {
this();
setModel(new DefaultComboBoxModel(items));
}
public void addButtonListener(ActionListener listener) {
comboBoxEditor.addActionListener(listener);
}
public void removeButtonListener(ActionListener listener) {
comboBoxEditor.removeActionListener(listener);
}
class ButtonableComboBoxEditor implements ComboBoxEditor {
private JButton button = new JButton();
#Override
public Component getEditorComponent() {
return button;
}
#Override
public void setItem(Object anObject) {
if (anObject != null) {
button.setText(anObject.toString());
}
}
#Override
public Object getItem() {
return button.getText();
}
#Override
public void selectAll() {
System.out.println("select all");
button.requestFocus();
}
#Override
public void addActionListener(ActionListener l) {
System.out.println("add listener");
button.addActionListener(l);
}
#Override
public void removeActionListener(ActionListener l) {
System.out.println("remove listener");
button.removeActionListener(l);
}
}
public static void main(String args[]) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
String[] comboBoxItems = {
"Browse", "Explorer", "Firefox", "IE", "Chrome", "Opera"};
JFrame frame = new JFrame();
JPanel panel = new JPanel();
ButtonableComboBox bcb = new ButtonableComboBox(comboBoxItems);
bcb.addButtonListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.getActionCommand());
}
});
panel.add(bcb);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// https://stackoverflow.com/a/11949899/230513
frame.add(createToolBar(frame), BorderLayout.NORTH);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}

Update UI using swingworker thread

I want to use the swing worker thread to update my GUI in swing. pls any help is appreciated.I need to update only the status of 1 field using the thread i.e setText().
I just answer similar question on another forum for a question about SwingWorker:
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.Timer;
public class Main extends JFrame
{
private JLabel label;
private Executor executor = Executors.newCachedThreadPool();
private Timer timer;
private int delay = 1000; // every 1 second
public Main()
{
super("Number Generator");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(300, 65);
label = new JLabel("0");
setLayout(new FlowLayout());
getContentPane().add(label, "Center");
prepareStartShedule();
setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
new Main();
}
});
}
private void prepareStartShedule()
{
timer = new Timer(delay, startCycle());
timer.start();
}
private Action startCycle()
{
return new AbstractAction()
{
#Override
public void actionPerformed(ActionEvent e)
{
executor.execute(new MyTask());
}
};
}
private class MyTask extends SwingWorker<Void, Integer>
{
#Override
protected Void doInBackground() throws Exception
{
doTasksInBackground();
return null;
}
private void doTasksInBackground()
{
publish(generateRandomNumber());
}
private int generateRandomNumber()
{
return (int) (Math.random() * 101);
}
#Override
protected void process(List<Integer> chunks)
{
for(Integer chunk : chunks) label.setText("" + chunk);
}
}
}
ps: #trashgod helps me a month ago to understand how to deal with SwingWorker (Can't get ArrayIndexOutOfBoundsException from Future<?> and SwingWorker if thread starts Executor), so thanks to him.
EDIT: The code is corrected. Thanks #Hovercraft Full Of Eels

Categories