Timer cannot stop (maybe the GUI error) - java

I'm trying to create animation for a traffic light simulation that uses a timer. There is a button to stop the simulation, but clicking it does not seem to affect the animation. I did check in the animation but the animation seem like different places. Please help.
In the main class:
DataModels dm = new DataModels();
Simulation sm = new Simulation(dm);
sm.go();
Here is the simulation class:
public class Simulation extends JPanel implements ActionListener {
DataModels dm;
Timer tm = new Timer(20, this);
private boolean ss = false;
public Simulation(DataModels dm) {
this.dm = dm;
// redLightTime= dm.getRedLight()*1000;
}
public void go() {
sm = new Simulation(dm);
simulation = new JFrame();
simulation.setTitle("Traffic light and Car park Siumulation");
simulation.setSize(800, 700);
simulation.setResizable(false);
simulation.setVisible(true);
simulation.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
simulation.add(sm, BorderLayout.CENTER);
// Command button panel
JPanel command = new JPanel();
command.setPreferredSize(new Dimension(800, 100));
// Pause or play button
JButton pauseplayB = new JButton("Pause");
pauseplayB.setSize(new Dimension(50, 50));
pauseplayB.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Execute when button is pressed
ss = true;
System.out.println("You clicked the button");
}
});
command.add(pauseplayB);
JButton stopB = new JButton("Stop");
JButton saveB = new JButton("Save");
command.setLayout(new GridLayout(1, 1));
command.add(stopB);
command.add(saveB);
simulation.add(command, BorderLayout.SOUTH);
}
Now paintComponent will change based on timer change. The following code is also in the Simulation class.
public void paintComponent(Graphics g) {
// Many other actions
// ....
startAnimation();
}
public void startAnimation() {
if ( !false) {
tm.start();
} else {
tm.stop();
}
// Checking button click
System.out.println(ss);
}
According to the console output, the ss value never changes.

The button's action listener should call the function to stop the timer somehow and not rely on the paint event to do it.
EDIT: Here is some code :)
public void actionPerformed(ActionEvent e) {
// Execute when button is pressed
ss = true;
System.out.println("You clicked the button");
startAnimation();
}
And the startAnimation method should have if(!ss) instead of if(!false)

In addition to JTMon's suggestion, your startAnimation method contains a logic bomb
public void startAnimation() {
if ( !false) { //<-- this will ALWAYS be true
tm.start();
} else {
tm.stop();
}
// Checking button click
System.out.println(ss);
}
The if statement that controls the timer will ALWAYS try & start the timer

Related

Stop code execution until button is pressed

After choose.setVisible(true) I would like first
to be able to choose and after pressing the ok button
to continue execution.
The below code shows the chooser and continues
without waiting.
static class box extends JFrame {
Checkbox cboxtps = new Checkbox("Grf1", false);
Checkbox cboxrspt = new Checkbox("Grf2", false);
JLabel lblQts = new JLabel("Please select graphs");
JButton btn1 = new JButton("Go");
public box(String str) {
super(str);
setLayout(new GridLayout(4, 1));
add(lblQts);
add(cboxtps);
add(cboxrspt);
add(btn1);
btn1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
//Execute when button is pressed
System.out.println("You clicked the button");
}
});
}
}
public static void main(String args[]) {
box choose = new box("Select Graphs");
choose.setSize(300, 150);
choose.pack();
choose.setVisible(true);
List<File> filepaths = fileselect();
list = Splitter(filepaths);
}
Since you are working asynchronously here, you would have to put the code after choose.setVisible(true) into the actionPerformed callback like so:
public void actionPerformed(ActionEvent e)
{
System.out.println("You clicked the button");
List<File> filepaths = fileselect();
list = Splitter(filepaths);
}
In general, when working with a lot of callbacks it is the best to define helper functions to avoid deep nesting.

JDialog opening very slow

I'm having some problems while working on a project for school. The JDialog renders very slow. Let me show you.
This is the GUI:
When I click "Advance time" it takes around 3 seconds to open the JDialog. When it's open I get this (which is fine):
But when I drag that JDialog around, I get this (which is not ok):
It also takes very long to close the JDialog. It closes, but you can still see it:
This is the snippet of code where I think the problem lays, it's the code for the menu-bar:
private JMenu editMenu()
{
JMenu editMenu = new JMenu("Edit");
editMenu.setMnemonic(KeyEvent.VK_E);
JMenuItem advanceTimeMenuItem = new JMenuItem("Advance time");
advanceTimeMenuItem.setMnemonic(KeyEvent.VK_A);
advanceTimeMenuItem.setToolTipText("Advance the internal clock");
advanceTimeMenuItem.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent event)
{
//We first create panel to add to the dialog.
JPanel panel = new JPanel();
//Calendar
AdvanceTimePanel calendar = new AdvanceTimePanel(internalClockController);
//Button that will be used to confirm the system time change.
JButton btnSave = new JButton("Save");
//Add actionlistener to the save button
btnSave.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e)
{
Date selectedDate = calendar.getDate();
try
{
internalClockController.updateDateTime(selectedDate);
} catch (InvalidInternalClockException e1)
{
System.out.println("InvalidInternalClockException: " + e1.getMessage());
}
}
});
//Add the components to the panel.
panel.add(btnSave);
//This is the calendar added to the panel.
panel.add(calendar);
//Create the dialog and add the panel to it.
JDialog jDialog = new JDialog();
jDialog.add(panel);
jDialog.setBounds(100, 100, 400, 200);
jDialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
jDialog.setVisible(true);
}
});
editMenu.add(advanceTimeMenuItem);
Does someone have an idea how to speed things up?
Thanks in advance.
Events are handled on one single thread. (Also repaint events.) For the application to remain
responsive, perform longer actions a bit later by using invokeLater, as below:
#Override
public void actionPerformed(ActionEvent event)
{
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
... // All code here
}
});
}
This is quite wordy; Java 8 allows:
advanceTimeMenuItem.addActionListener(
(event) -> {
EventQueue.invokeLater(
() -> {
... // All code
});
});

Java moving back and forth between content in runnable Jar file

I'm quite new to programming so I don't know the right way to do things and have been just experimenting a bit. I want to create a runnable where I can move back and forth between different content. The following works when run from inside eclipse, but if I export it as a JAR file, once I've moved forward once and then back again, moving forward won't give me the content anymore, but just the back button.
I tried something like this:
public class TestMain extends JFrame {
static PanelClass panel;
static boolean inUse = false;
public static void main(String[] args) {
panel = new PanelClass();
final TestMain test = new TestMain();
final Container container = test.getContentPane();
container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS));
test.setSize(500, 500);
final JButton back = new JButton("Back");
back.setAlignmentX(Component.CENTER_ALIGNMENT);
back.setMaximumSize(new Dimension(200, 80));
back.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
test.getContentPane().removeAll();
test.setContentPane(container);
test.getContentPane().revalidate();
}
});
final JButton exit = new JButton("Exit");
exit.setAlignmentX(Component.CENTER_ALIGNMENT);
exit.setMaximumSize(new Dimension(200, 80));
exit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
JButton problem = new JButton("Problem");
problem.setMaximumSize(new Dimension(200, 80));
problem.setAlignmentX(Component.CENTER_ALIGNMENT);
problem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
inUse = true;
test.setContentPane(panel);
test.getContentPane().add(back);
test.getContentPane().revalidate();
}
});
container.add(problem);
container.add(exit);
test.setVisible(true);
test.setDefaultCloseOperation(EXIT_ON_CLOSE);
test.setLocationRelativeTo(null);
while (true) {
while (!panel.stop && !inUse) {
}
inUse = false;
panel = new PanelClass();
test.setContentPane(panel);
test.getContentPane().add(back);
test.getContentPane().revalidate();
}
}
}
And the class for what I want to have as the second content:
public class PanelClass extends JPanel {
JTextArea text = new JTextArea("Some text here!" + '\n' + '\n');
JButton button1 = new JButton("Button 1");
JButton button2 = new JButton("Button 2");
boolean stop = false;
public PanelClass() {
text.setEditable(false);
text.setMaximumSize(new Dimension(300, 300));
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
Dimension d = new Dimension(200, 60);
button1.setAlignmentX(Component.CENTER_ALIGNMENT);
button1.setMaximumSize(d);
button2.setAlignmentX(Component.CENTER_ALIGNMENT);
button2.setMaximumSize(d);
this.add(text);
this.add(button1);
this.add(button2);
}
}
What is the actual working way to do this? What if I have a lot of windows I'd like to be able to move back and forth between? I know it's a lot of bad/possibly-hard-to-read code, but I hope someone could help me out.
This is the code that runs when you press "Problem":
test.setContentPane(panel);
test.getContentPane().add(back);
test.getContentPane().revalidate();
and this is the code that runs when you press "Back":
test.getContentPane().removeAll();
test.setContentPane(container);
test.getContentPane().revalidate();
What is the sequence of calls when you press "Problem" then "Back" then "Problem"? It's this. (The revalidate() calls won't mess anything up, so I won't show them)
// Problem
test.setContentPane(panel);
test.getContentPane().add(back);
// Back
test.getContentPane().removeAll();
test.setContentPane(container);
// Problem
test.setContentPane(panel);
test.getContentPane().add(back);
Notice that you set the panel as the content pane, and then remove all the components from it when "Back" is pressed. The next time you press "Problem", the panel has no components on it, because you removed them.
did you try exporting as a runnable jar and choose package required libraries into generated jar when you exported as JAR from eclipse?

JProgressBar - Won't work in the class that I am calling it in

I'm making a project and need a progress bar. I've got the class with the Timer and it runs fine when I include a main; but when I try to call it in the mainGUI method, it's all black until it hits 100% then appears.
package microproject.resources;
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class Timer extends JFrame {
JProgressBar current;
JTextArea out;
JButton find;
Thread runner;
int num = 0;
int length = 0;
public Timer() {
setTitle("Progress");
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
length = Integer.parseInt(JOptionPane.showInputDialog(null, "How many seconds:"));
JPanel p = new JPanel(new GridLayout(1,1));
p.setPreferredSize(new Dimension(300,65));
current = new JProgressBar(0, length);
current.setPreferredSize(new Dimension(250,50));
current.setValue(0);
current.setStringPainted(true);
p.add(current);
setVisible(true);
setContentPane(p);
pack();
setVisible(true);
iterate();
}
public void iterate() {
while(num < length +1) {
current.setValue(num);
try {
Thread.sleep(1000);
} catch(InterruptedException e) {}
num += 1;
}
}
public static void main(String[] args) {
Timer f = new Timer();
}
}
This is the code for the Timer Class ^
package microproject.resources;
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class GUIMain extends JFrame {
public static void main(String []args){
GuiFrame();
}
public static void GuiFrame(){
JFrame frame = new JFrame("Casino Royal3");
frame.setSize(811,577);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(2,1));
frame.setResizable(false);
JPanel PNorth = new JPanel(new FlowLayout(FlowLayout.LEFT,0,0));
JPanel PSouth = new JPanel(new BorderLayout());
//Creating Image for Casino Button
ImageIcon img1 = new ImageIcon("src\\Casino.jpg");
final JButton btn1 = new JButton(img1);
btn1.setPreferredSize(new Dimension(550,274));
btn1.setMargin(new Insets(0,0,0,0));
PNorth.add(btn1, BorderLayout.EAST);
btn1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
btn1.setIcon(new ImageIcon("src\\Casino2.jpg"));
}
});
//Creating Image for Sheridan Label
ImageIcon img2 = new ImageIcon("src\\SHERIDAN_LOGO.jpg");
JButton btn2 = new JButton(img2);
btn2.setMargin(new Insets(0,0,0,0));
PNorth.add(btn2);
btn2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ImageIcon instruc = new ImageIcon("src\\Instructions.jpg");
JLabel instructions = new JLabel(instruc);
JOptionPane.showConfirmDialog(null, instructions, "instructions", JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE);
}
});
JPanel timmus = new JPanel(new FlowLayout(FlowLayout.LEFT,0,0));
timmus.setPreferredSize(new Dimension(166, 273));
timmus.setBackground(Color.BLUE);
ImageIcon time = new ImageIcon("src\\Timer.jpg");
JButton timer = new JButton(time);
timer.setMargin(new Insets(0,0,0,0));
timer.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Timer f = new Timer();
}
});
timmus.add(timer);
ImageIcon mus = new ImageIcon("src\\music.jpg");
JButton music = new JButton(mus);
music.setMargin(new Insets(0,0,0,0));
timmus.add(music);
JPanel games = new JPanel(new FlowLayout(FlowLayout.LEFT,0,0));
games.setPreferredSize(new Dimension(500,279));
games.setBackground(Color.BLUE);
ImageIcon calculator = new ImageIcon("src\\Calculator.jpg");
JButton calc = new JButton(calculator);
calc.setMargin(new Insets(0,0,0,0));
calc.setPreferredSize(new Dimension(166,273));
games.add(calc);
calc.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Calculator c1 = new Calculator();
}
});
ImageIcon g1 = new ImageIcon("src\\250Hangman.jpg");
JButton game1 = new JButton(g1);
//game1.setBackground(Color.WHITE);
game1.setMargin(new Insets(0,0,0,0));
game1.setPreferredSize(new Dimension(166,273));
games.add(game1);
game1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Hangman h1 = new Hangman();
}
});
ImageIcon g2 = new ImageIcon("src\\Minesweeper.jpg");
JButton game2 = new JButton(g2);
// game2.setBackground(Color.WHITE);
game2.setMargin(new Insets(0,0,0,0));
game2.setPreferredSize(new Dimension(166,273));
games.add(game2);
PSouth.add(timmus, BorderLayout.CENTER);
PSouth.add(games, BorderLayout.EAST);
frame.add(PNorth, BorderLayout.NORTH);
frame.add(PSouth, BorderLayout.SOUTH);
frame.setVisible(true);
frame.pack();
}
}
That's the entire program, the Timer ActionListener is called "timer"
Thanks in advance
Welcome to the wonderful world of blocked Event Dispatching Thread (and violation of the initial thread)
Basically, Swing is a single threaded environment, all updates and modifications to the UI are expected to be executed within the context of the Event Dispatching Thread (AKA EDT).
The EDT is responsible for, amongst other things, processing repaint requests. If, for some reason, you block this thread (for example, using a long running loop or blocking IO), it will prevent the EDT from processing new paint requests, making it appear as if your program has hung...because essentially it has.
The reason you might see a difference between running Timer directly and using it in your GUI is because when the application is started, it will be running within, what is commonly known as, the "main" thread.
When you first create a top level Swing container, the EDT is started (which is a separate thread), meaning that the UI will appear in it's own thread, but the application will continue running in the "main" thread, allowing your iterate method to run independently of the EDT.
However, when you try and run it from within your GUI, it's all running within the context of the EDT, causing it to be blocked.
Start by taking a look at
Concurrency in Swing
Initial Threads
To fix the problem, based on your example code, I would suggest using a SwingWorker. This will allow you to run your "long running task" in a background thread, but provides a number of methods that allow you to resync your updates back to the EDT. This is very important, as you should never attempt to update the UI or change it's state from any thread other then the EDT.
Take a look at Worker Threads and SwingWorker for more details
And if required, some examples...
JProgressBar not updating
JProgressBar too fast
JProgressBar won't update
Progress Bar Java

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