Java Jframe is displaying but the contents (Panel) is not showing properly - java

I've developed a small application to track my daily work activities, this tool contains two classes:
Executor
UIProgress
My objective was to create a ProgressBar which updates the status of the execution, the logic used is given below,
From executeTask () defined in Executor class, I'have created
UIProgress object.
The UIProgress class extends JFrame. Create a panel which contains
a label with one image and the progress bar. I've defined a
method updateProgress in this class which set the value for
progressbar.
In executeTask () method (in Executor class), created UIProgress
object. In executeTask (), am calling different functions to execute
the tasks and after each function am invoking
UIProgress.updateProgress () method with integer vale to update progressbar.
But while running the program, the JFrame UI is transparent means it didn't show the contents instead contains the background data in the frame, Only progressbar is showing and it updating but the entire JFrame is transparent. We are not seeing the panel (image) and it shows as a transparent mode.
Note: setVisible (true) called after added panel into JFrame.
Executor.java
public void executeTask ()
{
/* Create and display the form */
progress = new UIProgress();
progress.prepareGUI();
progress.updateProgress (10);
getWorkedItems ();
//progress.pack ();
progress.updateProgress (30);
getWorkedTickets ();
progress.updateProgress (50);
getRemainTickets ();
progress.updateProgress (70);
jf.postTriagedTicketDetailsDaily();
...
}
UIProgress.java
public class UIProgress extends javax.swing.JFrame {
public UIProgress() {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
initComponents();
}
private void initComponents() {
panelHeading = new javax.swing.JPanel();
jLabel1 = new javax.swing.JLabel();
progress_cntrl = new javax.swing.JProgressBar();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
panelHeading.setBackground(new java.awt.Color(204, 204, 204));
panelHeading.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
panelHeading.setDebugGraphicsOptions(javax.swing.DebugGraphics.NONE_OPTION);
panelHeading.setOpaque(false);
jLabel1.setBackground(new java.awt.Color(0, 0, 0));
jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/devtriagerepot_daily/Background-20.jpeg"))); // NOI18N
javax.swing.GroupLayout panelHeadingLayout = new javax.swing.GroupLayout(panelHeading);
panelHeading.setLayout(panelHeadingLayout);
panelHeadingLayout.setHorizontalGroup(
panelHeadingLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, panelHeadingLayout.createSequentialGroup()
.addContainerGap(29, Short.MAX_VALUE)
.addComponent(progress_cntrl, javax.swing.GroupLayout.PREFERRED_SIZE, 651, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(27, 27, 27))
.addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
);
panelHeadingLayout.setVerticalGroup(
panelHeadingLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(panelHeadingLayout.createSequentialGroup()
.addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 147, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(26, 26, 26)
.addComponent(progress_cntrl, javax.swing.GroupLayout.PREFERRED_SIZE, 40, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 31, Short.MAX_VALUE))
);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(panelHeading, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 4, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(panelHeading, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
);
getAccessibleContext().setAccessibleParent(this);
pack();
}
public void prepareGUI ()
{
progress_cntrl.setMaximum(120);
progress_cntrl.setStringPainted(true);
Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
int x = (int) ((dimension.getWidth() - this.getWidth()) / 2);
int y = (int) ((dimension.getHeight() - this.getHeight()) / 2);
this.setLocation(x, y);
pack ();
setVisible(true);
}
public void updateProgress (int val)
{
progress_cntrl.update(progress_cntrl.getGraphics());
progress_cntrl.setValue(val);
}

The key is likely in these methods here:
getWorkedItems ();
getWorkedTickets ();
getRemainTickets ();
If they take any time to perform at all, your calling them on the Swing event thread will block the thread and freeze your GUI completely, rendering it unable to draw itself properly. The solution is to call any long-running methods in a background thread, such as a SwingWorker's doInBackground() method, and make Swing calls only on the Swing event thread. Again a SwingWorker would work well for this, and in fact it has its own "bound" progress property that can be used. Within the worker simply call setProgress(value) where value is your int from 0 to 100. Then attach a PropertyChangeListener to the worker so that the GUI can be notified of these changes when the progress property is updated.
A caveat: be sure to listen for the worker to finish its run so that you can call get() on the worker as this ill allow you to trap and respond to any exceptions that might have been called during its run.
For example, your code could look something like:
public void executeTask() {
progress = new UIProgress();
progress.prepareGUI();
final SwingWorker<Void, Void> myWorker = new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
// progress.updateProgress (10);
setProgress(10); // sets the worker's "bound" progress property
getWorkedItems();
setProgress(30);
getWorkedTickets();
setProgress(50);
getRemainTickets();
setProgress(70);
// ... only further background work goes here
// no direct Swing calls
return null;
}
};
myWorker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
// if the progress property has been changed
// get its value and use it to update the GUI
progress.updateProgress((int) evt.getNewValue());
} else if (SwingWorker.StateValue.DONE == evt.getNewValue()) {
// worker is done then here notify the GUI
// perhaps call:
// jf.postTriagedTicketDetailsDaily();
// call get() on worker to catch and handle exceptions
try {
myWorker.get();
} catch (InterruptedException | ExecutionException e) {
// TODO handle the excpetions here
e.printStackTrace();
}
}
}
});
myWorker.execute();
}
Note: code not tested.
Please check out Lesson: Concurrency in Swing
Also check out the Swing Tutorials
If this doesn't solve your problem, then you will likely have to create and post a sscce or a minimal example program/mcve where you condense your code into the smallest bit that still compiles and runs, has no outside dependencies (such as need to link to a database or images), has no extra code that's not relevant to your problem, but still demonstrates your problem.
For example, this small program demonstrates the above code in a working GUI:
import java.awt.*;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import javax.swing.*;
public class TestWorker {
private UIProgress progress;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new TestWorker().executeTask();
});
}
public void executeTask() {
progress = new UIProgress();
progress.prepareGUI();
final SwingWorker<Void, Void> myWorker = new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
// progress.updateProgress (10);
setProgress(10); // sets the worker's "bound" progress property
getWorkedItems();
setProgress(30);
getWorkedTickets();
setProgress(50);
getRemainTickets();
setProgress(70);
TimeUnit.SECONDS.sleep(2);
// ... only further background work goes here
// no direct Swing calls
return null;
}
};
myWorker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
// if the progress property has been changed
// get its value and use it to update the GUI
progress.updateProgress((int) evt.getNewValue());
} else if (SwingWorker.StateValue.DONE == evt.getNewValue()) {
// worker is done then here notify the GUI
progress.updateProgress(100);
// perhaps call:
// jf.postTriagedTicketDetailsDaily();
// call get() on worker to catch and handle exceptions
try {
myWorker.get();
} catch (InterruptedException | ExecutionException e) {
// TODO handle the exceptions here
e.printStackTrace();
}
}
}
});
myWorker.execute();
}
// dummy methods just to demonstrate long-running code
private void getRemainTickets() {
mySleep(3); // emulate long-running code
}
private void getWorkedTickets() {
mySleep(4);
}
private void getWorkedItems() {
mySleep(2);
}
private void mySleep(int seconds) {
try {
TimeUnit.SECONDS.sleep(seconds);
} catch (InterruptedException e) {}
}
#SuppressWarnings("serial")
private class UIProgress extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = 100;
private JProgressBar progressBar = new JProgressBar(0, 100);
private JLabel statusLabel = new JLabel(" ");
public UIProgress() {
JPanel statusPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
statusPanel.add(new JLabel("Status:"));
statusPanel.add(Box.createHorizontalStrut(4));
statusPanel.add(statusLabel);
setLayout(new BorderLayout());
setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
add(statusPanel, BorderLayout.PAGE_START);
add(progressBar, BorderLayout.PAGE_END);
}
public void prepareGUI() {
JFrame frame = new JFrame("UI Progress");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
public void updateProgress(int prog) {
String text = String.format("Current Progress is %d%%", prog);
statusLabel.setText(text);
progressBar.setValue(prog);
}
}
}

Related

In Java, where to put code to reliably fire on window close?

I have several windows that I want to save defaults from, after the time the user takes action to close the window (by the button in the title bar, a menu item or a button I've provided) and before it's disposed of.
Some windows I can DISPOSE_ON_CLOSE but some I need info from before they're disposed().
formWindowClosed seems only to fire when the window is disposed of, which I can't always rely on (see above & below)
formWindowClosing seems to fire only when the user closes the window from the titlebar's system menu, even though I call System.exit(0) in my own menu action handler
According do GC documentation, the dispose() method is not always called and is frequently ignored on app shutdown.
I've added a ShutdownHook to run System.runFinalization() but the code is still not being executed. This may be too late anyways, as some windows will have been disposed of by then.
How can I ensure that the code is run before the window is disposed of? It is a task that the window should be able to take care of, itself. I'm kind of frustrated at the unreliability of the Closed, Closing and dispose events. What am I missing?
Use WindowListener windowClosed() method. In general in Java you cannot rely on disposition. It is not guaranteed that this method will be called.
After finding a number of similar questions here:
WindowAdapter windowClosed method not running
Workaround for non-compliant JVM not sending WindowClosing events
Message when closing JFrame Window
I created an app that fired System.out.println() statements on each of windowDeactivated, windowClosing and WindowClosed events and tried closing both a JFrame and a JDialog window with the system X button and with a button that just setVisible(false):
/**
* Test program to explore the relationship between defaultCloseOperation
* states, and the sequence of events triggered when closing a window
* with the (X) button vs using setVisible(false).
*
* #author MaskedCoder
*
*/
package testwindowadapter;
import java.awt.EventQueue;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.WindowConstants;
/**
* Class to listen for window close events
*/
public class WindowNotifier extends WindowAdapter implements WindowListener
{
public WindowNotifier() {
super();
}
#Override
public void windowClosing(WindowEvent e)
{
super.windowClosing(e);
System.out.println(e.getComponent().getClass().getSimpleName() + ".windowClosing fired");
}
#Override
public void windowClosed(WindowEvent e) {
super.windowClosed(e); //To change body of generated methods, choose Tools | Templates.
System.out.println(e.getComponent().getClass().getSimpleName() + ".windowClosed fired");
}
#Override
public void windowDeactivated(WindowEvent e) {
super.windowDeactivated(e);
System.out.println(e.getComponent().getClass().getSimpleName() + ".windowDeactivated fired");
}
}
/**
* Creates new form TestDialog
*/
public class TestDialog extends javax.swing.JDialog {
public TestDialog(java.awt.Frame parent, boolean modal) {
super(parent, modal);
initComponents();
addWindowListener(new WindowNotifier());
cboDefaultCloseOp.setSelectedIndex(getDefaultCloseOperation());
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
btnClose = new javax.swing.JButton();
cboDefaultCloseOp = new javax.swing.JComboBox();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle("WindowAdapter Test");
btnClose.setText("Close window");
btnClose.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnCloseActionPerformed(evt);
}
});
cboDefaultCloseOp.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "DO_NOTHING_ON_CLOSE", "HIDE_ON_CLOSE", "DISPOSE_ON_CLOSE" }));
cboDefaultCloseOp.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
cboDefaultCloseOpItemStateChanged(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(cboDefaultCloseOp, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addGap(58, 58, 58)
.addComponent(btnClose)))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(cboDefaultCloseOp, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(btnClose)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pack();
}// </editor-fold>
private void btnCloseActionPerformed(java.awt.event.ActionEvent evt) {
setVisible(false);
}
private void cboDefaultCloseOpItemStateChanged(java.awt.event.ItemEvent evt) {
setDefaultCloseOperation(cboDefaultCloseOp.getSelectedIndex());
}
// Variables declaration - do not modify
private javax.swing.JButton btnClose;
private javax.swing.JComboBox cboDefaultCloseOp;
// End of variables declaration
}
/**
* Creates new form TestFrame
*/
public class TestFrame extends javax.swing.JFrame {
public TestFrame() {
super();
initComponents();
addWindowListener(new WindowNotifier());
cboDefaultCloseOp.setSelectedIndex(getDefaultCloseOperation());
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
cboDefaultCloseOp = new javax.swing.JComboBox();
btnClose = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
cboDefaultCloseOp.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "DO_NOTHING_ON_CLOSE", "HIDE_ON_CLOSE", "DISPOSE_ON_CLOSE", "EXIT_ON_CLOSE" }));
cboDefaultCloseOp.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
cboDefaultCloseOpItemStateChanged(evt);
}
});
btnClose.setText("Close window");
btnClose.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnCloseActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(cboDefaultCloseOp, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addGap(41, 41, 41)
.addComponent(btnClose)))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(cboDefaultCloseOp, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(btnClose)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pack();
}// </editor-fold>
private void btnCloseActionPerformed(java.awt.event.ActionEvent evt) {
setVisible(false);
}
private void cboDefaultCloseOpItemStateChanged(java.awt.event.ItemEvent evt) {
setDefaultCloseOperation(cboDefaultCloseOp.getSelectedIndex());
}
// Variables declaration - do not modify
private javax.swing.JButton btnClose;
private javax.swing.JComboBox cboDefaultCloseOp;
// End of variables declaration
}
public class TestWindowAdapter {
public TestWindowAdapter() {
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
// TestDialog MainWin = new TestDialog(null, true);
TestFrame MainWin = new TestFrame();
MainWin.setVisible(true);
}
});
}
}
From that, I created a WindowListener that reliably fired once and only once, optionally asking for permission before allowing closure. It works for JFrame and JDialog. I chose to define "closed" as any time that the window goes from visible to not visible and "opened" as any time that the window goes from not visible to visible. This will not include iconification / deiconification. windowClosing duties will not be performed if the confirmClose denies permission to close thus preventing the window from becoming invisible.
/**
*
* #author MaskedCoder
*/
package testwindowadapter;
import java.awt.Window;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
public class ReliableOneShotCloseListener extends WindowAdapter implements WindowListener {
public interface CloseDuties {
public boolean confirmClose(WindowEvent e);
public void windowClosing(WindowEvent e);
}
private CloseDuties closeDuties;
private int defaultCloseOperation;
private boolean windowClosingFired = false;
public ReliableOneShotCloseListener(int iniDefaultCloseOperation, CloseDuties iniCloseDuties) {
super();
closeDuties = iniCloseDuties;
defaultCloseOperation = iniDefaultCloseOperation;
}
private int getDefaultCloseOperation(WindowEvent e) {
if(e.getComponent() instanceof JFrame) {
return ((JFrame) e.getComponent()).getDefaultCloseOperation();
}
else if(e.getComponent() instanceof JDialog) {
return ((JDialog) e.getComponent()).getDefaultCloseOperation();
}
else throw new IllegalArgumentException("WindowEvent.getComponent() is " + e.getComponent().getClass().getSimpleName() + ", must be JFrame or JDialog.");
}
private void setDefaultCloseOperation(WindowEvent e, int newDefaultCloseOperation) {
if(e.getComponent() instanceof JFrame) {
((JFrame) e.getComponent()).setDefaultCloseOperation(newDefaultCloseOperation);
}
else if(e.getComponent() instanceof JDialog) {
((JDialog) e.getComponent()).setDefaultCloseOperation(newDefaultCloseOperation);
}
else throw new IllegalArgumentException("WindowEvent.getComponent() is " + e.getComponent().getClass().getSimpleName() + ", must be JFrame or JDialog.");
}
private void performCloseDuties(WindowEvent e) {
if(!windowClosingFired) {
if(closeDuties.confirmClose(e)) {
setDefaultCloseOperation(e, defaultCloseOperation);
closeDuties.windowClosing(e);
windowClosingFired = true;
}
else
setDefaultCloseOperation(e, WindowConstants.DO_NOTHING_ON_CLOSE);
}
}
public int getDefaultCloseOperation() {
return defaultCloseOperation;
}
public void setDefaultCloseOperation(int newDefaultCloseOperation) {
defaultCloseOperation = newDefaultCloseOperation;
}
#Override
public void windowOpened(WindowEvent e) {
windowClosingFired = false;
}
#Override
public void windowClosing(WindowEvent e) {
performCloseDuties(e);
}
#Override
public void windowClosed(WindowEvent e) {
performCloseDuties(e);
}
#Override
public void windowActivated(WindowEvent e) {
windowClosingFired = false;
}
#Override
public void windowDeactivated(WindowEvent e) {
if(!e.getComponent().isVisible())
performCloseDuties(e);
}
}
Adding this as a windowlistener to a JDialog or JFrame extension and implementing a version of CloseDuties adds a great deal of flexibility and reliability to the business of closing a window.

how to force java swing gui to update on this snippet

What I want from the following minimum working example is to change its radio button's text twice in a small time interval after clicking on it. i.e., when I click on the button, I want to immediately change its text to "1" and after 3 seconds to change its text again to "2".
public class Example extends javax.swing.JFrame {
public Example() {
jRadioButton1 = new javax.swing.JRadioButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jRadioButton1.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
jRadioButton1ItemStateChanged(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup().addGap(137, 137, 137)
.addComponent(jRadioButton1).addContainerGap(242, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup().addGap(126, 126, 126)
.addComponent(jRadioButton1).addContainerGap(153, Short.MAX_VALUE))
);
pack();
}
private void jRadioButton1ItemStateChanged(java.awt.event.ItemEvent evt) {
jRadioButton1.setText("1");
//repaint();
try { Thread.sleep(3000); }
catch (InterruptedException e) {}
jRadioButton1.setText("2");
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Example().setVisible(true);
}
});
}
private javax.swing.JRadioButton jRadioButton1;
}
The above obviously doesn't work.
I know that I should use repaint() or SwingUtilities.invokeLater() or maybe a new thread in some way, but I didn't manage yet to achieve the desired result with any combination of the them.
What should I do?
Thanks in advance.
Sleeping in the event dispatch thread blocks it and prevents drawing from happening as you have found out. It also makes the rest of the UI unresponsive for the time, so it's in the list of things you should never do.
The standard way to run delayed, or repeated action in swing applications is using a swing Timer. It runs the action properly in the event dispatch thread, so that you also don't need to pay special attention to thread safety. Using a Timer your button action becomes:
private void jRadioButton1ItemStateChanged(java.awt.event.ItemEvent evt) {
jRadioButton1.setText("1");
Timer timer = new Timer(3000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
jRadioButton1.setText("2");
}
});
timer.setRepeats(false);
timer.start();
}
First of all, change this
private javax.swing.JRadioButton jRadioButton1;
to
public javax.swing.JRadioButton jRadioButton1;
Then. You may write this class
public class Updater extends Thread {
private Example e ;
public Updater(Example e) {
this.e = e;
}
public void run(){
try {
Thread.sleep(3000);
e.jRadioButton1.setText("2");
} catch (InterruptedException ex){
}
}
}
Now here in this method.
private void jRadioButton1ItemStateChanged(java.awt.event.ItemEvent evt) {
jRadioButton1.setText("1");
new Updater(this).start();
}

How to make a JList invisible unless something is done?

I have three Jlists in a JFrame. Ideally, the first two lists should always be visible, but the third should only be visible if you choose a specific item from the second list.
Is there any way to grey-out or make this last list invisible unless the correct item from the second list is chosen? I have Googled quite a bit and looked through JList documentation, but could not find a solution.
Here is the relevant code after removing work-sensitive stuff:
//third list that should not appear unless specific item chosen in second list
dayPanel.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
dayLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
dayLabel.setText("<html><center>For new rows, are one or multiple outputs used?</center>\n<i>(only used if B is selected in the second list");
dayTabList.setModel(new javax.swing.AbstractListModel() {
String[] strings = { "3A", "3B" };
public int getSize() { return strings.length; }
public Object getElementAt(int i) { return strings[i]; }
});
dayTabList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
dayTabList.setMaximumSize(new java.awt.Dimension(430, 32));
dayTabList.setPreferredSize(new java.awt.Dimension(466, 32));
dayTabList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
dayTabListValueChanged(evt);
}
});
dayScrollPane.setViewportView(dayTabList);
javax.swing.GroupLayout dayPanelLayout = new javax.swing.GroupLayout(dayPanel);
dayPanel.setLayout(dayPanelLayout);
dayPanelLayout.setHorizontalGroup(
dayPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, dayPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(dayScrollPane)
.addContainerGap())
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, dayPanelLayout.createSequentialGroup()
.addContainerGap(51, Short.MAX_VALUE)
.addComponent(dayLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(47, 47, 47))
);
dayPanelLayout.setVerticalGroup(
dayPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(dayPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(dayLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(dayScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(23, Short.MAX_VALUE))
);
//listener for the second list
private void resultsTabListValueChanged(javax.swing.event.ListSelectionEvent evt) {
// TODO add your handling code here:
String resultsTabChoice;
resultsTabChoice = (String)resultsTabList.getSelectedValue();
boolean adjust = evt.getValueIsAdjusting();
if(!adjust){
if(resultsTabChoice.equals("B")){
dayTabList.setVisible(true);
}else {
dayTabList.setVisible(false);
}
}
}
You can use addListSelectionListener, add a listener on your second list which implements ListSelectionListener and in this listener implements valueChanged(ListSelectionEvent e), in this method check if desired value is checked and make your list invisible, I give you a source sample:
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
public class SwingSample {
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
SwingSample window = new SwingSample();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public SwingSample() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(1,2));
// create the first list
String[] data = {"one", "two", "three", "four"};
JList firstList = new JList(data);
frame.add(firstList);
// create the second list
String[] numbers = {"1", "2", "invisible", "4"};
JList secondList = new JList(numbers);
frame.add(secondList);
// the listener
myListListener listener = new myListListener(firstList);
secondList.addListSelectionListener(listener);
}
}
class myListListener implements ListSelectionListener{
private JList jlist;
public myListListener(JList value){
this.jlist = value;
}
public void valueChanged(ListSelectionEvent e) {
boolean adjust = e.getValueIsAdjusting();
if(!adjust){
// get the selected value
String value = (String)((JList)e.getSource()).getSelectedValue();
// if condition is accomplished make the second list invisible
if(value.equals("invisible")){
jlist.setVisible(false);
}
else{
jlist.setVisible(true);
}
}
}
}
Hope this helps,

Suddenly: java.lang.NullPointerException, worked fine last night

I made a small program that listens and sends lines on a tcp socket and appends the received info to a JTextArea. I use this to chat on a Minecraft server without having the game open.
I was working fine last night, but when I got up it wasn't working. When I opened netbeans and ran it, it gave this error:
Exception in thread "main" java.lang.NullPointerException
at com.xxx.mcchat.chat.main(chat.java:333)
Can anyone explain what's wrong?
Here is the code (http://pastebin.com/FPNty0qf):
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.xxx.mcchat;
import java.io.*;
import java.net.*;
import net.sf.json.*;
import org.apache.commons.beanutils.*;
import org.apache.commons.collections.*;
import org.apache.commons.lang.*;
import net.sf.ezmorph.*;
import org.apache.commons.logging.*;
import java.awt.event.*;
import javax.swing.UIManager;
/**
*
* #author xxx
*/
public class chat extends javax.swing.JFrame {
/**
* Creates new form chat
*/
public chat() {
initComponents();
}
public void send(String user, String message){
Socket socket = null;
PrintWriter out = null;
BufferedReader in = null;
try {
socket = new Socket("mc.xxx.net", 20060);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Don't know about host");
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection");
System.exit(1);
}
BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
//System.out.println(in.readLine()); //Uncomment to debug
if(username != null){
out.println("/api/call?method=broadcast&args="+"[\"§7[Web] §b"+username+"§7:§f "+message+"\"]"+"&key=f0e2ad47a9a43c783d2c54f396f655c9279829c8c69ae9f52934648098dec993");
chatArea.append(username + ": " + message + "\n\r");
if(autoscrollCheck.isSelected()){
chatArea.setCaretPosition(chatArea.getText().length() - 1);
}
}else{
chatArea.append("You must set your username!!" + "\n\r");
if(autoscrollCheck.isSelected()){
chatArea.setCaretPosition(chatArea.getText().length() - 1);
}
}
}
/**
* This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jCheckBoxMenuItem1 = new javax.swing.JCheckBoxMenuItem();
jToggleButton1 = new javax.swing.JToggleButton();
jScrollPane1 = new javax.swing.JScrollPane();
chatArea = new javax.swing.JTextArea();
input = new javax.swing.JTextField();
send = new javax.swing.JButton();
user = new javax.swing.JTextField();
userset = new javax.swing.JButton();
autoscrollCheck = new javax.swing.JCheckBox();
jLabel1 = new javax.swing.JLabel();
jCheckBoxMenuItem1.setSelected(true);
jCheckBoxMenuItem1.setText("jCheckBoxMenuItem1");
jToggleButton1.setText("jToggleButton1");
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle("Minecraft Chat");
addWindowListener(new java.awt.event.WindowAdapter() {
public void windowOpened(java.awt.event.WindowEvent evt) {
formWindowOpened(evt);
}
public void windowClosing(java.awt.event.WindowEvent evt) {
formWindowClosing(evt);
}
});
chatArea.setEditable(false);
chatArea.setBackground(new java.awt.Color(0, 0, 0));
chatArea.setColumns(20);
chatArea.setFont(new java.awt.Font("Consolas", 0, 14)); // NOI18N
chatArea.setForeground(new java.awt.Color(255, 255, 255));
chatArea.setLineWrap(true);
chatArea.setRows(5);
jScrollPane1.setViewportView(chatArea);
input.setToolTipText("Enter message here");
input.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyPressed(java.awt.event.KeyEvent evt) {
inputKeyPressed(evt);
}
});
send.setText("Send");
send.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
sendActionPerformed(evt);
}
});
user.setToolTipText("");
user.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
userActionPerformed(evt);
}
});
user.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyPressed(java.awt.event.KeyEvent evt) {
userKeyPressed(evt);
}
});
userset.setText("Set");
userset.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
usersetActionPerformed(evt);
}
});
autoscrollCheck.setSelected(true);
autoscrollCheck.setText("Auto Scroll");
autoscrollCheck.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
autoscrollCheckActionPerformed(evt);
}
});
jLabel1.setText("Enter Username:");
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(jLabel1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(user, javax.swing.GroupLayout.PREFERRED_SIZE, 218, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(userset)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(autoscrollCheck))
.addComponent(jScrollPane1)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(input, javax.swing.GroupLayout.PREFERRED_SIZE, 649, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(send)))
.addGap(10, 10, 10))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(11, 11, 11)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(1, 1, 1)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(user, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel1)))
.addComponent(userset)
.addComponent(autoscrollCheck))
.addGap(6, 6, 6)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 316, Short.MAX_VALUE)
.addGap(6, 6, 6)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(1, 1, 1)
.addComponent(input, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(send))
.addGap(11, 11, 11))
);
pack();
}// </editor-fold>
String username = null;
private void inputKeyPressed(java.awt.event.KeyEvent evt) {
int key = evt.getKeyCode();
if (key == KeyEvent.VK_ENTER) {
send(username, input.getText());
input.setText("");
}
}
private void sendActionPerformed(java.awt.event.ActionEvent evt) {
send(username, input.getText());
input.setText("");
}
private void usersetActionPerformed(java.awt.event.ActionEvent evt) {
if(username == null){
if(!"".equals(user.getText())){
username = user.getText();
chatArea.append("Username set!"+"\n\r");
if(autoscrollCheck.isSelected()){
chatArea.setCaretPosition(chatArea.getText().length() - 1);
}
}else{
chatArea.append("Username can not be blank."+"\n\r");
if(autoscrollCheck.isSelected()){
chatArea.setCaretPosition(chatArea.getText().length() - 1);
}
}
}else{
send(username, "§7changed name to " + user.getText());
username = user.getText();
}
}
private void userActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
}
private void userKeyPressed(java.awt.event.KeyEvent evt) {
int key = evt.getKeyCode();
if (key == KeyEvent.VK_ENTER) {
if(username == null){
if(!"".equals(user.getText())){
username = user.getText();
chatArea.append("Username set!"+"\n\r");
if(autoscrollCheck.isSelected()){
chatArea.setCaretPosition(chatArea.getText().length() - 1);
}
}else{
chatArea.append("Username can not be blank."+"\n\r");
if(autoscrollCheck.isSelected()){
chatArea.setCaretPosition(chatArea.getText().length() - 1);
}
}
}else{
send(username, "§7changed name to " + user.getText());
username = user.getText();
}
}
}
private void formWindowClosing(java.awt.event.WindowEvent evt) {
}
private void formWindowOpened(java.awt.event.WindowEvent evt) {
// TODO add your handling code here:
}
private void autoscrollCheckActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
}
/**
* #param args the command line arguments
*/
public static void main(String args[]) throws IOException {
/* Set the system look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
javax.swing.UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(chat.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(chat.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(chat.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(chat.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new chat().setVisible(true);
}
});
Socket socket = null;
PrintWriter out = null;
BufferedReader in = null;
try {
socket = new Socket("mc.xxx.net", 20060);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Don't know about host");
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection");
System.exit(1);
}
BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
//System.out.println(in.readLine()); //Uncomment to debug
out.println("/api/subscribe?source=chat&key=1e287587f5d1d45255f4708467eeaf8a71085f9ccfd8a354523d233cf5a77be4&show_previous=true");
out.println("/api/subscribe?source=connections&key=e410592b70c0288654e6c1040edb0f21811dcb3f2ee11051163f36be9be00788&show_previous=false");
while(true){
String jsonString = in.readLine();
JSONObject obj = JSONObject.fromObject(jsonString);
JSONObject success = obj.getJSONObject("success");
if(success.get("message") != null){
chatArea.append("<" + success.get("player") + "> " + success.get("message") + "\n\r");
if(autoscrollCheck.isSelected()){
chatArea.setCaretPosition(chatArea.getText().length() - 1);
}
}else if (success.get("action") != null){
chatArea.append(success.get("player") + " " + success.get("action") + "\n\r");
if(autoscrollCheck.isSelected()){
chatArea.setCaretPosition(chatArea.getText().length() - 1);
}
}
}
}
// Variables declaration - do not modify
public static javax.swing.JCheckBox autoscrollCheck;
public static javax.swing.JTextArea chatArea;
private javax.swing.JTextField input;
private javax.swing.JCheckBoxMenuItem jCheckBoxMenuItem1;
private javax.swing.JLabel jLabel1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JToggleButton jToggleButton1;
private javax.swing.JButton send;
private javax.swing.JTextField user;
private javax.swing.JButton userset;
// End of variables declaration
}
(P.S Please don't get grumpy because I'm using a GUI generator, this is my first program, I promise I will learn to do it by hand )
The only thing that can be null at line 333 is chatArea. (If success were null, it would've thrown an exception in the if statement at line 332.) As others have suggested, you probably have a race condition where it's not being initialized before line 333 is reached.
The correct way to fix it is to enclose chatArea calls in a call to SwingUtilities.invokeLater:
final JSONObject success = obj.getJSONObject("success");
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (success.get("message") != null) {
chatArea.append("<" + success.get("player") + "> " + success.get("message") + "\n\r");
if (autoscrollCheck.isSelected()) {
chatArea.setCaretPosition(chatArea.getText().length() - 1);
}
} else if (success.get("action") != null) {
chatArea.append(success.get("player") + " " + success.get("action") + "\n\r");
if (autoscrollCheck.isSelected()) {
chatArea.setCaretPosition(chatArea.getText().length() - 1);
}
}
}
});
Any time you make a change to a Swing component, you should call it in the event dispatch thread. What's more, since the EDT is single-threaded, queue-based kind of executor, this is guaranteed to wait until the runnable you submitted earlier is done, so chatArea will definitely be set.
One other note: it's generally good practice to wrap UIManager calls in an invokeLater call as well.
Edit: I just want to be a little more clear about what you should always wrap in an invokeLater call:
Constructing Swing components
Changing properties of Swing components
Modifying the data model of a Swing component (not necessarily getting the data, just telling the component that cares that it has changed, such as firing events, needs to happen on the EDT)
Modifying UIManager properties, including setting the look and feel or modifying the values of its keys
Instantiating a look and feel
Instantiating sublcasses of ComponentUI
Adding and removing components to and from a container
Things that don't need to be wrapped:
Changing properties on components that aren't displayed yet According to Robin in the comments, this still needs to happen on the EDT.
Calls to repaint
Calls to validate, or invalidate (I think, I need to find confirmation on this)
Do all this, and any time you switch to a new look and feel, you won't have any problems with things not being called on the EDT.
Long story short, Swing isn't thread-safe, so you should always call Swing component methods from the event dispatch thread.
Also, I welcome any suggestions for my list about things I may have forgotten.
Here's are some resources that describe threading in Swing:
Java SE 6 javax.swing javadocs
Java trail on Swing concurrency
Old blog post about the decision to make Swing single-threaded (in case you're curious)
The problem is that you're readily switching between static and non-static data. Initially, the program runs main() (static). Therein, you reference chatArea (line 333, also static). However, chatArea is only set upon calling initComponents() (non-static), which happens in the constructor (non-static). This will not always be called before the remainder of the function.
Based on your invokeLater methodology, you should move everything related to the chat program, which comes after invokeLater, into the constructor (or some method which is not static).
Basically, the only thing that should be static is your main() method. The rest should not be static. If it helps, separate things into a new class, which you reference from main(); this will help you initialize the program, then run all your chat-related things.
It is probably a race condition which makes it work sometimes. The variable chatArea is not guaranteed to be initialized by the time the main thread gets to line 333. This is due to the deferred initialization of the GUI via invokeLater() some lines before that:
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new chat().setVisible(true);
}
});
You need some synchronization between those threads, or, what also should work, just initialize the GUI in the main thread:
final chat chatObject = new chat();
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
chatObject.setVisible(true);
}
});

How to Pause and Resume a Thread in Java from another Thread

I'm writing an application with Java Swing. What i need is a procedure where i can stop the "elaboration" thread using a button in the graphic interface.
Here a simple project focused on what i need
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JTextArea;
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* #author Nikola
*/
public class Main extends javax.swing.JFrame
{
private MyThread THREAD;
public Main()
{
initComponents();
}
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jButton1 = new javax.swing.JButton();
jScrollPane1 = new javax.swing.JScrollPane();
jTextArea1 = new javax.swing.JTextArea();
jButton2 = new javax.swing.JButton();
jButton3 = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jButton1.setText("Pause Thread");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
jTextArea1.setColumns(20);
jTextArea1.setRows(5);
jScrollPane1.setViewportView(jTextArea1);
jButton2.setText("Resume Thread");
jButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton2ActionPerformed(evt);
}
});
jButton3.setText("Start Thread");
jButton3.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton3ActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jButton3)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 63, Short.MAX_VALUE)
.addComponent(jButton2)
.addGap(18, 18, 18)
.addComponent(jButton1))
.addComponent(jScrollPane1))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 244, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jButton1)
.addComponent(jButton2)
.addComponent(jButton3))
.addContainerGap())
);
pack();
}// </editor-fold>
private void jButton3ActionPerformed(java.awt.event.ActionEvent evt)
{
THREAD = new MyThread(jTextArea1);
THREAD.start();
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
try
{
THREAD.pauseThread();
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt)
{
THREAD.resumeThread();
}
public static void main(String args[])
{
/*
* Set the Nimbus look and feel
*/
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/*
* If Nimbus (introduced in Java SE 6) is not available, stay with the
* default look and feel. For details see
* http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try
{
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels())
{
if ("Nimbus".equals(info.getName()))
{
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
}
catch (ClassNotFoundException ex)
{
java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
catch (InstantiationException ex)
{
java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
catch (IllegalAccessException ex)
{
java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
catch (javax.swing.UnsupportedLookAndFeelException ex)
{
java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/*
* Create and display the form
*/
java.awt.EventQueue.invokeLater(new Runnable()
{
public void run()
{
new Main().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JButton jButton1;
private javax.swing.JButton jButton2;
private javax.swing.JButton jButton3;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTextArea jTextArea1;
// End of variables declaration
}
class MyThread extends Thread
{
JTextArea area;
private final Object lock = new Object();
public MyThread(JTextArea area)
{
super();
this.area = area;
}
#Override
public void run()
{
for(int i=0 ; ; i++)
area.setText(i+"");
}
public void pauseThread() throws InterruptedException
{
synchronized(lock)
{
lock.wait();
}
}
public void resumeThread()
{
synchronized(lock)
{
lock.notify();
}
}
}
The question is simple:
In the real application, the user set some options and then start the thread which doing the elaboration of the selected data.
I want to provide a "pause" button so the user can stop temporarily the elaboration and make some needed check and after that can resume the operation.
In the way i coded is the graphic thread that stop, not the "elaboration" one.
If you run my sample code and press "Start" the textarea starts to counting. The final result that i need is that when i press the "Pause" button the thread go to "sleep" and the counting stops, when i press the "Resume" button the thread "wakes up" and the counting in the text area starts againt to count.
You can't definitively pause one thread from another in the way you seem to want.
What you need to do instead, is signal that the other thread should stop, by setting some sort of flag. The thread in question must have logic to check this flag and pause its work when that happens.
So in this particular case, perhaps change MyThread as follows:
class MyThread extends Thread {
private volatile boolean running = true; // Run unless told to pause
...
#Override
public void run()
{
for(int i=0 ; ; i++)
{
// Only keep painting while "running" is true
// This is a crude implementation of pausing the thread
while (!running)
yield;
area.setText(i+"");
}
public void pauseThread() throws InterruptedException
{
running = false;
}
public void resumeThread()
{
running = true;
}
}
This is a crude example that for brevity uses a sort of spinlock rather than proper monitor-based sleeping. Hopefully though it communicates the idea of how you use a flag to control the pausing of the thread.
Note that if you were doing some long-running set of steps within the block, instead of just the setText call, it would be good practice to check Thread.currentThread().interrupted() between each of the steps - and exit the loop if the itnerrupt flag is set. This is broadly what the built-in blocking methods (e.g. I/O) do so that they can be interrupted by other threads - since the running flag is only checked one per loop, it doesn't do much good to set it if each loop takes 20 minutes.
Try it like this:
class MyThread extends Thread {
JTextArea area;
private final Object GUI_INITIALIZATION_MONITOR = new Object();
private boolean pauseThreadFlag = false;
public MyThread(JTextArea area) {
super();
this.area = area;
}
#Override
public void run() {
for(int i=0 ; ; i++) {
checkForPaused();
area.setText(i+"");
}
}
private void checkForPaused() {
synchronized (GUI_INITIALIZATION_MONITOR) {
while (pauseThreadFlag) {
try {
GUI_INITIALIZATION_MONITOR.wait();
} catch (Exception e) {}
}
}
}
public void pauseThread() throws InterruptedException {
pauseThreadFlag = true;
}
public void resumeThread() {
synchronized(GUI_INITIALIZATION_MONITOR) {
pauseThreadFlag = false;
GUI_INITIALIZATION_MONITOR.notify();
}
}
}
It is a good idead to use monitors like you did. But you can not force the wait from outside. You have to tell the thread to wait, until you notify him again (over the monitor). In this case, you just have this simple method checkForPaused() that you will have to put in strategic positions so there is not a long delay until the thread is paused.
You can also extend this function so you can ask the thread if he is paused with a flag set in checkForPaused() and a public boolean isPausing().

Categories