JButton call function in other class - java

I am creating a timer application. I created my timer (in millisecond) and my interface (with JFrame). I would like to start my chrono (in class "Chrono") when I click on bouton "Start_button" (in class "WindowChrono") from my main class "Application".
Start_button in WindowChrono
JButton Start_button = new JButton("Start");
Start_button.setForeground(Color.BLUE);
Start_button.setFont(new Font("Tahoma", Font.PLAIN, 20));
Start_button.setBackground(new Color(255, 255, 255));
Start_button.setBounds(474, 456, 142, 27);
Start_button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if(i==0) {
Start_button.setText("Stop");
i = 1;
}
else {
Start_button.setText("Start");
i = 0;
}
}
});
main in Application
public class Application extends WindowChrono {
public void main(String[] args) {
WindowChrono window = new WindowChrono();
run();
Chrono Timer = new Chrono();
int refreshTime = 10;
Timer.start(); // LORS DE L ACTIVATION DU BOUTON START
Timer.stop(); // LORS DE L ACTIVATION DU BOUTON STOP
while (Timer.getStopTime == 0) {
Thread.sleep(refreshTime);
System.out.println(Timer.actualTime()); // AFFICHE LE TEMPS ACUTEL DANS LA FENETRE D'AFFICHAGE
}
System.out.println(Timer.getTime());
}
}
How can I do that?

First you want to show your window. So in your main method you can put this code to start it:
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
Application window = new Application(); // Application is a WindowChrono because it extends it
window.setVisible(true);
}
});
It will make sure that Swing handles the appearance of the window as soon as possible (invokeLater). So you don't have to worry about that anymore.
Now, once the window is visible it will take over. All algorithms, methods or what ever you execute should be done in the Window instance (and no longer in your main)
So your Application has a constructor somewhere:
public class Application extends WindowChrono{
public Application(){
// your constructor will be executed when you call "new Application()"
}
}
In your constructor you could initialise your timer (without starting it) so that the "timer" instance exists in your Window.
private Chrono timer;
public Application(){
this.timer = new Chrono();
}
Your button is looking good already. Now you only need to start/stop the timer from inside the ActionListener:
public void actionPerformed(ActionEvent arg0) {
if(i==0) {
Start_button.setText("Stop");
i = 1;
Application.this.timer.start();
}
else {
Start_button.setText("Start");
i = 0;
Application.this.timer.stop();
}
}
The mentioning of Application before the this is necessary to tell Java that you mean the current Application instance (not the instance of the ActionListener.
You can also put the "actionListener" method in your Application directly:
public void performButtonAction(int i){
// the code from your action listener
}
and then just call the method like this:
Start_button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
performButtonAction(i);
}
});
The only thing that is not clear to me is where your i is coming from (and why it is an int and not a boolean which could be easier don't you think?).
Oh, one more thing: variable names should start with a small letter start_Button instead of Start_Button. Only class names start with a capital letter. It helps you keep your code clear. Imagine you had something like this: Application Application = new Application() .. now what is what? :)

Related

Java: The escape key is always pressed after dispatchEvent() for WINDOW_CLOSING on a JFrame

I have a simple JFrame that asks a user for a confirmation to exit when they click X to close the window, this works fine. I also wanted the user to be presented with the same option if they also pressed the escape key (ESC), unfortunately it seems to be trapped in a state where the escape key seems to be constantly pressed when it is not. Where is the mistake and why?
public class Zz extends javax.swing.JFrame implements Events {
boolean exitAttempt = false;
java.awt.event.WindowEvent closeEvent;
//public Zz() {}
public static void main(java.lang.String[] args) {
Zz zz = new Zz();
zz.dostuff();
}
public void dostuff() {
setSize(800, 600);
setLocationRelativeTo(null);
setResizable(false);
setDefaultCloseOperation(javax.swing.JFrame.DO_NOTHING_ON_CLOSE);
addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(java.awt.event.WindowEvent we) {
exitAttempt = true;
}
});
closeEvent = new java.awt.event.WindowEvent(
this, java.awt.event.WindowEvent.WINDOW_CLOSING);
setVisible(true);
java.awt.Canvas canvas = new java.awt.Canvas();
canvas.setPreferredSize(new java.awt.Dimension(800, 600));
add(canvas);
Keys keys = new Keys();
addKeyListener(keys);
pack();
while (true) {
events(keys);
if (exitAttempt) {
if (javax.swing.JOptionPane.YES_OPTION ==
showConfirmDialog("Do you want to Exit ?",
"Confirmation:", javax.swing.JOptionPane.YES_NO_OPTION,
javax.swing.JOptionPane.QUESTION_MESSAGE, null)) {
exit();
break; //while loop
}
exitAttempt = false;
}
}
dispose();
}
public void triggerCloseEvent() {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
dispatchEvent(closeEvent);
}
});
}
public int showConfirmDialog(java.lang.Object message,
java.lang.String title, int optionType, int messageType,
javax.swing.Icon icon) {
return javax.swing.JOptionPane.showConfirmDialog(
this, message, title, optionType, messageType, icon);
}
public boolean exit() {
setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
return true;
}
public void events(Keys keys) {
System.out.println((keys.getPressed())[java.awt.event.KeyEvent.VK_ESCAPE]);
if ((keys.getPressed())[java.awt.event.KeyEvent.VK_ESCAPE]) {
triggerCloseEvent();
}
}
}
interface Events {
public void events(Keys keys);
}
class Keys implements java.awt.event.KeyListener {
private final boolean[] pressed;
public Keys() {
pressed = new boolean[256];
}
public void keyTyped(java.awt.event.KeyEvent event) {}
public void keyPressed(java.awt.event.KeyEvent event) {
pressed[event.getKeyCode()] = true;
}
public void keyReleased(java.awt.event.KeyEvent event) {
pressed[event.getKeyCode()] = false;
}
public boolean[] getPressed() {
return pressed;
}
}
I have a simple JFrame that asks a user for a confirmation to exit when they click X to close the window, this works fine
Your design is incorrect.
You should NOT have a while (true) loop.
GUI's are event driven. You create the frame and make it visible. That is the end of the code in your main() method or constructor. The GUI will then sit there forever doing nothing.
However, eventually, the user will then generate events that the GUI responds to.
This means that the code to display the JOptionPane should be moved to the windowClosing() method of your WindowListener.
See: Closing an Application for some basics and helpful classes to use.
I also wanted the user to be presented with the same option if they also pressed the escape key
Don't use a KeyListener.
Swing was designed to be used with Key Bindings.
You can use the ExitAction contained in the Closing an Application link when creating your key bindings:
KeyStroke escapeKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false);
InputMap im = frame.getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
im.put(escapeKeyStroke, "escape");
frame.getRootPane().getActionMap().put("escape", new ExitAction());
Read the Swing tutorial. There are section on :
How to Uuse Key Bindings
How to Use Actions
to help explain how the above suggestions work.
The tutorial examples will also show you how to better structure your code and note that the never use a while (true) loop.

Disable buttons on GUI in Swing

I have buttons on a GUI that execute tests when clicked on in Selenium. They can only be run serially and are currently added to EventQueue. I would like it so that if a button is clicked on and a test is executed, then it will disable the other buttons so that other tests cannot be added to a queue.
Currently a button looks like:
Test1 = new JButton("Test1 ");
Test1.setLocation(290, 30);
Test1.setSize(120, 30);
Test1.addActionListener(this);
Test1.addMouseListener(new MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent e) {
if (Test1.isEnabled()) {
Test1.setEnabled(false);
errorLabel.setText("");
service.submit(()->{
Result result = JUnitCore.runClasses(Test1.class);
EventQueue.invokeLater(()->{
errorMessageDisplay(result);
Test1.setEnabled(true);
});
});
}
}
});
buttonPanel.add(Test1);
I have used the EventQueue as it allows me to reset update Pass/Fail error messages on the GUI.
How can I best achieve this?
You should add ActionListener to your button. What's even more important, you should use naming conventions what also means that your objects' names should start with a small letter. Capital letters are reserved for Classes and static fields (all upper case). The following code adds an ActionListener to your JButton and disables it after clicked. If it's not what you're looking for, I'll add another version in a moment.
test1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
test1.setEnabled(false);
}
});
In case, you want to keep the state of your button, but don't disable it, the following code might be a solution:
private final static String ENABLED = "ENABLED";
private final static String DISABLED = "DISABLED";
public static void main(String[] args) {
Map<JButton, String> map = new HashMap<>();
JButton test1 = new JButton();
map.put(test1, ENABLED);
test1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (map.get(test1).equals(ENABLED)) {
//do something
} else {
//do something else. I'll enable.
map.remove(test1);
map.put(test1, ENABLED);
}
}
});
}

Add a GUI to class

I want to know how to add a GUI to my program. I have started creating a java program in Blue J and the first class of the program is a class which has been extended by other classes.
Now I have to make a GUI too but from my understanding I can only implement an interface as the GUI extends the class Frame. The problem is I want to create a GUI of my class, it has instance variables too so is there a work around? Could I make my first class an interface without altering the extensions too much?
code:
public class Players /* Class name */
{
private int attack; /* Instance variables* */
private int defence;
private int jump;
public Players(int a, int d, int j) /* Constructor being defined */
{
int total = a + d + j;
if((total) == 100)
{
attack = a;
defence = d;
jump = j;
}
else
{
System.out.println("Make stats add to 100");
}
}
public Players()/* Default contructor if not user defined */
{
attack = 34;
defence = 33;
jump = 33;
}
public void addAttack(int a)
{
attack += a;
}
public void addDefence(int a)
{
defence += a;
}
public void addJump(int a)
{
jump += a;
}
public void getBasicStats()
{
System.out.println(attack + " " + defence + " " + jump);
}
}
This is my first class and my superclass for most of the other classes
I suggest learning how to use Swing. You will have several different classes interacting together. In fact, it is considered good practice to keep separate the code which creates and manages the GUI from the code which performs the underlying logic and data manipulation.
Another suggestion:
Learn JavaFX and download SceneBuilder from Oracle: here
At my university they have stopped teaching Swing and started to teach JavaFX, saying JavaFX has taken over the throne from Swing.
SceneBuilder is very easy to use, drag and drop concept. It creates a FXML file which is used to declare your programs GUI.
How will I declare aan instance variable inside the GUI class?
Like as shown bellow, you could start with something like this, note that your application should be able to hand out your data to other classes, for instance I changed getBasicStats() to return a String, this way you can use your application class anywhere you want, I guess this is why you were confused about where to place the GUI code...
public class PlayersGUI extends JFrame {
private static final long serialVersionUID = 1L;
private Players players; // instance variable of your application
private PlayersGUI() {
players = new Players();
initGUI();
}
private void initGUI() {
setTitle("This the GUI for Players application");
setPreferredSize(new Dimension(640, 560));
setLocation(new Point(360, 240));
JPanel jPanel = new JPanel();
JLabel stat = new JLabel(players.getBasicStats());
JButton attack = new JButton("Attack!");
attack.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
players.addAttack(1);
}
});
JButton hugeAttack = new JButton("HUGE Attack!");
hugeAttack.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
players.addAttack(10);
}
});
JButton defend = new JButton("Defend");
defend.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
players.addDefence(1);
}
});
JButton showStats = new JButton("Show stats");
showStats.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
stat.setText(players.getBasicStats());
}
});
jPanel.add(stat);
jPanel.add(attack);
jPanel.add(hugeAttack);
jPanel.add(defend);
jPanel.add(showStats);
add(jPanel);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
public static void main(String... args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
PlayersGUI pgui = new PlayersGUI();
pgui.pack();
pgui.setVisible(true);
}
});
}
}
I would recommend using netbeans to start with. From there you can easily select pre created classes such as Jframes. Much easier to learn. You can create a GUI from there by dragging and dropping buttons and whatever you need.
Here is a youtube tut to create GUI's in netbeans.
https://www.youtube.com/watch?v=LFr06ZKIpSM
If you decide not to go with netbeans, you are gonna have to create swing containers withing your class to make the Interface.

Communication between Java Swing Application and Leap Motion Listener

I want to know how I can do a communication between the Java Swing Application and between my leap motion listener.
Because I want that in my application when I click on a button I can change a number with the number of finger see by the leap motion.
I have one Java Swing application :
public class KidCountingFrame extends JFrame
And one Leap Motion Runnable:
public class LeapMouse implements Runnable
{
#Override
public void run()
{
CustomListener l = new CustomListener();
Controller c = new Controller();
c.addListener(l);
}
}
Which is launching a Leap Motion Listener... :
public class CustomListener extends Listener
Maybe I have to use a design pattern ?
* UPDATE : *
I try to applied the ProgressBarDemo on my project and to follow explications.
But one error happens when I put the listener in the SwingWorker constructor :
Exception in thread "Thread-1443" java.lang.NullPointerException: null upcall object
Here my updated code :
public class PanelLeapFingers extends JPanel implements ActionListener,
PropertyChangeListener
{
private JButton digitDisplayButton;
private Task task;
class Task extends SwingWorker<Void, Void>
{
public Task()
{
try
{
NbFingersListener l = new NbFingersListener();
Controller c = new Controller();
c.addListener(l);
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
}
#Override
public Void doInBackground()
{
// In background :
// Find how digit fingers are shown by the user
int progress = 0;
//setProgress(????); //I don't really know how call the listener here
setProgress(5); //Here it's just to make a test
return null;
}
#Override
public void done()
{
Toolkit.getDefaultToolkit().beep();
digitDisplayButton.setEnabled(true);
setCursor(null); // turn off the wait cursor
}
}
public PanelLeapFingers()
{
super(new BorderLayout());
digitDisplayButton = new JButton("?");
digitDisplayButton.setFont(new Font("Arial", Font.PLAIN, 40));
digitDisplayButton.setActionCommand("start");
digitDisplayButton.addActionListener(this);
JPanel panel = new JPanel();
panel.add(digitDisplayButton);
add(panel, BorderLayout.PAGE_START);
setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
}
public void actionPerformed(ActionEvent evt)
{
digitDisplayButton.setEnabled(false);
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
task = new Task();
task.addPropertyChangeListener(this);
task.execute();
}
public void propertyChange(PropertyChangeEvent evt) {
if ("progress" == evt.getPropertyName()) {
int progress = (Integer) evt.getNewValue();
digitDisplayButton.setText(progress+"");
}
}
}
I'm not sure to be on the good way and I don't understand how I can receive information from my listener in my setProgress( ) function.
EDIT :
Solution : Finally I have decide to use a Singleton Model to communicate between the listener and the Java Swing APP. I save all informations when the Listener is working in the Singleton Model and I recover the information that I need in the Java Swing APP.
As discussed here, the Listener will be called asynchronously, typically from another thread. To avoid blocking the event dispatch thread, create your Listener in the constructor of a SwingWorker and arrange for your doInBackground() implementation to publish() frames of interest; process() can then handle these frames on the event dispatch thread.
Alternatively, poll the Controller at a suitable rate in the ActionListener of javax.swing.Timer.

Simple memory game with replay button

I want to build a simple memory game. I want to put a replay button, which is play again the memory game.
I have built a class named MemoryGame and a main class.
Here is the part of the ButtonListener code.
public void actionPerformed(ActionEvent e) {
if (exitButton == e.getSource()) {
System.exit(0);
}
else if (replayButton == e.getSource()) {
//How can I declare it?
}
}
If I declare the replay button as :
new MemoryGame();
It's work fine, but it pops up another windows.
I want to clear the current display and return to the beginning, without a new windows. How can I do that?
EDIT :
I think I need to rewrite the code of my program, because my program does not have the init() method as suggested which is the initial state of the program.
My Java knowledge is very limited and usually I create less method and dump most into a method.
I will try to redo my program.
Thanks for the suggestions.
Show us what is inside the MemoryGame how you create its initial state. Effectively what folks are suggesting here is for you is to have an initial method which will set-up the game state which the MemeoryGame constructor will call. Then on replay-button of the game you call this method.
Something along these lines:
void init(){
this.x = 10;
this.y = 10;
}
public MemoryGame(){
init();
}
public void actionPerformed(ActionEvent e) {
if (exitButton == e.getSource()) {
System.exit(0);
}
else if (replayButton == e.getSource()) {
init();
}
}
one way you can do it although it might be dirty, is to grab your MemoryGame constructor, and put the stuff inside it inside another method, and call that method in your constructor and inside the button event.
as an example i have made the following class and it resets itself with the use of the previous technique:
public class App extends JFrame{
public static void main(String[] args){
new App();
}
public App(){
init();
}
private JButton changeColorButton;
private JButton resetAppButton;
private JPanel panel;
private void init() {
changeColorButton=null;
resetAppButton=null;
panel=null;
this.setSize(200,400);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new JPanel();
panel.setBackground(Color.white);
panel.setPreferredSize(new Dimension(200,400));
changeColorButton = new JButton("Change");
changeColorButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
panel.setBackground(Color.black);
panel.repaint();
}
});
changeColorButton.setPreferredSize(new Dimension(100,100));
resetAppButton = new JButton("Reset");
resetAppButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
init();
}
});
resetAppButton.setPreferredSize(new Dimension(100,100));
panel.add(changeColorButton);
panel.add(resetAppButton);
this.add(panel);
this.validate();
}
}
what this app does is it has two buttons. one changes the color and the other resets the app itself.
You should think about re-factoring your code so that the MemoryGame class does not create the GUI, then you wont be recreating it whenever you initialise a new Game.
It's a good idea to keep program logic separate to UI code.
What you could do is you could call dispose() on your JFrame. This will get rid of it and go to your title screen like this:
Here's the button code
public void actionPerformed(ActionEvent event)
{
if (closeButton = event.getSource())
{
System.exit(0);
}
if (playAgainButton = event.getSource())
{
Game.frame.dispose(); // Your class name, then the JFrame variable and call dispose
}
}
This will work but you may have a few problems reseting your program. If so then create a reset method where you can reset all your variables and call when playAgainButton is clicked. For example:
public void reset()
{
// Right here you'd reset all your variables
// Perhaps you have a gameOver variable to see if it's game over or not reset it
gameOver = false;
}

Categories

Resources