JLabel that changes text from one thing to another - java

I'm working on this program and I ran into another issue. I have a Jframe with a JLabel that I wish for it to change text from one thing to another. However, when I try to do that it doesnt show me the text changing, rather the last text I set it to.
How do I get my JLabel to cycle through text SLOWLY?
I'm trying a wait method to make the program go slowly so I can see if I can make it cycle through, but that doesnt seem to be working.
it would be helpful if someone could edit my code or make their own example of how to do this, THANKS!
public class CreditGraphics {
public String cardNum;
public JFrame frame;
public JPanel panel;
public JLabel label;
public JTextField text;
public CreditGraphics() {
synchronized(this){
try {
frame = new JFrame("HI");
panel = new JPanel();
label = new JLabel();
text = new JTextField(16);
panel.add(label);
panel.add(text);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.setPreferredSize(new Dimension(500, 500));
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
wait(4000);
label.setText("Hi");
wait(4000);
frame.revalidate();
frame.repaint();
label.setText("Hello");
frame.revalidate();
frame.repaint();
text.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cardNum = text.getText();
}
});
}
catch(InterruptedException e) {
e.printStackTrace();
}}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new CreditGraphics();
}
});
}
public void checkCard(){
}
}

As suggested by #trashgod use Swing Timer that is more suitable for swing application to perform a task once, after a delay or to perform a task repeatedly.
sample code:
private Timer timer;
...
label.setText("Hi");
// delay of 4 seconds
timer=new Timer(4000,new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
label.setText("Hello");
// timer.stop(); // stop the timer if repeated mode is on
}
});
timer.setRepeats(false); // you can turn-on it if needed
timer.start();
Note:
There is no need to call frame.repaint() and frame.revalidate() in this case.
Override getPreferredSize() to set the preferred size of the JPanel in case of custom painting.
sample code:
JPanel panel = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(..., ...);
}
};
read more...

Do not use Thread.sleep() or wait() as it will freeze your Swing application.
Instead you should use a javax.swing.Timer
See the Java tutorial How to Use Swing Timers and Lesson: Concurrency in Swing for more information and examples.

Related

How to refresh the Label one by one?

public class Test {
public static void main(String[] args) {
Methode met = new Methode();
JFrame f = new JFrame("Label Example");
JLabel l1;
JButton btn;
l1 = new JLabel("Start", SwingConstants.CENTER);
btn = new JButton("Bestätigen");
JPanel panel = new JPanel();
String comboBoxListe[] = { "1", "2", "3", "4", "5" }; // 1=300 2=250 3=200 4=150 5=100
JComboBox bundeslandAuswahl = new JComboBox(comboBoxListe);
panel.add(bundeslandAuswahl);
l1.setBounds(0, 0, 1800, 800);
l1.setFont(new Font("Serif", Font.PLAIN, 100));
btn.setBounds(800, 0, 100, 50);
panel.setBounds(900, 0, 100, 100);
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
met.ausgabe(l1);
}
});
f.add(btn);
f.add(l1);
f.add(panel);
f.setLayout(null);
f.setVisible(true);
f.setLocationRelativeTo(null);
f.setExtendedState(JFrame.MAXIMIZED_BOTH);
Timer t = new Timer();
}}
class Methode {
void ausgabe(JLabel l1) {
String temp = "";
String[] arr2 = { "Hallo", "World", "!" };
for (int i = 0; i < arr2.length; i++) {
temp = arr2[i];
l1.setText(temp);
try {
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
The Label only shows the last element of the Array, if i use the ActionListener. Without the btn.addActionListener its work. How can i solve it with a button? I want that when I click the method ausgabe, that the code displays step by step the individual array fields in the label.
Thanks
That happens because you have to repaint the component(l1). When you use graphic user interface in a single thread program, your program will run into a while block within the GUI code. So when the part of the code that is being executed is not yours then the program is working in GUI staff like repainting the window or graphic components.
You have to call a method in l1 to repaint it. That's the reason because the last text is the only showed. In that way a GUI code will be executed and your interface will be updated. If you do that your problem will be solved. Use the java documentation to find this method.
Start by looking at Concurrency in Swing for the reasons why this approach won't work and then How to Use Swing Timers for the solution.
The "core" issue is, Swing is single threaded and not thread safe. This means that when you call ausgabe from the ActionListener, you're trying to run a long running/blocking process within the context of the Event Dispatching Thread.
But, until the method exists, the EDT can not process any new paint or other events, so nothing gets updated until it's completed.
Because Swing is also not thread safe, it's not advisable to use a Thread to try and fix the issue. Instead, you should make use of a Swing Timer, which acts like a pseudo loop, but which is called back within the EDT, making it safe to use to update the UI.
For example...
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JLabel label;
private Timer timer;
private String text = "Hello World";
public TestPane() {
setLayout(new GridBagLayout());
label = new JLabel("");
add(label);
}
#Override
public void addNotify() {
super.addNotify();
if (timer != null) {
timer.stop();
timer = null;
}
timer = new Timer(1000, new ActionListener() {
private int counter;
#Override
public void actionPerformed(ActionEvent evt) {
if (counter >= text.length()) {
timer.stop();
timer = null;
}
label.setText(text.substring(0, counter));
counter += 1;
}
});
timer.setInitialDelay(1000);
timer.start();
}
#Override
public void removeNotify() {
super.removeNotify();
if (timer != null) {
timer.stop();
timer = null;
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
You should also take the time to learn how to use the various layout managers, it will save you a lot of time, hassle and head scratching.
See Laying Out Components Within a Container for more details.
One trick I might have used, would have been to use two labels. One with the full text set on it and with it's text color set the same color as the background of the panel, the second used to animate the update. Each positioned so that they will overlap each other.
This way, you provide enough information to the layout manager to make determinations about how much space the component needs.
In the above example, I just cheated and overrode getPreferredSize, again, this could have just calculated the final size of the label, but that's becoming complicated.

Extending variable scope from one frame to another frame

I have two JFrame based windows: SeatLayout and BillSummary. I need to get the seatnumber from the SeatLayout frame and display it in BillSummary but the variable scope is limited to the first frame.
How can I do this?
Using multiple JFrame is a bad practice and it should be avoided.
Reason being, it will add more problems in the future and it will be nightmare to maintain.
To answer your question , how to pass variable from your parent(JFrame) to a child(JDialog) .This can achive by using JDialog.
I am going to run through an example.
lets say, your BillSummary.java is ....
//BillSummary Class
public class billSummary {
JFrame frame;
billSummary(JFrame frame) {
this.frame = frame;
}
public void launchbillSummary(int seatNumber) {
// Create a dialog that suits your ui , you can use JPanel as your layout container
JDialog dialog = new JDialog(frame, "Bill Summary", true);
dialog.setLayout(new BorderLayout());
dialog.setSize(100, 100);
dialog.add(new JLabel(Integer.toString(seatNumber)), BorderLayout.CENTER);
dialog.setVisible(true);
}
}
Your seatLayout.java
public class seatLayout {
seatLayout(){
//Lets say you have seleted seat number 10
int defaultSeatNumber = 10;
//Lets say you have a button and when it is clicked , you pass the data to billsummary page
JButton enter = new JButton("Enter");
//Your seatLayout GUI
JFrame frame = new JFrame("seat layout");
frame.setSize(300,300);
frame.add(enter);
enter.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
//Do your passing of data/ price of calculation here
//You pass the data that to your custom dialog -> Bill summary
new billSummary(frame).launchbillSummary(defaultSeatNumber);
}
});
frame.setVisible(true);
}
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new seatLayout();
}
});
}
}
I hope this help and answers your question. Good luck :)

How to keep a component in the background window stay in focus?

In my program, I have this MAIN window and a HELP window. The HELP window (when opened) is to always stay on top whether it's in focus or not. The issue however is, when I try to requestFocusInWindow() for a component in the MAIN window through an action listener that gets fired from the HELP window, it just won't let me do it.
What is the proper way of accomplishing this?
TY :)
Edit:
As requested, here's a short example of what I'm trying to accomplish. Essentially I need the button inside the HELP window to trigger focus to the TextField inside the Main window.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Main {
public static void initGUI() {
mainFrame = new JFrame("Main");
helpFrame = new JFrame("Help");
mainFrame.setPreferredSize(new Dimension(500, 200));
helpFrame.setPreferredSize(new Dimension(500, 200));
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
helpFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setLayout(new FlowLayout());
helpFrame.setLayout(new FlowLayout());
mainTextView = new JTextField("", 20);
mainButton = new JButton("Open Help");
helpButton = new JButton("Request Focus");
mainButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource().equals(mainButton)) {
helpFrame.pack();
helpFrame.setVisible(true);
}
}
});
helpButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource().equals(helpButton))
System.out.println("Focus requested:" + mainTextView.requestFocusInWindow());
}
});
helpFrame.add(helpButton);
mainFrame.add(mainTextView);
mainFrame.add(mainButton);
mainFrame.pack();
mainFrame.setVisible(true);
}
public static void main(String[] args) {
initGUI();
}
static JFrame mainFrame, helpFrame;
static JTextField mainTextView;
static JButton mainButton, helpButton;
}
So turns out the fix was rather trivial. If requestFocus() is used instead of requestFocusInWindow(), it seems to work just fine.
Kinda feel stupid for how much time I spent on this :P
helpButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource().equals(helpButton))
mainTextView.requestFocus();
}
});

Timing the display of JPanels

I have an annoying issue with my desktop app that I am just unable to figure out. I have isolated the problem into the following example. What I am trying to do....
I have a jframe and 5 jpanels, each panel has a different picture. When launched, the user will see panel A with a button all inside my jframe. When the button is pressed I would like panel A to dissappear and panel B,C,D and E become visible after one another but each panel to be displayed for different lengths of time...
B visible for 3 secs, B invisible, C visible for 5 seconds, C invisible... and so on.
I have tried javax.Timer, Thread.sleep(3000) and even for statements and none seem to achieve what I want. How would you guys achieve this and what is the method I need to be looking at?
Thanks in advance.
Using a Swing Timer sounds like a reasonable approach. When the user clicks the JButton, show B and start the Timer, which should have an interval of 3 seconds. When the Timer fires, show C and change the Timer's interval to 5 seconds. When it fires again, show C and set the interval for however long you want to show C.
If that isn't working, please post an MCVE showing what you've tried, and we'll go from there.
Here I have done an example which shows:
How to use a Swing timer
How to add images on JLabel without freezing the program
Swapping the pics with the help of an timing array
After timer starts its starts changing :
My SSCCE:
/**
*
* #author rohan
*/
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class TestSwapPics {
public TestSwapPics() {
initComponents();
}
private void initComponents() {
JFrame f =new JFrame();
Panel = new javax.swing.JPanel();
Panel.setLayout(new BorderLayout(5,5));
jLabel1 = new javax.swing.JLabel();
jButton1 = new javax.swing.JButton();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
jLabel1.setIcon(new ImageIcon(getClass().getResource("/images.jpg")));
jButton1.setText("Start");
Panel.add(jLabel1, BorderLayout.NORTH);
Panel.add(jButton1, BorderLayout.SOUTH);
f.add(Panel);
f.pack();
f.setVisible(true);
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
startPicsChange();
}
private void startPicsChange() {
new Thread(new Runnable() {
#Override
public void run() {
Timer t = createAndStartTimer(timings[count],count);
while (t.isRunning()) {//wait for timer to be done
try {
Thread.sleep(1);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
count++;
if (count == timings.length) {
JOptionPane.showMessageDialog(null, "Done");
} else {
startPicsChange();
}
}
});
}
}).start();
}
private Timer createAndStartTimer(int delay, final int count) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
if(count==0)
jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/p3.PNG")));
if(count==1)
jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/p6.PNG")));
System.out.println("yes! reached here");
}
});
Timer t = new Timer(delay, new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
System.out.println("here 2!!");
}
});
t.setRepeats(false);
t.start();
return t;
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new TestSwapPics();
}
});
}
private JButton jButton1;
private JLabel jLabel1;
private JPanel Panel;
private int[] timings = {2000, 1000, 4000,5000,2000};
private int count=0;
}

problem with getting JFrame bounds inside a timer in Netbeans

I want to animate a JFrame to become half-size when i press a button in my programme. I think the easiest way is putting the current bounds of JFrame into a timer and decrease bounds 1 by 1 when the timer running.But when I declare a new timer in netbeans IDE it will looks like this.
Timer t = new Timer(5,new ActionListener() {
public void actionPerformed(ActionEvent e) {
//inside this I want to get my Jframe's bounds like this
// int width = this.getWidth();---------here,"this" means the Jframe
}
}
});
But the problem is in here "this" not refering to JFrame.And also I cant even create a new object of my JFrame.Because it will give me another window.Can anyone help me solve this problem ?.
Try
int width = Foo.this.getWidth();
where Foo subclasses JFrame.
I want to animate a JFrame to become half-size when i press a button in my programme
So when you click the button you have access to the button. Then you can use:
SwingUtilities.windowForComponent( theButton );
to get a reference to the frame.
So now when you create the ActionListener for the Timer you can pass in the Window as an argument for the ActionListener.
Edit:
The suggestion by mre is simple and straight forward and easy to use in many cases (and probably the better solution in this case).
My suggestion is a little more complicated but it was introducing you to the SwingUtilities method which will eventually allow you to write more reusable code that could potentially be used by any frame or dialog you might create.
A simple example would be something like:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class AnimationSSCCE extends JPanel
{
public AnimationSSCCE()
{
JButton button = new JButton("Start Animation");
button.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
JButton button = (JButton)e.getSource();
WindowAnimation wa = new WindowAnimation(
SwingUtilities.windowForComponent(button) );
}
});
add( button );
}
class WindowAnimation implements ActionListener
{
private Window window;
private Timer timer;
public WindowAnimation(Window window)
{
this.window = window;
timer = new Timer(20, this);
timer.start();
}
#Override
public void actionPerformed(ActionEvent e)
{
window.setSize(window.getWidth() - 5, window.getHeight() - 5);
// System.out.println( window.getBounds() );
}
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("AnimationSSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new AnimationSSCCE() );
frame.setSize(500, 400);
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
Of course you would want to stop the timer when the winow reaches a certain minimum size. I'll leave that code up to you.

Categories