Reputation: 1
I am trying to create a program in java that makes the letters of a string appear one at a time into a JLabel, but the text just appears all at once every time. The more the delay on the Thread.Sleep();, the longer it takes to appear. I think what is happening is that it is writing it all out and then printing it into the Label, but i still don't know what to do to fix it. The code is here:
package uiTesting;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.AbstractButton;
import javax.swing.JButton;
import java.awt.Font;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
public class ScrollingText extends JFrame {
private JPanel contentPane;
//Variables and values
public static String ThingToBePrinted = "You look down the gigantic hallway, the cold breath of spirits breathing down your neck. "
+ "Its nothing you haven't felt before. The spirits of those long past were always closer here, where many of them met"
+ " their end. Maybe you would be one of them, someday. But not today. Today, there was still too much to be done to rest.";
public static String ThingPrinted = "";
public static int Mili = 100;
public String html1 = "<html><body style='width: ";
public String html2 = "px'>";
/**
* Launch the application.
*/
public static void main(String[] args) {
System.out.println(ThingToBePrinted.length());
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ScrollingText frame = new ScrollingText();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public ScrollingText() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 719, 504);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
//The only Label
JLabel Scrolling_L1 = new JLabel("");
Scrolling_L1.setFont(new Font("Tahoma", Font.PLAIN, 15));
Scrolling_L1.setVerticalAlignment(SwingConstants.TOP);
Scrolling_L1.setBounds(10, 11, 693, 354);
contentPane.add(Scrolling_L1);
//The only Button
JButton Master_B1 = new JButton("Print Text");
Master_B1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
try {
//scrolling function
for (int i = 0; i < ThingToBePrinted.length(); i++) {
String x = String.valueOf(ThingToBePrinted.charAt(i));
ThingPrinted = ThingPrinted + x;
Scrolling_L1.setText(html1 + "500" + html2 + ThingPrinted); //Html for wrapping text
Thread.sleep(Mili); //Delay between letters
}
}catch (Exception e){
JOptionPane.showMessageDialog(null, "Error");
}
}
});
Master_B1.setFont(new Font("Tahoma", Font.PLAIN, 25));
Master_B1.setBounds(164, 385, 375, 70);
contentPane.add(Master_B1);
}
}
I would really appreciate any solution at this point, I've been troubleshooting for hours
Upvotes: 0
Views: 56
Reputation: 329
It is because you are updating the JLabel in the UI thread itself from the event handler. Better way is to start a new thread in the event handler and then update the JLabel from this new thread. Following is the section you need to use in your code. I have tested it, it works.
Master_B1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
try { // Start new thread here for updating JLabel.
new Thread() {
public void run() {
//scrolling function
for (int i = 0; i < ThingToBePrinted.length(); i++) {
String x = String.valueOf(ThingToBePrinted.charAt(i));
ThingPrinted = ThingPrinted + x;
Scrolling_L1.setText(html1 + "500" + html2 + ThingPrinted); //Html for wrapping text
try {
Thread.sleep(Mili); // Delay between letters
} catch (Exception e) {
}
}
}
}.start();
}catch (Exception e){
JOptionPane.showMessageDialog(null, "Error");
}
}
});
Upvotes: 1
Reputation: 44891
Your problem is related to how concurrency works in Swing. One (imperfect) solution is to use a SwingWorker. You could change your action listener to this:
Master_B1.addActionListener(event -> {
SwingWorker<Object, Void> worker = new SwingWorker<Object, Void>() {
@Override
protected String doInBackground() throws InterruptedException {
for (int i = 0; i < ThingToBePrinted.length(); i++) {
ThingPrinted += ThingToBePrinted.charAt(i);
Scrolling_L1.setText(html1 + "500" + html2 + ThingPrinted); // Html for wrapping text
Thread.sleep(Mili); //Delay between letters
}
return null;
}
};
worker.execute();
});
Read this tutorial: Lesson: Concurrency in Swing to get a better understanding of the topic. (You might want to read up on concurrency in Java in general also, see this tutorial for example).
Upvotes: 1