JOptionPane and scroll function - java

I want to JList a lot of results in a JOptionPane, however, I'm not sure how to add in a scroll function should there be too many results. How would I add a scroll bar to a JOptionPane? Any help would be great.
Thanks.

Here is an example using a JTextArea embedded in a JScrollPane:
JTextArea textArea = new JTextArea("Insert your Text here");
JScrollPane scrollPane = new JScrollPane(textArea);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
scrollPane.setPreferredSize( new Dimension( 500, 500 ) );
JOptionPane.showMessageDialog(null, scrollPane, "dialog test with textarea",
JOptionPane.YES_NO_OPTION);

Put the objects in a JList or other such component, drop it into a JScrollPane, and put the JScrollPane into the JOptionPane.

you can add any JComponent(s) to JOptionPane, including JScrollPane contains JList

I had a similar need, a JOptionPane with a Scrolling TextArea that any of my classes across my application could write to. This was to provide the user with status and progress information.
My approach was to make this a static class that I instantiated once and any class could call its update method to write to it. Below is the code and a small driver in the hopes it saves someone esle the time. This could be made not static, that just fit my needs.
package com.acme.view;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JButton;
import java.awt.BorderLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import com.acme.controller.MyController;
import com.acme.utils.NonModalMessage;
public class MyView {
private JFrame frame;
private int dialogNum = 0;
private MyController myCntrlr;
/**
* Launch the application.
*/
public static void main(String[] args) {
NonModalMessage.createMesgDialog();
NonModalMessage.updateMessage("Acme Anvil Targeting Progress");
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MyView window = new MyView();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public MyView() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 250, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myCntrlr = new MyController();
JButton btnMybutton = new JButton("myButton");
btnMybutton.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
NonModalMessage.setMessageVisible();
if(dialogNum > 0 && dialogNum % 10 == 0){
NonModalMessage.clearMessage();
NonModalMessage.updateMessage("Acme Anvil Targeting Progress");
myCntrlr.someMethod("Controller reports Roadrunner sighted. Message Number: ", dialogNum);
}
NonModalMessage.getMessage();
NonModalMessage.updateMessage("Message number: " + Integer.toString(dialogNum));
System.out.println("dialogNum: " + dialogNum);
dialogNum++;
}
});
frame.getContentPane().add(btnMybutton, BorderLayout.NORTH);
}
}
package com.acme.controller;
import com.acme.utils.NonModalMessage;
public class MyController {
public MyController(){
}
public void someMethod(String mystring, int myInt){
NonModalMessage.updateMessage(mystring + " "+ myInt);
}
}
package com.acme.utils;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;
public class NonModalMessage {
private static JTextArea textArea = null;
private static JOptionPane oPane = null;
private static JDialog dialog = null;
private static JScrollPane myjsPane = null;
public NonModalMessage(){}
public static void createMesgDialog(){
textArea = new JTextArea();
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
myjsPane = new JScrollPane(textArea);
myjsPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
oPane = new JOptionPane();
oPane.add(myjsPane);
//final JDialog dialog = pane.createDialog(myPane, "Progress Dialog");
dialog = oPane.createDialog(null, "");
dialog.setTitle("Progress Messages");
dialog.setModal(false);
dialog.setSize(400, 250);
dialog.setResizable(true);
dialog.setAlwaysOnTop(true);
}
public static void setMessageVisible(){
dialog.setVisible(true);
}
public static void updateMessage(String newMessage){
String mytext = textArea.getText();
if(mytext.isEmpty()){
textArea.setText(newMessage);
}
else{
textArea.setText(mytext + "\n" + newMessage);
}
oPane.setMessage( myjsPane );
}
public static String getMessage(){
return textArea.getText();
}
public static void clearMessage(){
textArea.setText("");
oPane.setMessage( myjsPane );
}
}

Related

Swing window not opening

I am creating a NotePad app in Java Swing but when I am trying to open a popup to set a title, it is not showing up.
The class that calls the popup:
import java.io.*;
import java.util.*;
import java.awt.event.*;
import javax.swing.*;
public class NewFile implements ActionListener{
public static String title;
public void actionPerformed(ActionEvent e){
PopupFileName popup = new PopupFileName();
/*try{
Thread.sleep(30000);
}catch (InterruptedException o){
o.printStackTrace();
}*/
JTextArea titl = popup.title;
title = titl.getText();
try{
File writer = new File(title+".txt");
if(writer.createNewFile()){
System.out.println("file created");
}else{
System.out.println("file exists");
}
}catch (IOException i) {
System.out.println("An error occurred.");
i.printStackTrace();
}
}
}
The popup class that is supposed to open:
import javax.swing.*;
public class PopupFileName{
static JFrame popup = new JFrame("File Title");
static JLabel titlel = new JLabel("Title:");
static public JTextArea title = new JTextArea();
public static void main(String[] args){
popup.setSize(200,300);
popup.setVisible(true);
popup.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
popup.add(titlel);
popup.add(title);
}
}
Is there any way I can make it visible and make it able to get the text before it is created?
Start by taking a look at:
Creating a GUI With Swing
How to Write an Action Listener
How to Use Scroll Panes
How to Use Buttons, Check Boxes, and Radio Buttons
How to Make Dialogs
You're running in an event driven environment, this means, something happens and then you respond to it.
The problem with your ActionListener is, it's trying to present a window and then, immediately, trying to get some result from it. The problem is, the window probably isn't even present on the screen yet.
What you need is some way to "stop" the code execution until after the user responds. This is where a modal dialog comes in.
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
JButton btn = new JButton("Test");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String title = PopupFileName.getTitle(TestPane.this);
System.out.println(title);
}
});
add(btn);
}
}
public static class PopupFileName extends JPanel {
private JLabel titlel = new JLabel("Title:");
private JTextArea title = new JTextArea(20, 40);
public PopupFileName() {
setLayout(new BorderLayout());
add(titlel, BorderLayout.NORTH);
add(new JScrollPane(title));
}
public String getTitle() {
return title.getText();
}
public static String getTitle(Component parent) {
PopupFileName popupFileName = new PopupFileName();
int response = JOptionPane.showConfirmDialog(parent, popupFileName, "Title", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
switch (response) {
case JOptionPane.OK_OPTION:
return popupFileName.getTitle();
default: return null;
}
}
}
}

JTextField get no focus when in a heavy-weight popup

I want do display a text filed in a popup. When popup is completly over the application frame (MediumWeightPopup) - all works fine, but when a part of popup is outside of frame (HeavyWeightPopup) it cannot be focused. In this case caret is invisible and no text input is possible.
Here is my code:
import java.awt.BorderLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Popup;
import javax.swing.PopupFactory;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class PopupTest {
public static void main(String[] args) {
JFrame frm = new JFrame("Popup test");
JPanel p = new JPanel();
p.addMouseListener(new MouseAdapter() {
Popup pop;
#Override
public void mouseReleased(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
if (pop != null) {
pop.hide();
}
JPanel popupPanel = new JPanel(new BorderLayout());
JTextField field = new JTextField(20);
popupPanel.add(field);
pop = PopupFactory.getSharedInstance().getPopup(p, popupPanel, e.getXOnScreen(), e.getYOnScreen());
pop.show();
System.out.println("Popup type: " + pop.getClass().getName());
System.out.println("Can get focus? " + field.requestFocusInWindow());
}
}
});
frm.add(p);
frm.setSize(500, 300);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.setLocationRelativeTo(null);
frm.setVisible(true);
}
}
On right click near to right border of window I get a non-focusable text field. The same problem I get with any other component in popup that allows key control (for example JTable).
How can I focus a component in a HeavyWeightPopup?
I also struggled with this years ago. I can't figure out how to give initial focus to a component on the popup. Here are some of my questions/observations:
What is the Popup class used for?
I always thought that a Popup should have some basic functionality, such as the pupup should close when:
a) the escape key is pressed
b) the popup loses focus
The popup class provides none of the above functionality and in fact seems to require some obscure code to even get the keyboard focus to work properly.
Using a JWindow seems to provide the same functionality as a Popup.
JPopupMenu seems to support both of the above requirements.
Run the following program:
a) click on each of the buttons
b) click on an empty part of the frame
It appears to me that whenever you need a "popup" you should use a JPopupMenu.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
public class PopupTest extends JFrame
{
String[] numbers = { "one", "two", "three", "four", "five" };
public PopupTest()
{
getContentPane().setLayout( new FlowLayout() );
getContentPane().setBackground(Color.YELLOW);
JButton popup = new JButton("Popup as Popup");
popup.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
popupPopup(e);
}
});
getContentPane().add(popup);
JButton window = new JButton("Window as Popup");
window.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
windowPopup(e);
}
});
getContentPane().add(window);
JButton menu = new JButton("PopupMenu as Popup");
menu.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
menuPopup(e);
}
});
getContentPane().add(menu);
}
private void popupPopup(ActionEvent e)
{
JList list = new JList(numbers);
list.setSelectedIndex(0);
PopupFactory factory = PopupFactory.getSharedInstance();
Popup popup = factory.getPopup(this, list, getLocation().x, getLocation().y+100);
//popup.show();
Window window = SwingUtilities.windowForComponent(list);
if (window != null)
{
window.setFocusableWindowState(true);
}
popup.show();
KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent(list);
}
private void windowPopup(ActionEvent e)
{
JList list = new JList(numbers);
list.setSelectedIndex(0);
JWindow window = new JWindow(this);
window.getContentPane().add(list);
window.pack();
window.setVisible(true);
window.setLocation(getLocation().x + 200, getLocation().y+100);
window.addWindowListener( new WindowAdapter()
{
public void windowDeactivated(WindowEvent e)
{
System.out.println("deactivated");
}
});
}
private void menuPopup(ActionEvent e)
{
JList list = new JList(numbers);
list.setSelectedIndex(0);
JPopupMenu menu = new JPopupMenu();
menu.add( new JTextField(10) );
menu.add( list );
menu.show((Component)e.getSource(), 0, 100);
}
private static void createAndShowGUI()
{
JFrame frame = new PopupTest();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.setSize(500, 200);
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}
Edit:
Based on Sergiy's answer, this code was close to working. The difference in the popupPopup() method is that the show() method needs to be invoked AFTER the window is made focusable. Code updated to reflect this change.
Source code analyse brought me another solution
pop = PopupFactory.getSharedInstance().getPopup(p, popupPanel, e.getXOnScreen(), e.getYOnScreen());
// some new stuff
Window win = SwingUtilities.windowForComponent(popupPanel);
if (win instanceof JWindow && win.getType() == Window.Type.POPUP) {
win.setFocusableWindowState(true);
}
// continue old stuff
pop.show();
So the complete example looks like
import java.awt.BorderLayout;
import java.awt.Window;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JWindow;
import javax.swing.Popup;
import javax.swing.PopupFactory;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class PopupTest {
public static void main(String[] args) {
JFrame frm = new JFrame("Popup test");
JPanel p = new JPanel();
p.addMouseListener(new MouseAdapter() {
Popup pop;
#Override
public void mouseReleased(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
if (pop != null) {
pop.hide();
}
JPanel popupPanel = new JPanel(new BorderLayout());
JTextField field = new JTextField(20);
popupPanel.add(field);
pop = PopupFactory.getSharedInstance().getPopup(p, popupPanel, e.getXOnScreen(), e.getYOnScreen());
Window win = SwingUtilities.windowForComponent(popupPanel);
if (win instanceof JWindow && win.getType() == Window.Type.POPUP) {
win.setFocusableWindowState(true);
}
pop.show();
System.out.println("Popup type: " + pop.getClass().getName());
System.out.println("Can get focus? " + field.requestFocusInWindow());
}
}
});
frm.add(p);
frm.setSize(500, 300);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.setLocationRelativeTo(null);
frm.setVisible(true);
}
}
Interesting: the call field.requestFocusInWindow() still returns false, but field gets focus anyway.
BTW: this solution is also better for me because in my real code I get the Popup from a JComboBox (my goal is to create JTableComboBox with a table in popup and an optional filter field on top of the table).

label unclear text when change its text

unfortunately I can't handle the change of txt when the button is clicked, I try to write a txt and overtime that I click the button, this txt value should change and allotting seems right, the only problem is that the printed number is not obvious and it seems some part of previous txt remains with it.
package berGenerator;
import java.awt.EventQueue;
public class sscce {
private JFrame frame;
private final Action action = new SwingAction();
private static int i = 555;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
sscce window = new sscce();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public sscce() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 550, 401);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
JButton Next = new JButton("Next");
Next.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
Next.setAction(action);
Next.setBounds(167, 290, 198, 64);
frame.getContentPane().add(Next);
}
private class SwingAction extends AbstractAction {
public SwingAction() {
putValue(NAME, "Next Timeslot/scheduler");
putValue(SHORT_DESCRIPTION, "Some short description");
}
public void actionPerformed(ActionEvent e) {
i = i+1;
frame.getContentPane().validate();
frame.getContentPane().repaint();
String from = String.valueOf(i);
System.out.println("sw is: "+from);
JTextArea TextArea11 = new JTextArea("");
TextArea11.setText(from);
TextArea11.setForeground(Color.GREEN);
TextArea11.setBounds(6, 66, 87, 16);
frame.getContentPane().add(TextArea11);
}
}
}
Avoid using null layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify.
Layout managers are fundamental to the Swing API, you should make the time to learn how to use them, they will solve more problems than you think they create.
See Laying Out Components Within a Container for more details.
You're creating multiple instances of JTextArea and adding to the frame, but you're not removing any, you're running into a potential z-ordering problem at best and a major resource management issue at worst.
Instead, simply create a single instance of JTextArea, add it to the frame (just like you did your button) and simply update it when the Action is triggered, for example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import static javax.swing.Action.NAME;
import static javax.swing.Action.SHORT_DESCRIPTION;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class Test {
private JFrame frame;
private final Action action = new SwingAction();
private static int i = 555;
private JTextArea textArea;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Test window = new Test();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Test() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
textArea = new JTextArea(10, 20);
textArea.setText(String.valueOf(i));
frame.add(new JScrollPane(textArea));
JButton next = new JButton("Next");
next.setAction(action);
frame.getContentPane().add(next, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
}
private class SwingAction extends AbstractAction {
public SwingAction() {
putValue(NAME, "Next Timeslot/scheduler");
putValue(SHORT_DESCRIPTION, "Some short description");
}
public void actionPerformed(ActionEvent e) {
i = i + 1;
String from = String.valueOf(i);
System.out.println("sw is: " + from);
textArea.setText(from);
textArea.setForeground(Color.GREEN);
}
}
}

Custom JOptionPane / How to wait for a button in a frame to be clicked before returning a value to a method

I am trying to create a method which opens up a JFrame with some text and 4 JButtons. I need it to operate just like the methods in the JOptionPane class so that i can do things like
int i = JOptionPane.showConfirmDialog(...);
I want to be able to call the method and wait for one of the buttons to be clicked before returning a value.
This is what I have tried so far but obviously there are a couple of errors. Anybody know what i need to do to make this work and how to get around the errors. Here is the methood
private static String displaySetStatus(String text){
JButton jbtWin = new JButton("Win");
JButton jbtLose = new JButton("Lose");
JButton jbtCancelBet = new JButton("Cancel Bet");
JButton jbtSkip = new JButton("Skip");
JFrame f = new JFrame("Set Status");
f.add(new JLabel(text));
JPanel jpSouth = new JPanel();
jpSouth.add(jbtWin);
jpSouth.add(jbtLose);
jpSouth.add(jbtCancelBet);
jpSouth.add(jbtSkip);
f.add(jpSouth, "South");
f.setSize(200, 150);
f.setLocationRelativeTo(null);
f.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
f.setVisible(true);
String status = "Empty";
ActionListener buttonListener = new SetStatusListener();
jbtWin.addActionListener(buttonListener);
jbtLose.addActionListener(buttonListener);
jbtCancelBet.addActionListener(buttonListener);
jbtSkip.addActionListener(buttonListener);
class SetStatusListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
status = ((JButton)e.getSource()).getText();
}
}
while(status.equals("Empty")){
//do nothing - wait until button is clicked
}
f.setVisible(false);
return status;
}
If you want JOptionPane functionality, which is in fact that of a modal dialog window, why not use a JOptionPane for this? Or if that won't work, use a modal JDialog window and not a JFrame. Your while (true) block is going to totally mess up your program, and modality is what you in fact want.
For example:
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
#SuppressWarnings("serial")
public class Foo1 extends JPanel {
private JTextField textField = new JTextField(10);
private JButton getStatusBtn = new JButton(new GetStatusAction("Get Status"));
public Foo1() {
textField.setFocusable(false);
add(new JLabel("Status:"));
add(textField);
add(getStatusBtn);
}
private class GetStatusAction extends AbstractAction {
public GetStatusAction(String name) {
super(name);
int mnemonic = name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
Component parentComponent = Foo1.this;
// this panel can hold any gui components that you desire
// here I simply give it a centered JLabel that displays some text
JPanel message = new JPanel(new GridBagLayout());
message.setPreferredSize(new Dimension(200, 100));
message.add(new JLabel("Some Text"));
String title = "Get Status";
int optionType = JOptionPane.OK_CANCEL_OPTION;
int messageType = JOptionPane.PLAIN_MESSAGE;
Icon icon = null;
String[] options = { "Win", "Lose" };
int initialValue = 0;
// create and show our JOptionPane, and get the information from it
int selection = JOptionPane.showOptionDialog(parentComponent,
message, title, optionType, messageType, icon, options,
initialValue);
// if the selection chosen was valid (win or lose pushed)
if (selection >= 0) {
// get the selection and use it
textField.setText(options[selection]);
}
}
}
private static void createAndShowGui() {
Foo1 mainPanel = new Foo1();
JFrame frame = new JFrame("Foo1");
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();
}
});
}
}

How do I make my SwingWorker example work properly?

I've made my own SwingWorker example to get familiar with how it works.
What I'm wanting to do is the following:
When the button is clicked I want a progress bar appear until the task is done I want to simply remove the progress bar and add a string to the dialog.
When the button is clicked, the progress bar comes up but never goes away. (never removes the progress bar after 10 seconds and never places the label up)
Here is an SSCCE:
package swingtesting;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
public class SwingTesting {
/**
* Creates a frame that will hold a simple button to make use of SwingWorker
*/
public static void main(String[] args) {
// TODO code application logic here
JFrame frame = new JFrame();
JButton button = new JButton();
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
new GuiWorker().execute();
}
});
button.setText("Test Me");
frame.getContentPane().add(button);
frame.pack();
frame.setVisible(true);
}
}
class GuiWorker extends SwingWorker<Integer, Integer> {
/*
* This should just create a frame that will hold a progress bar until the
* work is done. Once done, it should remove the progress bar from the dialog
* and add a label saying the task complete.
*/
private JFrame frame = new JFrame();
private JDialog dialog = new JDialog(frame, "Swingworker test", true);
private JProgressBar progressBar = new JProgressBar();
public GuiWorker() {
progressBar.setString("Waiting on time");
progressBar.setStringPainted(true);
progressBar.setIndeterminate(true);
dialog.getContentPane().add(progressBar);
dialog.pack();
dialog.setVisible(true);
}
#Override
protected Integer doInBackground() throws Exception {
Thread.sleep(10000);
return 0;
}
#Override
protected void done() {
JLabel label = new JLabel("Task Complete");
dialog.getContentPane().remove(progressBar);
dialog.getContentPane().add(label);
}
}
Here an updated version of your code which works
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
public class SwingTesting {
public static void main(String[] args) {
EventQueue.invokeLater( new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
JButton button = new JButton();
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
new GuiWorker().execute();
}
});
button.setText("Test Me");
frame.getContentPane().add(button);
frame.pack();
frame.setVisible(true);
}
} );
}
}
class GuiWorker extends SwingWorker<Integer, Integer> {
/*
* This should just create a frame that will hold a progress bar until the
* work is done. Once done, it should remove the progress bar from the dialog
* and add a label saying the task complete.
*/
private JFrame frame = new JFrame();
private JDialog dialog = new JDialog(frame, "Swingworker test", true);
private JProgressBar progressBar = new JProgressBar();
public GuiWorker() {
progressBar.setString("Waiting on time");
progressBar.setStringPainted(true);
progressBar.setIndeterminate(true);
dialog.getContentPane().add(progressBar);
dialog.pack();
dialog.setModal( false );
dialog.setVisible(true);
}
#Override
protected Integer doInBackground() throws Exception {
System.out.println( "GuiWorker.doInBackground" );
Thread.sleep(1000);
return 0;
}
#Override
protected void done() {
System.out.println("done");
JLabel label = new JLabel("Task Complete");
dialog.getContentPane().remove(progressBar);
dialog.getContentPane().add(label);
dialog.getContentPane().validate();
}
}
Key point is that setting a model dialog visible blocks until the dialog is disposed. So making it non-modal fixed it + the validate call on the content pane when you switch components. I also adjusted your main method to run on the EDT, and added some System.out calls. If you remove the setModal( false ) call you will see those statements are not printed until you close the dialog
There's no need to make the dialog non-modal. Simply display the dialog after starting the SwingWorker. This can be done either from the calling class, the one executing the SwingWorker, by first calling execute, and then showing the dialog, or it can be done from the SwingWorker, but if from the latter, you'll have to make your own pseudo-execute method that calls super's execute, and then shows the dialog. Note that you can't override execute() itself since it's final.
For example...
import java.awt.CardLayout;
import java.awt.Window;
import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
#SuppressWarnings("serial")
public class SwingTesting2 {
private static void createAndShowGui() {
final JFrame frame = new JFrame("SwingTesting2");
final JDialog dialog = new JDialog(frame, "Dialog",
ModalityType.APPLICATION_MODAL);
final DialogPanel dialogPanel = new DialogPanel();
dialog.getContentPane().add(dialogPanel.getMainPanel());
dialog.pack();
dialog.setLocationRelativeTo(frame);
JButton button = new JButton(new AbstractAction("Test Me") {
#Override
public void actionPerformed(ActionEvent actEvt) {
final GuiWorker2 guiWorker = new GuiWorker2();
guiWorker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if (pcEvt.getPropertyName().equals("state")) {
if (pcEvt.getNewValue() == SwingWorker.StateValue.DONE) {
try {
dialogPanel.done(guiWorker.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
} else if (pcEvt.getPropertyName().equals("progress")) {
dialogPanel.setProgress((Integer)pcEvt.getNewValue());
}
}
});
guiWorker.execute();
dialogPanel.start();
dialog.setVisible(true);
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(button);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class GuiWorker2 extends SwingWorker<Integer, Integer> {
private static final int MAX_COUNT = 20;
private static final long SLEEP_TIME = 100;
private int count = 0;
#Override
protected Integer doInBackground() throws Exception {
while (count < MAX_COUNT) {
Thread.sleep(SLEEP_TIME);
count++;
setProgress((100 * count) / MAX_COUNT);
}
return count;
}
}
#SuppressWarnings("serial")
class DialogPanel {
public static final String PROGRESS_BAR = "Progress Bar";
public static final String DONE = "Done";
private static final int TIMER_DELAY = 2000;
private CardLayout cardLayout = new CardLayout();
private JPanel mainPanel = new JPanel(cardLayout);
private JLabel doneLabel = new JLabel("Done", JLabel.CENTER);
private JProgressBar progressBar = new JProgressBar();
public DialogPanel() {
progressBar.setString("Waiting on time");
progressBar.setStringPainted(true);
progressBar.setIndeterminate(false);
mainPanel.add(progressBar, PROGRESS_BAR);
mainPanel.add(doneLabel, DONE);
}
public void setProgress(Integer newValue) {
progressBar.setValue(newValue);
}
public void start() {
cardLayout.show(mainPanel, PROGRESS_BAR);
progressBar.setValue(0);
}
public void done(int countValue) {
doneLabel.setText(DONE + ". Count: " + countValue);
cardLayout.show(mainPanel, DONE);
new Timer(TIMER_DELAY, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Window win = SwingUtilities.getWindowAncestor(mainPanel);
win.dispose();
}
}){{setRepeats(false);}}.start();
}
public JPanel getMainPanel() {
return mainPanel;
}
}

Categories