Making a method trigger another method in a Java GUI - java

Consider the following code.
import edu.cmu.ri.createlab.terk.robot.finch.Finch;
import javax.swing.JFrame;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class RobotControl extends JFrame {
public static void main (String args[]) {
RobotControl GUI = new RobotControl(); //GUI is the name of my object.
GUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GUI.setSize(300,300);
GUI.setVisible(true);
GUI.setTitle("RobotControl");
}
private JButton foward;
public RobotControl() { //constructor
setLayout (new FlowLayout());
foward = new JButton("foward");
add(foward);
ActionListener e = new event();
foward.addActionListener(e);
}
public class event implements ActionListener {
public void actionPerformed1(ActionEvent e){
}
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
}
}
Now consider the following code that would make my finch robot move foward for 10 seconds.
Finch myf = new Finch();
myf.setWheelVelocities(255, 255, 10000);
Now, my question is, would it be possible to execute the second piece of code as a result of clicking the foward button created on the GUI, from the first piece of code? If so how would i go about it. I have tried putting the finch code into the actionListener class but nothing happens. where am i going wrong. I need advice.

The short answer is, yes.
First, you need to maintain an instance of Finch as a instance variable...
public class RobotControl extends JFrame {
private Finch finch;
//...
}
You need to create an instance of Finch...
public RobotControl {
finch = new Finch();
}
Then in your ActionListener, you need to "communicate" with Finch
public void actionPerformed1(ActionEvent e){
myf.setWheelVelocities(255, 255, 10000);
}
The long answer, it's likely that you are going to have to issue multiple commands in sequence, the problem with this, is this process is likely to block the Event Dispatching Thread, preventing from responding to new incoming events and making it look like your application has "stopped"
While there are multiple ways you might alleviate this problem, if you don't need Finch to communicate with the UI (such as report status of motors or something), you could simply use a single threaded Executor of some kind and simply issue a sequence of commands via it.
If you need to provide feedback to the client UI, things become considerably more complicated...

Here is a sample code:
-------------------------
RobotControl.java
myrobot = new Finch();
foward = new JButton("foward");
add(foward);
forward.addActionListener(new ForwardButtonListener(myrobot));
-------------------------
ForwardButtonListener.java
public class ForwardButtonListener implements ActionListener {
Finch robotToControl;
public FowardButtonListener(Finch aRobot) {
robotToControl = aRobot;
}
public void actionPerformed (ActionEvent e) {
robotToControl.setWheelVelocities(255, 255, 10000);
}
}
-------------------------

Related

Why does java swing timer class not work?

Here is my main class
import javax.swing.Timer;
public class Test {
public static int k=9;
public static void main(String[] args) {
Timer t = new Timer(100, new Loop());
t.start();
}
}
And my class Loop which implements ActionListener
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Loop implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if(Test.k==9){
System.out.println("Its's Working");
}
}
}
I don't know why? When I've fully what it need but it doesn't print "Its's Working" in the console
And one more question is that "Is this Timer class similar to Thread in java ?"
Thanks for your answer!
Your program exits immediately after stating the timer, giving it no chance to fire.
The AWT Event Dispatch Thread (EDT) will need to have started for some reason in order for the timer to stay alive.
Swing is supposed to be use from this thread. If you do so, it should work.
java.awt.EventQueue.invokeLater(() -> {
Timer t = new Timer(100, new Loop());
t.start();
});
To avoid indenting a lot of code , and to have a short main, I tend to create a method call go and use a method reference.
java.awt.EventQueue.invokeLater(Test::go);
private static void go() {

Bouncing balls won't pause

all
What I'm trying to do is to create a bouncing balls java program. Which I did. Each time the user presses start balls will populate the screen. the only problem I'm having is that I don't know how to pause it. Any help would be appreciated. I tried adding something similar to how I did the addball function but don't know how to apply that to pause the ball. I have tried to do the puase function by adding the button pause but don't know how to get it working
BounceFrame:
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class BounceFrame extends JFrame {
private static final long serialVersionUID = 1L;
private BallComponent ballComponent;
public BounceFrame() {
setTitle("Bounce");
ballComponent = new BallComponent();
add(ballComponent, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel();
// Adds more balls.
addButton(buttonPanel, "Start", new ActionListener() {
public void actionPerformed(ActionEvent ae) {
addBall();
}
});
addButton(buttonPanel, "Pause", new ActionListener() {
public void actionPerformed(ActionEvent ae) {
}
});
// Closes the panel.
addButton(buttonPanel, "Close", new ActionListener() {
public void actionPerformed(ActionEvent ae) {
System.exit(0);
}
});
add(buttonPanel, BorderLayout.SOUTH);
pack();
}
public void addButton(Container c, String title, ActionListener listener) {
JButton b = new JButton(title);
c.add(b);
b.addActionListener(listener);
}
public void addBall() {
Ball b = new Ball(ballComponent.getBounds());
RunnableBall rB = new RunnableBall(b, ballComponent);
Thread t = new Thread(rB);
t.start();
}
}
RunnableBall:
import java.util.logging.Level;
import java.util.logging.Logger;
public class RunnableBall implements Runnable {
private Ball b;
private BallComponent comp;
private static final int DELAY = 3; //Controls speed of the balls.
public RunnableBall(Ball b, BallComponent comp)
{
this.b = b;
this.comp = comp;
}
#Override
public void run() {
comp.add(b);
while (true)
{
b.move(comp.getBounds());
comp.repaint();
try
{
Thread.sleep(DELAY);
}
catch (InterruptedException ex) {
Logger.getLogger(RunnableBall.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
When you add the ball you need to store the RunnableBall object you are creating in some collection variable, such as a variable of type ArrayList<RunnableBall>, for example. Then in your Pause button's ActionListener you can loop through the ArrayList and call a pause method on each of your RunnableBalls.
So you'll need to then define a pause method inside RunnableBall, which sets a boolean variable "isPaused" to true. So then you'll need to create that variable, isPaused, inside the RunnableBall class, and make it change the behaviour of the run method. You should be able to figure that bit out.
One thing you'll need to take care with is the fact that because you're using multiple threads, you'll need the communication between those threads (i.e. the process of setting the isPaused variable to true or false) to be thread-safe. I think you could achieve that by declaring the isPaused variable to be volatile, but there are other ways to do it.

Implement 2 classes for ActionListener for buttons

I have 2 classes, the first class is where I am creating GUI and all of the components needed. Including the buttons. This is being done outside of the main method and in there own respective methods. I want to .addActionListener, but from another class outside of this one. I do not want to use inner classes.
Here is the classes containing Main and the Gui components and the button.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
public class PasswordGeneratorGui {
private JFrame interfaceFrame;
private JPanel interfacePanel;
private JMenuBar interfaceMenuBar;
private JMenu interfaceMenu;
private JMenuItem interfaceMenuItemFile;
private JButton interfaceButtonGenerate;
public static void main(String[] args) {
new PasswordGeneratorGui();
}
public PasswordGeneratorGui() {
createInterfacePanel();
createInterfaceFrame();
createInterfaceMenuBar();
createInterfaceMenu();
createInterfaceMenuItem();
createInterfaceButton();
PasswordGeneratorButtonHandler b = new PasswordGeneratorButtonHandler();
interfaceFrame.add(interfacePanel);
interfaceFrame.setVisible(true);
}
public void createInterfacePanel() {
interfacePanel = new JPanel();
interfacePanel.setLayout(null);
}
public void createInterfaceFrame() {
interfaceFrame = new JFrame();
interfaceFrame.setTitle("Password Generator");
interfaceFrame.setBounds(50, 50, 700, 400);
interfaceFrame.setResizable(false);
interfaceFrame.setJMenuBar(interfaceMenuBar);
}
public void createInterfaceMenuBar() {
interfaceMenuBar = new JMenuBar();
interfaceMenuBar.setBounds(0, 0, 700, 20);
interfaceMenuBar.setVisible(true);
interfacePanel.add(interfaceMenuBar);
}
public void createInterfaceMenu() {
interfaceMenu = new JMenu("File");
interfaceMenuBar.add(interfaceMenu);
}
public void createInterfaceMenuItem() {
interfaceMenuItemFile = new JMenuItem("Exit");
interfaceMenu.add(interfaceMenuItemFile);
}
**public void createInterfaceButton() {
interfaceButtonGenerate = new JButton("Generate");
interfaceButtonGenerate.setBounds(0, 358, 700, 20);
interfaceButtonGenerate.addActionListener();
interfacePanel.add(interfaceButtonGenerate);
}**
}
Here is the class for the ActionListener
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class PasswordGeneratorButtonHandler implements ActionListener {
PasswordGeneratorButtonHandler generate = new PasswordGeneratorButtonHandler();
public PasswordGeneratorButtonHandler() {
}
public void interfaceButtonGenerateHandler(ActionEvent event) {
System.exit(1);
}
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
}
I just want to be able to call the AcitonListener method from the second class. I have tried initiating a new instance of the class and calling it however I think I wasn't quite going in the correct direction.
I'm a little confused about what your asking. You said
I just want to be able to call the AcitonListener method from the second class
Taken literally this means that while you're inside of the PasswordGeneratorButtonHandler class, you want to call the actionPerformed() method. If so, just use this.actionPerformed(), where this is a special keyword in java, representing the current instance of your class.
If however you want to add your handler to the button you created in the first class, which seems like what you might want to do, then you just need to call the JButton#addActionListener() method.
public PasswordGeneratorGui() {
createInterfacePanel();
createInterfaceFrame();
createInterfaceMenuBar();
createInterfaceMenu();
createInterfaceMenuItem();
createInterfaceButton();
PasswordGeneratorButtonHandler b = new PasswordGeneratorButtonHandler();
interfaceButtonGenerate.addActionListener(b); // Add handler to button
interfaceFrame.add(interfacePanel);
interfaceFrame.setVisible(true);
}
Also, inside of the PasswordGeneratorButtonHandler class, you instantiate an instance of the class called generate. This is unnecessary.

simple timer, starting from 0 to whatever number

I am trying to make a simple timer, starting from 0 to whatever number.I want to interrup the timer when I press a button.
I've done this so far, I'n not interested about the button part yet.When I run, I don't get anything displayed.
import java.util.ArrayList;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/*lista clienti care asteapta
avem timer->creaza action event care il tratam in action performed--crestem timpul simu;larii cu 1 in action performed,apoi parcurgem lista de clienti care ast si verificam care clienti au timpul de arival = timpul simulatrii
--fiecare client e distribuit la una din cozi-for pt fiecare client. gasim coada cu timpul min de asteptare si il adaugam acolo--tot in action performed
daca timpul de servire a ajun l;a 0 clientul e scos din coada
*/
public class Magazin extends JFrame{
//protected ArrayList<Clienti> arrayClienti = new ArrayList<Clienti>();
public Magazin(){
}
class event implements ActionListener{
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
int count = 0;
count++;
TimeClass tc=new TimeClass(count);
Timer timer= new Timer(1000,tc);
timer.start();
//System.out.println(count+"sec:");
}
}
class TimeClass implements ActionListener{
int counter;
public TimeClass(int counter){
this.counter=counter;
}
public void actionPerformed(ActionEvent tc) {
counter++;
System.out.println("sec:"+counter);
}
}
}
In the Main class I have this:
public class Main {
public static void main(String args[]) {
new Magazin();
}
You need to create and display a top-level window for something to be visible, this means that since you're using a JFrame, somewhere in code you'll need a main method, and that somewhere in code that is called, you'll need:
Magazin magazin = new Magazin(); // create your JFrame
magazin.setVisible(true); // display it.
I don't see a main method anywhere or your setting a JFrame visible. You've got other problems as well, but this is the first step you'll need for creating a visible GUI.
Some other issues:
You've got an ArrayList of something, Clienti, that is never used.
You've got no component, such as a JLabel, displaying your Time.
Your Timer's ActionListener creates a new JFrame -- why would it want to do that?
Your Magazin class has an actionPerformed method -- why? It's not acting as an ActionListener and does not implement ActionListener.
You will want to study the Swing tutorials to better understand how to use these tools. You can find links to the Swing tutorials and to other Swing resources here: Swing Info

ActionListener call blocks MouseClick event

I have a window with a MenuItem "maddbound3" with the following ActionListener:
maddbound3.addActionListener
(
new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
menu_addbound3();
}
}
);
When the menu is clicked this listener calls menu_addbound3() below:
void menu_addbound3()
{
while(getEditMode() != EditMode.NONE)
{
System.out.println("!... " + getEditMode());
synchronized(this)
{
try
{
wait();
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
}
A MouseClicked event alters the value of the edit mode and issues a notifyAll() so that the while loop should exit. However, tests have shown that when the system is running through the while loop, the MouseClicked event never occurs on clicking the mouse.
Does the ActionListener block the MouseClicked event? How can I resolve this issue?
Thanks
Don't have a while(true) on the Swing event thread, and likewise don't call wait() on the Swing event thread -- you'll freeze the whole GUI making it completely unresponsive. You need to understand that the main Swing event thread or "event dispatch thread" is responsible for all Swing drawing and user interaction, and so if you tie it up with long-running or freezing code, you lock your entire GUI.
Instead, change the state of your program -- perhaps by setting a variable or two, and have the behavior of your program depend on this state. If you need more specific advice, please tell us what behavior you're trying to achieve, and we can perhaps give you a better way of doing it.
For more on the Swing event thread, please read: Lesson: Concurrency in Swing
Edit
You state:
When the user clicks the menu item I want to obtain information via a series of "discrete" mouse clicks from the window. Hence, on clicking the menu, the user would be prompted to "select a point in the window". So, what I need is for my ActionListener function (menu_addbound3) to then wait for a mouse click. Hence the wait/notify setup. A mouse click changes the edit_mode and notifyAll() causes the wait in the while loop to exit which then causes the while loop to exit and I can then prompt for my next bit of information within the menu_addbound3 function, repeating this as as I need to.
Thanks for the clarification, and now I can definitely tell you that you are doing it wrong, that you most definitely do not want to use the while loop or wait or notify. There are many ways to solve this issue, one could be to use some boolean or enum variables to give the program a state and then alter its behavior depending on the state. Your EditMode enum can be used in the MouseListener to let it know that its active, and then you could also give the MouseListener class a boolean variable windowPointSelected, set to false, and then only set it true after the first click has been made.
Edit 2
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class ProgState extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final Color EDIT_COLOR = Color.red;
private EditMode editMode = EditMode.NONE;
private boolean firstPointSelected = false;
private JMenuBar jMenuBar = new JMenuBar();
private JTextField firstPointField = new JTextField(15);
private JTextField secondPointField = new JTextField(15);
public ProgState() {
add(firstPointField);
add(secondPointField);
JMenu menu = new JMenu("Menu");
menu.add(new JMenuItem(new AbstractAction("Edit") {
#Override
public void actionPerformed(ActionEvent arg0) {
setEditMode(EditMode.EDITING);
setFirstPointSelected(false);
}
}));
jMenuBar.add(menu);
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent mEvt) {
if (getEditMode() == EditMode.EDITING) {
Point p = mEvt.getPoint();
String pStr = String.format("[%d, %d]", p.x, p.y);
if (!isFirstPointSelected()) {
firstPointField.setText(pStr);
setFirstPointSelected(true);
} else {
secondPointField.setText(pStr);
setEditMode(EditMode.NONE);
}
}
}
});
}
public void setEditMode(EditMode editMode) {
this.editMode = editMode;
Color c = editMode == EditMode.NONE ? null : EDIT_COLOR;
setBackground(c);
}
public EditMode getEditMode() {
return editMode;
}
public void setFirstPointSelected(boolean firstPointSelected) {
this.firstPointSelected = firstPointSelected;
}
public boolean isFirstPointSelected() {
return firstPointSelected;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public JMenuBar getJMenuBar() {
return jMenuBar;
}
private static void createAndShowGui() {
ProgState progState = new ProgState();
JFrame frame = new JFrame("EditMode");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(progState);
frame.setJMenuBar(progState.getJMenuBar());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
enum EditMode {
NONE, EDITING
}
From the discussion it seems that having your class assume a number of states is the best way to proceed. We can achieve this by one or more enum variables. The reason I found this so hard to grasp initially is that I couldn't see the benefit of having all of ones code in the MouseClicked function. This is ugly and unmanageable at best.
However, using multiple enums and splitting processing into a number of external functions, we do indeed achieve a nice system for what we want.

Categories

Resources