Chaudary Usman Chaudary Usman - 1 month ago 8
Java Question

GUI freeze when JCombobox selected, How to use Timer in Swing Application with Condition Statement in actionListener?

I am working on a login frame where i am retrieving and populating JComboBox with user created databases and then I am setting Text of JLabel on the basis of Item selected from JComboBox.
I want to delay the execution and display the 'Connecting...' text in JLabel when user selects an item from JComboBox but when I select an item the GUI freezes and after 5 seconds it shows 'Connected' It skips the 'Connecting...' JLabel.

A Lot of Thanks in advance.

package com.softoak.dba;

import java.awt.Color;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;

import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;

import javax.swing.JComboBox;

public class Login{

private JFrame frame;
static ArrayList<String> dbcom = new ArrayList<String>();
static String[] usecom;
JLabel status = new JLabel("•");
JLabel lblNotConnected;

/**
* Launch the application.
*/
public static void main(String[] args) throws Exception{
Connection m_Connection = DriverManager.getConnection("jdbc:sqlserver://localhost;integratedSecurity=true");

String dbs = "SELECT * FROM sys.databases WHERE owner_sid != 1";

Statement st = m_Connection.createStatement();

ResultSet m_ResultSet = st.executeQuery(dbs);
dbcom.add("-None-");

while(m_ResultSet.next()){
dbcom.add(m_ResultSet.getString(1));
}
usecom = new String[dbcom.size()];
usecom = dbcom.toArray(usecom);

EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Login window = new Login();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}

/**
* Create the application.
*/
public Login() {
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.getContentPane().setLayout(null);

status.setBounds(385, 235, 10, 10);
status.setForeground(Color.red);
frame.getContentPane().add(status);

JLabel lblLoginApplication = new JLabel("Login Application");
lblLoginApplication.setFont(new Font("Lucida Calligraphy", Font.BOLD, 20));
lblLoginApplication.setBounds(120, 25, 220, 30);
frame.getContentPane().add(lblLoginApplication);

JComboBox comboBox = new JComboBox(usecom);
comboBox.setBounds(230, 80, 110, 30);
comboBox.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
if (comboBox.getSelectedIndex() == 1 || comboBox.getSelectedIndex() == 2) {
lblNotConnected.setText("Connecting...");
try{
Thread.sleep(5000);
}catch(InterruptedException ex){
JOptionPane.showMessageDialog(null,ex.getMessage());
}
status.setForeground(Color.green);
lblNotConnected.setText("Connected");
JOptionPane.showMessageDialog(null, "Connected");
}
else{
status.setForeground(Color.red);
lblNotConnected.setText("Not Connected");
}
}
});
frame.getContentPane().add(comboBox);

JLabel lblSelectDatabase = new JLabel("Select Database");
lblSelectDatabase.setFont(new Font("Microsoft Sans Serif", Font.BOLD, 14));
lblSelectDatabase.setBounds(91, 79, 129, 30);
frame.getContentPane().add(lblSelectDatabase);

lblNotConnected = new JLabel("Not Connected");
lblNotConnected.setFont(new Font("Elephant", Font.PLAIN, 12));
lblNotConnected.setBounds(280, 230, 110, 20);
frame.getContentPane().add(lblNotConnected);
}


}

Answer

Code executed in a listener executes on the Event Dispatch Thread(EDT). When you use Thread.sleep() this causes the EDT to sleep which means the GUI can't repaint itself. Read the section from the Swing tutorial on Concurrency for more information.

Any potentially long running task should NOT execute on the EDT for the above reason. Instead you should use a separate Thread. Check out the SwingWorker from the above tutorial. You can use Thread.sleep() there and publish values to display as you wish.

However, why would you want the user to wait 5 seconds? I know I would get frustrated.

Maybe instead you should be using a ProgressMonitor to let the user know that you might be executing a long running task. Read the section from the Swing tutorial on How to Use Progress Bars for more information and working examples.

Comments