I am trying to create a slideshow with Java Swing.
I began with implementing a class PicturePanel
public class PicturePanel extends JPanel {
private int counter = 0;
private ImageIcon[] images = new ImageIcon[10];
private JLabel label;
public PicturePanel()
{
for(int i = 0 ; i <images.length;i++)
{
images[counter] = new ImageIcon("check.png");
label = new JLabel();
add(label);
Timer timer = new Timer(100, new TimerListener());
}
}
private class TimerListener implements ActionListener {
public TimerListener() {
}
#Override
public void actionPerformed(ActionEvent ae) {
counter++;
//counter% =images.length;
label.setIcon(images[counter]);
}
}
}
Then I am calling this class in my Jframe through this code :
panProfil= new PicturePanel();
panProfil is a Jpanel in my form
When I run my project, I don't get any errors, but there is nothing in my form. Can someone point me in the right direction?
So you haven't started your Timer that's the problem (as #ItachiUchiha pointed out). But another thing you need to do is know when to stop() the Timer or else it will keep running
You want to start() it in the constructor after you create the Timer. In you ActionListener, to stop it, you'll want to do something like this.
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent ae) {
if (counter == images.length) {
((Timer)e.getSource()).stop();
} else {
label.setIcon(images[counter]);
counter++;
}
}
}
If you want to access the Timer from your main GUI class, so you can control it, you want to have a getter for it, and declare it globally
public class PicturePanel extends JPanel {
private Timer timer = null;
public PicturePanel() {
timer = new Timer(1000, new TimerListener());
}
public Timer getTimer() {
return timer;
}
}
Then you can start and stop it from your main GUI class
DrawPanel panel = new DrawPanel();
Timer timer = panel.getTimer();
Also, I don't see the point of create a JLabel every iteration and adding it to the JPanel. You only need one.
public class Project2 {
int c=0;
public static void main(String arg[]) throws InterruptedException {
JFrame login = new JFrame("Login");
// creating a new frame
login.setSize(700, 500);
JPanel addPanel = new JPanel();
JLabel pic = new JLabel();
Project2 p2= new Project2();
String[] list = {"C:\\Users\\divyatapadia\\Desktop\\pic1.jpg", "C:\\Users\\divyatapadia\\Desktop\\benefit.PNG" , "C:\\Users\\divyatapadia\\Desktop\\pic2.jpg"};
pic.setBounds(40, 30, 500, 300);
JButton log = new JButton("SHOW");ImageIcon[] img = new ImageIcon[3];
for(int time = 0;time<3;time++) {
img[time]= new ImageIcon(list[time]);
}
addPanel.add(pic);
addPanel.add(log);
login.add(addPanel);
login.setVisible(true);
try {
log.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Timer t ;
t= new Timer(1000,new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(p2.c<3) {
pic.setIcon(img[p2.c]);
p2.c++;
}}
});
t.start();
}
}
);
}catch(Exception ex)
{
System.out.println(ex.toString());
}
}
}
Related
I am printing simple value to append JTextArea using simple for loop, and when I run it, it's properly Run if I print value in console output...
But if I append JTextArea and print value in the text area, they are appended all after whole program run.
public class SwingThread {
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
SwingThread window = new SwingThread();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public SwingThread() {
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);
JScrollPane scrollPane = new JScrollPane();
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
JTextArea textArea = new JTextArea();
scrollPane.setViewportView(textArea);
JButton btnNewButton = new JButton("New button");
scrollPane.setColumnHeaderView(btnNewButton);
btnNewButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
try
{
for(int i = 0 ; i <= 5 ; i++)
{
textArea.append("Value "+i+"\n");
System.out.println("Value is" + i);
Thread.sleep(1000);
}
}
catch(Exception e)
{
System.out.println("Error : "+e);
}
}
});
}
}
I want to append one by one, but it was appended after the whole program runs.
Your problem is with your use of Thread.sleep, since when you call this on the Swing event thread (or EDT for Event Dispatch Thread) as you are doing, it will put the entire Swing event thread to sleep. When this happens the actions of this thread cannot be performed, including painting the GUI (updating it) and interacting with the user, and this will completely freeze your GUI -- not good. The solution in this current situation is to use a Swing Timer as a pseudo-loop. The Timer creates a loop within a background thread and guarantees that all code within its actionPerformed method will be called on the Swing event thread, a necessity here since we don't want to append to the JTextArea off of this thread.
Also as others have noted, if all you want to do is to perform a repeated action with delay in Swing, then yes, use this Swing Timer. If on the other hand you wish to run a long-running bit of code in Swing, then again this code will block the EDT and will freeze your program. For this situation use a background thread such as one supplied by a SwingWorker. Please check out Lesson: Concurrency in Swing for more on this.
e.g.,
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
// delay between timer ticks: 1000
int timerDelay = 1000;
new Timer(timerDelay, new ActionListener() {
private int counter = 0;
#Override
public void actionPerformed(ActionEvent e) {
// timer's stopping condition
if (counter >= MAX_VALUE) { // MAX_VALUE is a constant int = 5
((Timer) e.getSource()).stop();
} else {
textArea.append("Value " + counter + "\n");
}
counter++; // increment timer's counter variable
}
}).start();
}
});
The whole thing:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.*;
import javax.swing.*;
public class SwingThread2 {
protected static final int MAX_VALUE = 5; // our constant
private JFrame frame;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
SwingThread2 window = new SwingThread2();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public SwingThread2() {
initialize();
}
private void initialize() {
frame = new JFrame();
// frame.setBounds(100, 100, 450, 300); // avoid this
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JScrollPane scrollPane = new JScrollPane();
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
JTextArea textArea = new JTextArea(15, 40);
scrollPane.setViewportView(textArea);
JButton btnNewButton = new JButton("New button");
scrollPane.setColumnHeaderView(btnNewButton);
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
// delay between timer ticks: 1000
int timerDelay = 1000;
new Timer(timerDelay, new ActionListener() {
private int counter = 0;
#Override
public void actionPerformed(ActionEvent e) {
// timer's stopping condition
if (counter >= MAX_VALUE) { // MAX_VALUE is a constant int = 5
((Timer) e.getSource()).stop();
} else {
textArea.append("Value " + counter + "\n");
}
counter++; // increment timer's counter variable
}
}).start();
}
});
// better to avoid setting sizes but instead to
// let the components size themselves vis pack
frame.pack();
frame.setLocationRelativeTo(null);
}
}
Just for further information, here is an example of the same program above that uses a SwingWorker to perform a long running action, and then update a JProgressBar with this action. The worker is quite simple, and simply uses a while loop to advance a counter variable by a bounded random amount. It then transmits uses this value to update its own progress property (a value that can only be from 0 to 100, and so in other situations, the value will need to be normalized to comply with this). I attach a PropertyChangeListener to the worker, and this is notified on the Swing event thread whenever the worker's progress value changes and also whenever the SwingWorker changes state, such as when it is done operating. In the latter situation, the worker's StateValue becomes StateValue.DONE. The listener then updates the GUI accordingly. Please ask if any questions.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
public class SwingThread2 {
protected static final int MAX_VALUE = 5; // our constant
private JFrame frame;
private JProgressBar progressBar = new JProgressBar();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
SwingThread2 window = new SwingThread2();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public SwingThread2() {
initialize();
}
private void initialize() {
frame = new JFrame();
// frame.setBounds(100, 100, 450, 300); // avoid this
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JScrollPane scrollPane = new JScrollPane();
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
JTextArea textArea = new JTextArea(15, 40);
scrollPane.setViewportView(textArea);
JButton btnNewButton = new JButton("New button");
scrollPane.setColumnHeaderView(btnNewButton);
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
// delay between timer ticks: 1000
int timerDelay = 1000;
new Timer(timerDelay, new ActionListener() {
private int counter = 0;
#Override
public void actionPerformed(ActionEvent e) {
// timer's stopping condition
if (counter >= MAX_VALUE) { // MAX_VALUE is a constant
// int = 5
((Timer) e.getSource()).stop();
} else {
textArea.append("Value " + counter + "\n");
}
counter++; // increment timer's counter variable
}
}).start();
}
});
progressBar.setStringPainted(true);
JPanel bottomPanel = new JPanel();
bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.LINE_AXIS));
bottomPanel.add(new JButton(new MyAction("Press Me")));
bottomPanel.add(progressBar);
frame.getContentPane().add(bottomPanel, BorderLayout.PAGE_END);
// better to avoid setting sizes but instead to
// let the components size themselves vis pack
frame.pack();
frame.setLocationRelativeTo(null);
}
private class MyAction extends AbstractAction {
public MyAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
public void actionPerformed(ActionEvent e) {
progressBar.setValue(0);
setEnabled(false);
MyWorker myWorker = new MyWorker();
myWorker.addPropertyChangeListener(new WorkerListener(this));
myWorker.execute();
}
}
private class WorkerListener implements PropertyChangeListener {
private Action action;
public WorkerListener(Action myAction) {
this.action = myAction;
}
#Override
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
int progress = (int) evt.getNewValue();
progressBar.setValue(progress);
} else if ("state".equals(evt.getPropertyName())) {
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
action.setEnabled(true);
#SuppressWarnings("rawtypes")
SwingWorker worker = (SwingWorker) evt.getSource();
try {
// always want to call get to trap and act on
// any exceptions that the worker might cause
// do this even though get returns nothing
worker.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
}
}
private class MyWorker extends SwingWorker<Void, Void> {
private static final int MULTIPLIER = 80;
private int counter = 0;
private Random random = new Random();
#Override
protected Void doInBackground() throws Exception {
while (counter < 100) {
int increment = random.nextInt(10);
Thread.sleep(increment * MULTIPLIER);
counter += increment;
counter = Math.min(counter, 100);
setProgress(counter);
}
return null;
}
}
}
I need to use a thread to change the position of my JLabel (movingDisplay) every second when I click on my button (btnDisplay) and for the thread to stop when I click on my other button (btnDStop). I have a class called MoveDisplay that implements Runnable and does this action when I click on btnDisplay. After MoveDisplay has randomized x and y for my JLabel, it's supposed to send x and y back to my main class where it updates the position of the JLabel. I have a method in my mainclass to update the JLabel position however I get a NullPointerException when trying to do so. In fact it doesn't work changing any component at all from MoveDisplay class.
public class Main {
public static void main(String[] args) {
GUIFrame test = new GUIFrame();
}
}
MoveDisplay class:
public class MoveDisplay implements Runnable {
private GUIFrame gui;
private boolean moving = true;
private Thread thread;
public void run() {
gui = new GUIFrame();
if (moving) {
Random rand = new Random();
while (moving) {
int x = rand.nextInt(150) + 1;
int y = rand.nextInt(150) + 1;
gui.moveDisplay(x, y, 100, 100);
try {
thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
}
}
}
public void start() {
thread = new Thread(new MoveDisplay());
thread.start();
}
public void stop() {
thread.interrupt();
System.out.println("Stopped");
}
}
GUIFrame class:
public class GUIFrame {
private JFrame frame; // The Main window
private JLabel movingDisplay;
private boolean playing = true;
private boolean moving = true;
private MoveDisplay moveDisplay = new MoveDisplay();
/**
* Starts the application
*/
public void Start() {
frame = new JFrame();
frame.setBounds(0, 0, 494, 437);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
frame.setTitle("Multiple Thread Demonstrator");
InitializeGUI(); // Fill in components
frame.setVisible(true);
frame.setResizable(false); // Prevent user from change size
frame.setLocationRelativeTo(null); // Start middle screen
}
public void InitializeGUI() {
// The moving display outer panel
JPanel pnlDisplay = new JPanel();
Border b2 = BorderFactory.createTitledBorder("Display Thread");
pnlDisplay.setBorder(b2);
pnlDisplay.setBounds(12, 118, 222, 269);
pnlDisplay.setLayout(null);
// Add buttons and drawing panel to this panel
btnDisplay = new JButton("Start Display");
btnDisplay.setBounds(10, 226, 121, 23);
pnlDisplay.add(btnDisplay);
btnDStop = new JButton("Stop");
btnDStop.setBounds(135, 226, 75, 23);
pnlDisplay.add(btnDStop);
pnlMove = new JPanel();
pnlMove.setBounds(10, 19, 200, 200);
Border b21 = BorderFactory.createLineBorder(Color.black);
pnlMove.setBorder(b21);
pnlDisplay.add(pnlMove);
// Then add this to main window
frame.add(pnlDisplay);
movingDisplay = new JLabel("DisplayThread");
pnlMove.add(movingDisplay);
btnDStop.setEnabled(false);
btnDisplay.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
moving = true;
btnDisplay.setEnabled(false);
btnDStop.setEnabled(true);
startMoveDisplay();
}
});
btnDStop.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
moving = false;
btnDisplay.setEnabled(true);
btnDStop.setEnabled(false);
startMoveDisplay();
}
});
}
public void startMoveDisplay() {
if(moving) {
moveDisplay.start();
}
else {
moveDisplay.stop();
}
}
public void moveDisplay(int x, int y, int a, int b) {
movingDisplay.setBounds(10,10,150,150);
}
}
I've checked the code and in the MoveDisplay.run() you were creating a new frame, but in it's constructor the panel wasn't initialized, which triggered the NPE. Because of this I've refactored the GUIFrame constructor to initialeze all components (invoked the Start() method) and removed the new frame's initialization from the run method. Here are the modified classed
public class MoveDisplay {
private GUIFrame gui;
private volatile boolean moving;
public MoveDisplay(GUIFrame gui) {
this.gui = gui;
}
public void start() {
moving = true;
Random rand = new Random();
while (moving) {
int x = rand.nextInt(150) + 1;
int y = rand.nextInt(150) + 1;
gui.moveDisplay(x, y, 100, 100);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void stop() {
moving = false;
}
}
And here is the new frame class
public class GUIFrame {
private JFrame frame; // The Main window
private JLabel movingDisplay;
private boolean playing = true;
private boolean moving = true;
private MoveDisplay moveDisplay;
public GUIFrame() {
Start();
}
/**
* Starts the application
*/
private void Start() {
frame = new JFrame();
frame.setBounds(0, 0, 494, 437);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
frame.setTitle("Multiple Thread Demonstrator");
InitializeGUI(); // Fill in components
frame.setVisible(true);
frame.setResizable(false); // Prevent user from change size
frame.setLocationRelativeTo(null); // Start middle screen
moveDisplay = new MoveDisplay(this);
}
public void InitializeGUI() {
// The moving display outer panel
JPanel pnlDisplay = new JPanel();
Border b2 = BorderFactory.createTitledBorder("Display Thread");
pnlDisplay.setBorder(b2);
pnlDisplay.setBounds(12, 118, 222, 269);
pnlDisplay.setLayout(null);
// Add buttons and drawing panel to this panel
JButton btnDisplay = new JButton("Start Display");
btnDisplay.setBounds(10, 226, 121, 23);
pnlDisplay.add(btnDisplay);
JButton btnDStop = new JButton("Stop");
btnDStop.setBounds(135, 226, 75, 23);
pnlDisplay.add(btnDStop);
JPanel pnlMove = new JPanel();
pnlMove.setBounds(10, 19, 200, 200);
Border b21 = BorderFactory.createLineBorder(Color.black);
pnlMove.setBorder(b21);
pnlDisplay.add(pnlMove);
// Then add this to main window
frame.add(pnlDisplay);
movingDisplay = new JLabel("DisplayThread");
pnlMove.add(movingDisplay);
btnDStop.setEnabled(false);
btnDisplay.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
moving = true;
btnDisplay.setEnabled(false);
btnDStop.setEnabled(true);
startMoveDisplay();
}
});
btnDStop.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
moving = false;
btnDisplay.setEnabled(true);
btnDStop.setEnabled(false);
startMoveDisplay();
}
});
}
public void startMoveDisplay() {
if(moving) {
new Thread(new Runnable() {
#Override
public void run() {
moveDisplay.start();
}
}).start();
} else {
moveDisplay.stop();
}
}
public void moveDisplay(int x, int y, int a, int b) {
movingDisplay.setBounds(x, y, a, b);
}
}
You have to get a reference to the existing GUIFrame instance instead of creating a new one, try this:
MoveDisplay
public class MoveDisplay implements Runnable {
private GUIFrame gui;
Random rand = new Random();
volatile boolean moving;
public MoveDispaly(GUIFrame gui){
this.gui = gui;
}
public void run() {
while (moving) {
int x = rand.nextInt(150) + 1;
int y = rand.nextInt(150) + 1;
try {
SwingUtilities.invokeAndWait(new Runnable(){
public void run(){
gui.moveDisplay(x, y, 100, 100);
}
});
thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
}
}
public void start() {
moving = true;
thread = new Thread(new MoveDisplay());
thread.start();
}
public void stop() {
moving = false;
}
}
GUIFrame
public class GUIFrame{
MoveDisplay moveDisplay = new MoveDisplay(this);
...
}
Also, you have to run the part of the code that changes the GUI on the EDT thread.
Is not a good idea to stop a thread by interrupting it, you can stop it by setting the moving variable to false.
Maybe you can also use the Singleton Pattern to get the original instance of GUIFrame:
public static class instanceClassA {
private static instanceClassA = null;
public static instanceClassA(){
if(instance == null){
instance = instanceClassA();
}
return instance;
}
}
i have a fun project where i need to change the content of a text area inside a iteration.
Its a character, a "projectile", moving trought a string. The string is updated and sent to the textArea inside the iteration, and the iteration stops when the character reaches a wall.
But my textArea only updates (visually) when i leave the iteration. While im inside it, textArea freezes, as if its waiting for the iteration, even with Thread.sleep() inside it.
I made an MVCE exemplifing the problem bellow, notice the text only shows after the iteration, i want it to apper in every step of the while.
public class GUIProblem extends JFrame{
public GUIProblem() {
setSize(640, 480);
JPanel panel = new JPanel();
getContentPane().add(panel, BorderLayout.CENTER);
final JTextArea textArea = new JTextArea();
textArea.setRows(10);
textArea.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
int i = 0;
while(i < 10){
textArea.setText("this text only appears after the iteration, i want it to appear in each step of the iteration!");
System.out.println("iterating..." + i++);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
textArea.setColumns(30);
panel.add(textArea);
}
/**
*
*/
private static final long serialVersionUID = 1L;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
GUIProblem gui = new GUIProblem( );
gui.setVisible(true);
}
});
JOptionPane.showMessageDialog(null, "Click the textArea!");
}
}
You've a classic Swing threading issue where you stop the Swing event thread in its tracks with your iteration and its Thread.sleep() calls. The solution is the same as for similar questions: use a Swing Timer or background thread such as a SwingWorker. In your case, use the Timer.
For example, since you posted an MCVE
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GUIProblem extends JFrame {
public GUIProblem() {
// setSize(640, 480);
JPanel panel = new JPanel();
getContentPane().add(panel, BorderLayout.CENTER);
final JTextArea textArea = new JTextArea(20, 50);
textArea.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent mEvt) {
int i = 0;
int timerDelay = 200;
new Timer(timerDelay, new ActionListener() {
int count = 0;
private final int MAX_COUNT = 10;
#Override
public void actionPerformed(ActionEvent e) {
if (count >= MAX_COUNT) {
((Timer) e.getSource()).stop(); // stop the timer
return;
}
textArea.append("Count is: " + count + "\n");
count++;
}
}).start();
}
});
panel.add(new JScrollPane(textArea));
}
/**
*
*/
private static final long serialVersionUID = 1L;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
GUIProblem gui = new GUIProblem();
gui.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
gui.pack();
gui.setLocationRelativeTo(null);
gui.setVisible(true);
}
});
JOptionPane.showMessageDialog(null, "Click the textArea!");
}
}
I keep getting a stack overflow error when I run this short program I made! please help! Right now all it's supposed to do is take the users input and print their position (in X and Y coordinates). I'm not sure what Stack overflow error is or how to fix it.
import java.awt.*;
import javax.swing.*;
public class ExplorerPanel extends JFrame {
ExplorerEvent prog = new ExplorerEvent(this);
JTextArea dataa = new JTextArea(15, 20);
JTextField datain = new JTextField(20);
JButton submit = new JButton("Submit");
JTextField errors = new JTextField(30);
public ExplorerPanel() {
super("Explorer RPG");
setLookAndFeel();
setSize(400, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_…
BorderLayout bord = new BorderLayout();
setLayout(bord);
JPanel toppanel = new JPanel();
toppanel.add(dataa);
add(toppanel, BorderLayout.NORTH);
JPanel middlepanel = new JPanel();
middlepanel.add(datain);
middlepanel.add(submit);
add(middlepanel, BorderLayout.CENTER);
JPanel bottompanel = new JPanel();
bottompanel.add(errors);
add(bottompanel, BorderLayout.SOUTH);
dataa.setEditable(false);
errors.setEditable(false);
submit.addActionListener(prog);
setVisible(true);
}
private void setLookAndFeel() {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLo…
);
} catch (Exception exc) {
// ignore error
}
}
public static void main(String[] args) {
ExplorerPanel frame = new ExplorerPanel();
}
}
public class ExplorerEvent implements ActionListener, Runnable {
ExplorerPanel gui;
Thread playing;
String command;
String gamedata;
ExplorerGame game = new ExplorerGame();
public ExplorerEvent(ExplorerPanel in) {
gui = in;
}
public void actionPerformed(ActionEvent event) {
String command = event.getActionCommand();
if (command.equals("Submit")) {
startPlaying();
}
}
void startPlaying() {
playing = new Thread(this);
playing.start();
}
void stopPlaying() {
playing = (null);
}
void clearAllFields() {
gui.dataa.setText("");
}
public void run() {
Thread thisThread = Thread.currentThread();
while (playing == thisThread) {
// Game code
game.Game();
}
}
}
public class ExplorerGame {
ExplorerPanel gui = new ExplorerPanel();
String command;
int x = 1;
int y = 1;
public void Game() {
command = gui.submit.getText().toLowerCase();
if (command.equals("east")) {x--;}
else if (command.equals("south")) {y--;}
else if (command.equals("west")) {x++;}
else if (command.equals("north")) {y++;}
System.out.println(x + y);
}
}
In ExplorerGame, you have declared: -
ExplorerPanel gui = new ExplorerPanel();
then, in ExplorerPanel: -
ExplorerEvent prog = new ExplorerEvent(this);
and then again, in ExplorerEvent: -
ExplorerGame game = new ExplorerGame();
This will fill the Stack with recursive creation of objects.
ExplorerGame -> ExplorerPanel -> ExplorerEvent --+
^ |
|____________________________________________|
You want to solve the Issue?
I'll Suggest you: -
Throw away the code, and re-design your application. Having a cyclic dependency in your application is a big loop hole, showing a very poor design.
f.e. I have an email client, it receives new message, button with incoming messages starts doing something, until user clicks it to see whats up.
I'm trying to make button attract attention by selecting, waiting and then deselecting it, but this does nothing!
do{
button.setSelected(true);
Thread oThread = new Thread() {
#Override
public void run() {
synchronized (this) {
try {
wait(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
button.setSelected(false);
}
};
oThread.start();
}while(true);
You should use Swing timers for that. Don't interact with GUI objects from foreign threads.
There's some docs in the Java tutorial: How to use Swing timers.
Here's an example way you could do this playing with the button's icon.
// member var
Icon buttonIcon;
Timer timer;
// in constructor for example
buttonIcon = new ImageIcon("resources/icon.png");
button.setIcon(buttonIcon);
timer = new Timer(1000, this);
timer.start();
// in the actionPerformed handler
if (button.getIcon() == null)
button.setIcon(icon);
else
button.setIcon(null);
Your class will need to implement ActionListener for this to work like that. Add some logic to stop the flashing when you need it.
hafl_workaround to your questions
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ShakingButtonDemo implements Runnable {
private JButton button;
private JRadioButton radioWholeButton;
private JRadioButton radioTextOnly;
public static void main(String[] args) throws Exception {
SwingUtilities.invokeLater(new ShakingButtonDemo());
}
#Override
public void run() {
radioWholeButton = new JRadioButton("The whole button");
radioTextOnly = new JRadioButton("Button text only");
radioWholeButton.setSelected(true);
ButtonGroup bg = new ButtonGroup();
bg.add(radioWholeButton);
bg.add(radioTextOnly);
button = new JButton(" Shake with this Button ");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
shakeButton(radioWholeButton.isSelected());
}
});
JPanel p1 = new JPanel();
p1.setBorder(BorderFactory.createTitledBorder("Shake Options"));
p1.setLayout(new GridLayout(0, 1));
p1.add(radioWholeButton);
p1.add(radioTextOnly);
JPanel p2 = new JPanel();
p2.setLayout(new GridLayout(0, 1));
p2.add(button);
JFrame frame = new JFrame();
frame.setTitle("Shaking Button Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(p1, BorderLayout.NORTH);
frame.add(p2, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private void shakeButton(final boolean shakeWholeButton) {
final Point point = button.getLocation();
final Insets margin = button.getMargin();
final int delay = 75;
Runnable r = new Runnable() {
#Override
public void run() {
for (int i = 0; i < 30; i++) {
try {
if (shakeWholeButton) {
moveButton(new Point(point.x + 5, point.y));
Thread.sleep(delay);
moveButton(point);
Thread.sleep(delay);
moveButton(new Point(point.x - 5, point.y));
Thread.sleep(delay);
moveButton(point);
Thread.sleep(delay);
} else {// text only
setButtonMargin(new Insets(margin.top, margin.left + 3, margin.bottom, margin.right - 2));
Thread.sleep(delay);
setButtonMargin(margin);
Thread.sleep(delay);
setButtonMargin(new Insets(margin.top, margin.left - 2, margin.bottom, margin.right + 3));
Thread.sleep(delay);
setButtonMargin(margin);
Thread.sleep(delay);
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
};
Thread t = new Thread(r);
t.start();
}
private void moveButton(final Point p) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
button.setLocation(p);
}
});
}
private void setButtonMargin(final Insets margin) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
button.setMargin(margin);
}
});
}
}