JAVA GUI Label Output Error - java

import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Stock {
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Stock window = new Stock();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public Stock() {
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);
JLabel lblBrickStock = new JLabel("10");
lblBrickStock.setBounds(48, 62, 46, 14);
frame.getContentPane().add(lblBrickStock);
JButton btnNewButton = new JButton("Bricks");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int bricks = Integer.parseInt(lblBrickStock.getText());
bricks--;
if (bricks <= 10) {
lblBrickStock.setText(String.valueOf(bricks));
}
}
});
btnNewButton.setBounds(38, 28, 89, 23);
frame.getContentPane().add(btnNewButton);
}
}
I have created this stock program which is a prototype for a future program I am creating. What this program does is when you press the button the number in the label decreases. What I cannot do is that in the label I want it to say something like "10 remaining" and only for the number to decrease. It works with just the number but when I add the text I receive a whole host of errors. Any ways to work around or would I have to just use a separate label?

You can use a instance member counter to keep track of the number instead of getting the current values from the label text
public class Stock{
private int counter = 10;
...
}
And your action listener could be like :
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
counter--;
if (counter <= 10) {
lblBrickStock.setText(counter + " remaining");
}
}
});
That way, you don't have to parse the lblBrickStock.getText into a numeric value, and don't risk to get a parse exception if this is not a numeric value anymore.
Here is a small snipper showing how to use a variable in an anonymous inner class (the action listener)
public class TestFrame extends JFrame{
private int counter = 10;
public TestFrame(){
this.setTitle("Labo - TestFrame");
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.getContentPane().add(new JButton(new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(counter--);
}
}));
this.setVisible(true);
this.pack();
}
}
I clicked 3 times :
10
9
8

The problem is here:
int bricks = Integer.parseInt(lblBrickStock.getText());
you try to parse to Integer value with String inside. To avoid exception you can use: int bricks = Integer.parseInt(lblBrickStock.getText().replaceAll("\\D+",""));
but better idea would be static counter (as #AxelH mentioned in comment) instead of getting value from JLabel.

Related

I am trying to create a Java program that will make the letters appear one at a time in a JLabel

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
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).
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");
}
}
});

How do you get user input from a button using ActionListener? Java [duplicate]

I want to count the number of times the button is clicked using GUI.
I did this code:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
int clicked = 0;
clicked++;
System.out.println(clicked);
}
But it showing the output "1", each time I click the button.
I want every time I click the button to show me the count.
ex: If I click the button two times it should give me output of "2".
You are resetting the counter every time you click, because you have defined the variable inside the action method. Try not doing that.
int clicked = 0; // move this outside
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
// int clicked = 0; -- this resets it to 0 each time
clicked++;
System.out.println(clicked);
}
You've declared clicked as a local variable, initialised to 0, it can never be anything else but 1
Make clicked a class level variable instead...
private int clicked = 0;
//...
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
clicked++;
System.out.println(clicked);
}
Try below code
int clicked = 0;
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
clicked++;
System.out.println(clicked);
}
Change
int clicked = 0;
to be a member of your class. This way it wont be set to zero every time you press the button.
You have declared count variable inside the ActionListener. Declare it outside the block.
int clicked = 0; //make it as your class member.
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
clicked++;
System.out.println(clicked);
}
Depending on how you are instantiating this class you need to declare the clicked variable at either the field level or the class variable level. Currently, the scope of the clicked variable is local to the method.
Option 1
int clicked = 0;
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
clicked++;
System.out.println(clicked);
}
Option 2
static int clicked = 0;
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
clicked++;
System.out.println(clicked);
}
The option you use will depend on instantiation. The second option should be avoided if possible.
every time jButton1ActionPerformed fires, the clicked variables gets instantiated back to 0 that's why it is always giving you a value of 1. You should move the clicked variable outside of that method
//Somewhere in your class
private intClicked = 0;
//More methods here.
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
clicked++;
System.out.println(clicked);
}
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JTextField;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Threading extends JFrame {
private JPanel contentPane;
private JTextField DisplayOne;
private JTextField DisplayTwo;
int count;
int count1;
int count2;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run()
{
try {
Threading frame = new Threading();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Threading()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
JPanel panel = new JPanel();
contentPane.add(panel, BorderLayout.CENTER);
DisplayOne = new JTextField();
panel.add(DisplayOne);
DisplayOne.setColumns(10);
DisplayTwo = new JTextField();
panel.add(DisplayTwo);
DisplayTwo.setColumns(10);
JButton btnCountOne = new JButton("Count 1");
count1=0;
btnCountOne.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0)
{
DisplayOne.setText(Integer.toString(count1++));
}
});
panel.add(btnCountOne);
JButton btnCountTwo = new JButton("Count 2");
count2=0;
btnCountTwo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0)
{
DisplayTwo.setText(Integer.toString(count2++));
}
});
panel.add(btnCountTwo);
JButton btnCountBoth = new JButton("Count Both");
count=0;
btnCountBoth.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0)
{
while (count < 10)
{
DisplayOne.setText(Integer.toString(++count));
DisplayTwo.setText(Integer.toString(count));
}
}
});
panel.add(btnCountBoth);
}
}

Program not overwriting variable

I have a program which uses 3 radiobuttons to switch between 3 incrementing values for a counter, here time.
I want to change status when a radiobutton is pressed, and it does so, but only for a fraction. When launching the program will keep printing
0
Normal
2
Normal
4
Normal
6
etc. When I press the button slow it prints CHANGE Slow once but keeps incrementing with 2 and still prints Normal every time.
How can I have this permenently switch to a different value for status, and a different increment, until I choose another radiobutton again?
package daynightcycle;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
/**
* Day/night cycle with visuals. Adjustable speed and time inserts.
* Optional date or daycounter later
* #author rogie
*/
public class DayNightCycle extends JFrame implements Runnable{
//JFrame entities
private JPanel animationPanel;
public JRadioButton button;
public JRadioButton button2;
public JRadioButton button3;
public int time = 0;
public String status = "Normal";
public static void main(String[] args) {
DayNightCycle frame = new DayNightCycle();
frame.setSize(2000, 1300);
frame.setLocation(1000,350);
frame.createGUI();
frame.setVisible(true);
frame.setTitle("Day/Night Cycle, Rogier");
(new Thread(new DayNightCycle())).start();
}
private void createGUI() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
Container window = getContentPane();
window.setLayout(new FlowLayout() );
animationPanel = new JPanel();
animationPanel.setPreferredSize(new Dimension(2000, 900));
animationPanel.setBackground(Color.black);
window.add(animationPanel);
JRadioButton option1 = new JRadioButton("Slow");
JRadioButton option2 = new JRadioButton("Normal", true);
JRadioButton option3 = new JRadioButton("Fast");
option1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
System.out.println("CHANGE");
status = "Slow";
System.out.println(status);
}
});
option2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
status = "Normal";
}
});
option2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
status = "Fast";
}
});
//option2.setFont(new java.awt.Font("Tahoma", Font.BOLD, 30));
//option2.putClientProperty("JComponent.sizeVariant", "huge"); //doesn't work
ButtonGroup group = new ButtonGroup();
group.add(option1);
group.add(option2);
group.add(option3);
add(option1);
add(option2);
add(option3);
pack();
}
public void run() {
while(true){
System.out.println(time);
System.out.println(status);
try
{
Thread.sleep(500);
if (status.equals("Slow")) {
time += 1;
}
else if (status.equals("Normal")){
time += 2;
}
else {
time += 3;
}
}
catch(InterruptedException ex)
{
Thread.currentThread().interrupt();
}
}
}
}
You are creating to DayNightCycle-Objects, the first shows the GUI and the second prints on the console.
Change the line
(new Thread(new DayNightCycle())).start();
to
(new Thread(frame)).start();
public static void main(String[] args) {
final DayNightCycle frame = new DayNightCycle();
frame.setSize(2000, 1300);
frame.setLocation(1000,350);
frame.createGUI();
frame.setTitle("Day/Night Cycle, Rogier");
And then
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
frame.setVisible(true);
}
});
Or in java 8:
EventQueue.invokeLater(() -> frame.setVisible(true));
}
You in effect created a second DayNightCycle.

Not getting value from JSlider

I am using a JSlider in my program, and have implemented a ChangeListener for the same.
public void stateChanged(ChangeEvent e)
{
JSlider source=(JSlider) e.getSource();
frame_value.setText(Integer.toString(source.getValue()));
//Condition to change the frame_no only when user has stopped moving the slider
if (!source.getValueIsAdjusting())
{
frame_no=(int) source.getValue()-1;
if(frame_no<0)
frame_no=0;
}
....
}
What is happening is, that whenever the ChangeListener is called, the program just skips the if block, and goes to the code after that. I don't understand why is this happening. I am not able to get the correct value from the JSlider. Please help!!
PS: I don't know if this is the reason, but recently I have set the UI of the JSlider to place the tick where I click it. I don't know if that is responsible for it or not. Here is the code:
slider.setUI(new MetalSliderUI() {
protected void scrollDueToClickInTrack(int direction) {
int value = HEVC_Analyzer.slider.getValue();
value = this.valueForXPosition(HEVC_Analyzer.slider.getMousePosition().x);
HEVC_Analyzer.slider.setValue(value);
}
});
Must be something wrong in your code, since it's working fine in this example :
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class SliderChangeEffect extends JFrame
{
private JSlider slider;
private int count = 0;
private ChangeListener changeListener = new ChangeListener()
{
public void stateChanged(ChangeEvent ce)
{
JSlider slider = (JSlider) ce.getSource();
if (!slider.getValueIsAdjusting())
System.out.println(slider.getValue());
}
};
private void createAndDisplayGUI()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationByPlatform(true);
JPanel contentPane = new JPanel();
contentPane.setOpaque(true);
slider = new JSlider(0, 10, 5);
slider.setMajorTickSpacing(2);
slider.setMinorTickSpacing(1);
slider.addChangeListener(changeListener);
contentPane.add(slider);
getContentPane().add(contentPane);
pack();
setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new SliderChangeEffect().createAndDisplayGUI();
}
});
}
}
Just use the String.valueOf() and the event.MouseReleased().
private void jSlider1MouseReleased(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
try {
String valueOf = String.valueOf(jSlider1.getValue());
jLabel1.setText(valueOf);
} catch (Exception ex) {
ex.printStackTrace();
}
}

JLabel displaying countdown, java

I've got a "status" JLabel in one class (named Welcome) and the timer in another one (named Timer). Right now, the first one displays the word "status" and the second one should be doing the countdown. The way I would like it to be, but don't know how to - display 10, 9, 8, 7 ... 0 (and go to the next window then). My attempts so far:
// class Welcome
setLayout(new BorderLayout());
JPanel area = new JPanel();
JLabel status = new JLabel("status");
area.setBackground(Color.darkGray);
Font font2 = new Font("SansSerif", Font.BOLD, 25);
status.setFont(font2);
status.setForeground(Color.green);
area.add(status, BorderLayout.EAST); // can I put it in the bottom-right corner?
this.add(area);
and the timer:
public class Timer implements Runnable {
// public void runThread() {
// new Thread(this).start();
// }
public void setText(final String text) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
setText(text); // link to status here I guess
}
});
}
public void run() {
for (int i = 10; i > 0; i--) {
// set the label
final String text = "(" + i + ") seconds left";
setText(text);
// // sleep for 1 second
// try {
// Thread.currentThread();
// Thread.sleep(1000);
// } catch (Exception ex) {
// }
}
// go to the next window
UsedBefore window2 = new UsedBefore();
window2.setVisible(true);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
// runThread();
}
} // end class
I agree that you should consider using a "Java" Timer as per Anh Pham, but in actuality, there are several Timer classes available, and for your purposes a Swing Timer not a java.util.Timer as suggested by Anh would suit your purposes best.
As for your problem, it's really nothing more than a simple problem of references. Give the class with the label a public method, say setCountDownLabelText(String text), and then call that method from the class that holds the timer. You'll need to have a reference of the GUI class with the timer JLabel in the other class.
For example:
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Welcome extends JPanel {
private static final String INTRO = "intro";
private static final String USED_BEFORE = "used before";
private CardLayout cardLayout = new CardLayout();
private JLabel countDownLabel = new JLabel("", SwingConstants.CENTER);
public Welcome() {
JPanel introSouthPanel = new JPanel();
introSouthPanel.add(new JLabel("Status:"));
introSouthPanel.add(countDownLabel);
JPanel introPanel = new JPanel();
introPanel.setPreferredSize(new Dimension(400, 300));
introPanel.setLayout(new BorderLayout());
introPanel.add(new JLabel("WELCOME", SwingConstants.CENTER), BorderLayout.CENTER);
introPanel.add(introSouthPanel, BorderLayout.SOUTH);
JPanel usedBeforePanel = new JPanel(new BorderLayout());
usedBeforePanel.setBackground(Color.pink);
usedBeforePanel.add(new JLabel("Used Before", SwingConstants.CENTER));
setLayout(cardLayout);
add(introPanel, INTRO);
add(usedBeforePanel, USED_BEFORE);
new HurdlerTimer(this).start();
}
private static void createAndShowUI() {
JFrame frame = new JFrame("Welcome");
frame.getContentPane().add(new Welcome());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
public void setCountDownLabelText(String text) {
countDownLabel.setText(text);
}
public void showNextPanel() {
cardLayout.next(this);
}
}
class HurdlerTimer {
private static final int TIMER_PERIOD = 1000;
protected static final int MAX_COUNT = 10;
private Welcome welcome; // holds a reference to the Welcome class
private int count;
public HurdlerTimer(Welcome welcome) {
this.welcome = welcome; // initializes the reference to the Welcome class.
String text = "(" + (MAX_COUNT - count) + ") seconds left";
welcome.setCountDownLabelText(text);
}
public void start() {
new Timer(TIMER_PERIOD, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (count < MAX_COUNT) {
count++;
String text = "(" + (MAX_COUNT - count) + ") seconds left";
welcome.setCountDownLabelText(text); // uses the reference to Welcome
} else {
((Timer) e.getSource()).stop();
welcome.showNextPanel();
}
}
}).start();
}
}
Since you're using Swing you should use the javax.swing.Timer, not the java.util.Timer. You can set the timer to fire at 1 second (1000 ms) intervals and have your listener do the updating. Since Swing updates must take place in the event dispatch thread your listener is the perfect place for status.setText.
there's already a Timer class in java: http://www.exampledepot.com/egs/java.util/ScheduleRepeat.html
Why not put the setText method in the welcome class and just do 'status.setText(text)'?
And you might try BorderLayout.SOUTH or .PAGE END or .LINE END to get the timer in the lower right corner

Categories