i'm trying a very simple GUI in java.
i've just created a small GUI with buttons and when we click each button, it opens a website.
So i have have 3 buttons:
button1 = gmail
button2 = google
button3 = yahoo
when i click on button1 sometimes it opens gmail or google or yahoo.
The same problem with other button too.
Why?
Here is my very simple code:
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Gui extends Frame implements WindowListener,ActionListener {
//TextField text = new TextField(20);
Button a, b, c;
Process p1, p2, p3;
//private int numClicks = 0;
public static void main(String[] args) {
Gui myWindow = new Gui("Miquelon's");
myWindow.setSize(350,100);
myWindow.setVisible(true);
}
public Gui(String title) {
super(title);
setLayout(new FlowLayout());
addWindowListener(this);
a = new Button("Gmail");
b = new Button ("Google");
c = new Button ("Yahooooo");
add(a);
add(b);
add(c);
//add(text);
a.addActionListener(this);
b.addActionListener(this);
c.addActionListener(this);
}
public void actionPerformed(ActionEvent e)
{
try
{
{
p1 = Runtime.getRuntime().exec("cmd /c start https://mail.google.com");
p2 = Runtime.getRuntime().exec("cmd /c start https://google.com");
p3 = Runtime.getRuntime().exec("cmd /c start https://yahoo.com");
}
}
catch (IOException ex)
{
Logger.getLogger(Gui.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void windowClosing(WindowEvent e) {
dispose();
System.exit(0);
}
public void windowOpened(WindowEvent e) {}
public void windowActivated(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowDeactivated(WindowEvent e) {}
public void windowClosed(WindowEvent e) {}
}
Thank you
Your actionPerformed is running all three. You need to use actionPerformed to determine which button was pressed, and then run the corresponding command.
public void actionPerformed(ActionEvent e)
{
String address = "";
if(e.getSource() == a) address = "https://mail.google.com";
else if(e.getSource() == b) address = "https://google.com";
else if(e.getSource() == c) address = "https://yahoo.com";
else return; // not one of the three buttons, get out!
try
{
// only NEED to store the process if you want to do something with it later
// I just let mine dangle :) it works for me!
Runtime.getRuntime().exec("cmd /c start " + address);
}
catch (IOException ex)
{
Logger.getLogger(Gui.class.getName()).log(Level.SEVERE, null, ex);
}
}
You add the same ActionListener to all three buttons. And in the ACtionListener you open yahoo google and gmail. So what else did you expect?
If you don't differ in your actionPerformed method which button was pressed, then this is the correct behaviour.
There are various possibilities to solve this issue... use a ACtionListener for each button (for example anonymoous)
Or use e.getSource() to determine which button was pressed in the actionPerformed method.
For example:
if(e.getSource().equals(a)) {
address = "https://mail.google.com";
}
You don't identify each button in your actionPerformed event.
Every time the event is executed all three commands are executed
One consider naming your a to gmail so it's more descriptive.
a.addActionListener(new ActionListener() {
void actionPerformed(ActionEvent e) {
p1 = Runtime.getRuntime().exec("cmd /c start https://mail.google.com");
}
});
But in short it's running all three.
If you want to do three different things, you either need three different action listeners (one for each button) which each do one thing, or one action listener (one for all buttons) which makes an attempt to determine which button was pressed and does something based on which button called it.
What you have right now is one action listener that does all three things without regard as to which button was pressed.
You could also try setting the ActionCommand for each button so that they can all use the same event listener. This would also improve maintainability if/when you want to add a new button.
a = new Button("Gmail");
a.setActionCommand( "https://gmail.com" );
b = new Button ("Google");
b.setActionCommand( "https://google.com" );
c = new Button ("Yahooooo");
c.setActionCommand( "https://yahoo.com" );
and reimplement your listener method as such:
public void actionPerformed(ActionEvent e)
{
try
{
{
Runtime.getRuntime().exec("cmd /c start " + e.getActionEvent());
}
}
catch (IOException ex)
{
Logger.getLogger(Gui.class.getName()).log(Level.SEVERE, null, ex);
}
}
Related
I am learning Java and trying to implement a MouseListener for the first time. I have read the java doc
MouseListener but my code doesnt work, as in nothing happens when i press the button. Here is a jbutton with a pressed and released event. Can someone explain where i have gone wrong?
JButton upButton_1 = new JButton("Up");
upButton_1.addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent pevt) {
upButtonPressPerformed(pevt);
}
public void mouseReleased(MouseEvent revt) {
upButtonReleasePerformed(revt);
}
public synchronized void upButtonPressPerformed(
MouseEvent pevt) {
resultsTextArea.setText("Up Button Activated, String: " + downString);
try{
//See Above comments for sending ASCII String
byte[] bytes = DatatypeConverter.parseHexBinary(upString);
TwoWaySerialComm.SerialWriter sw = new TwoWaySerialComm.SerialWriter(
twoWaySerCom.serialPort.getOutputStream());
sw.out.write(bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
public synchronized void upButtonReleasePerformed(
MouseEvent revt) {
resultsTextArea.setText("Up Button released, String: " + downString);
try{
//See Above comments for sending ASCII String
byte[] bytes = DatatypeConverter.parseHexBinary(upString);
TwoWaySerialComm.SerialWriter sw = new TwoWaySerialComm.SerialWriter(
twoWaySerCom.serialPort.getOutputStream());
sw.out.write(bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
});
ActionListener is what you are looking for if you want to work with buttons.
JButton button = new JButton("SomeButton");
button.addActionListener(this);
void ActionPerformed(ActionEvent e) {
if(e.getSource() == button) {
// do whatever you want if button is clicked
}
}
Or you can use anonymous inner class:
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//do whatever you want
}
});
//or the Java8 version
button.addActionListener((e) -> {
//do whatever you want
});
Whit MouseListener you can listen to events like:
MouseClicked, MouseEntered, MouseExited, MousePresse, MouseReleased.
You could use these, but for button click its more logical to listen to your buttons not your mouse.
I am creating a virtual piano in Java. So far I have action listeners for two of the keys which work for the most part, just not after one another. For example, I hit q on the keyboard and it presses the c key and plays a c, which is what it's supposed to do. But then I want to hit the d key on the piano by hitting w on the keyboard, and it won't do it if I've already hit the q key.
// c key
JButton btnC3 = new JButton("");
btnC3.addKeyListener(new KeyAdapter()
{
#Override
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_Q)
{
btnC3.doClick();
}
}
});
btnC3.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
// play c
try
{
keys.playNote(Notes.c3.getValue());
}
catch (InterruptedException e1)
{
e1.printStackTrace();
}
catch (InvalidMidiDataException e2)
{
e2.printStackTrace();
}
}
});
// d key
JButton btnD3 = new JButton("");
btnD3.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_W)
{
btnD3.doClick();
}
}
});
btnD3.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
// play d
try
{
keys.playNote(Notes.d3.getValue());
}
catch (InterruptedException e1)
{
e1.printStackTrace();
}
catch (InvalidMidiDataException e2)
{
e2.printStackTrace();
}
}
});
btnD3.setBackground(Color.WHITE);
btnD3.setBounds(wKeyWidth*1, 0, wKeyWidth, wKeyHeight);
frame.getContentPane().add(btnD3);
Focus is the problem. It will work when the q is pressed because that button has the focus. It wont work if w is pressed no matter if you press q first because the "q" button has the focus throughout. You should use KeyBindings instead. They work despite whatever component has focus.
Another solution would be to add the q and w button presses to a keylistener added onto the JFrame and use requestFocus() and grabFocus().
But you would need to add implementation for both the keylistener in the JFrame and the button press and release for the button.
Here is the perfect link to see how focus affects how your key presses work in swing
http://www.javaworld.com/article/2076720/core-java/focus-on-swing.html
The problem is related to key board focus, a KeyListener will only generate events when the component the listener is registered to IS focusable and HAS focus.
Obviously, when a button is "clicked" it gains focus, meaning that none of the other components can responds.
The basic answer is, use is the Use Key Bindings API.
There are a number of choices you can make, you can use the current container to register the key bindings against, for example...
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
JButton btnC3 = new JButton("");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_Q, 0), "c3");
am.put("c3", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
btnC3.doClick();
}
});
btnC3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// play c
try {
keys.playNote(Notes.c3.getValue());
} catch (InterruptedException e1) {
e1.printStackTrace();
} catch (InvalidMidiDataException e2) {
e2.printStackTrace();
}
}
});
JButton btnD3 = new JButton("");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "d3");
am.put("d3", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
btnD3.doClick();
}
});
or you can register them against in the individual components. The choice will mostly come down to how reusable you want the solution to be.
For example, you could create a Action which can be applied to both the JButton and key binding which means you don't need to programmatically click the button.
For example...
public class NoteAction extends AbstractAction {
private Note note;
private Keys keys;
public NoteAction(Note note, Keys keys) {
this.note = note;
this.keys = keys;
}
#Override
public void actionPerformed(ActionEvent e) {
keys.playNote(note.getValue());
}
}
(I don't have your code so I'm just make some of the class names up)
Then you could simply use...
NoteAction noteAction = new NoteAction(Notes.d3, keys);
JButton btnC3 = new JButton(noteAction);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_Q, 0), "c3");
am.put("c3", noteAction);
to set it up.
See How to Use Actions for more details
how can I know in main method that one button is click to continue with the execution because the code doesn't work inside the actionperfomed button.
For example this is my main method
public static void main(String args[]) {
jwindows jw = new jwindows ();
//stop until a button inside the jwindows is clicked
// codeExecuteAfterButtonClick
}
The wait and notify methods is Object exist to handle this sort of situation
final JButton button = new JButton('click to continue');
button.setAction(new AbstractAction() {
public void actionPerformed(ActionEvent ae) {
synchronized (button) {
button.notify();
}
}
});
JFrame jf = new JFrame("Window");
jf.getContentPane().add(button, BorderLayout.CENTER);
jf.setDefaultCloseOperation(...);
jf.pack();
jf.setVisible();
synchronized(button) {
try {
button.wait();
} catch (InterruptedException ex) {
System.out.println("Interrupted");
}
}
System.out.println("After button clicked");
public void actionPerformed(ActionEvent event)
{
// TODO Auto-generated method stub
JButton src = (JButton) event.getSource(); //get which button is clicked
if(src.equals(GO)) //if GO button is clicked
{
try {
runHack();
} catch (AWTException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(src.equals(STOP)) //if STOP button is clicked
{
//do nothing
FeedBack.setText(null);
FeedBack.setText("Stopped");
}
}
I have a program where when you click on a button GO, it will execute a method called runHack();
private void runHack() throws AWTException
{
FeedBack.setText(null);
FeedBack.setText("Running(This doesn't print out)");
while(true)//infinite loop
{
FeedBack.setText("This doesn't print out");
}
}
runHack() is method that runs an infinite loop. When I click on the GO button, the program freezes while executing the runHack() method. The String "Running" doesn't displayed on the JLabel FeedBack.
My question is how do you make events still available when the program is in the infinite loop? I want it so that when I press on the STOP button, the program exits out of the infinite loop. Also, I want the JLabel FeedBack to work inside the loop.
you need run this infine toop inside of a new thread .this is how to do using timer .swing timer runs in separate thread.set delay to zero.so it's act as a while(true) loop.
in your code you are blocking EDT because of long lasting task(infinite loop) .the changes you made to textfield not get update because EDT is blocked.
you need to swing timer not java.util.Timer
import import javax.swing.Timer;
declare timer
Timer t;//global declaration;
initialize //
t=new Timer(0, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
FeedBack.setText("This doesn't print out");
}
});
when button click//
JButton src = (JButton) event.getSource(); //get which button is clicked
if(src.equals(GO)) //if GO button is clicked
{
try {
t.start();
} catch (AWTException e) {
e.printStackTrace();
}
}
if(src.equals(STOP)) //if STOP button is clicked
{
//do nothing
t.stop();
FeedBack.setText(null);
FeedBack.setText("Stopped");
}
updating...
a complete example
import java.awt.AWTException;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.Timer;
public class example extends JFrame implements ActionListener{
Timer t;
private final JTextField FeedBack;
private JButton go;
private JButton stop;
int i=0;
public example() {
FeedBack=new JTextField("initial text");
go=new JButton("go");
stop=new JButton("stop");
go.addActionListener(this);
stop.addActionListener(this);
this.setLayout(new GridLayout(1, 3));
this.add(go);
this.add(stop);
this.add(FeedBack);
this.setVisible(true);
t = new Timer(0, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
FeedBack.setText(i+"");
i++;
}
});
}
public void actionPerformed(ActionEvent event) {
JButton src = (JButton) event.getSource();
System.out.println(src);
if (src==go) //if GO button is clicked
{
t.start();
}
if (src==stop) //if STOP button is clicked
{
//stop timer
t.stop();
//FeedBack.setText(null);
FeedBack.setText("Stopped");
}
}
public static void main(String[] args) {
example f = new example();
}
}
output>>
Short answer:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run(){
runHack();
}
}).start();
Just take in account that there are better ways to spawn new Threads like using an Executor. Like someone commented, Threads is a broad topic, you should read the documentation.
[EDIT]
Like #Hovercraft Full Of Eels said is not Thread safe calling in a new Thread modifications of the UI.
Somehow I cannot access & close a JFrame with.dispose(), and it gives me a nullPointerException. Neither do I want to do a System.exit(0). How do I access the JFrame directly, is there a workaround to close the JFrame?
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
frame = new ScannerUI();
frame.setVisible(true);
}
catch (Exception e)
{
e.printStackTrace();
}
}
});
}
... (further down, and I cannot access the JFrame already, gives me a nullpointerexception)
btnBack.setBounds(400, 270, 80, 40);
panel.add(btnBack);
btnBack.setText ("BACK");
btnBack.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//ScannerUI.DISPOSE_ON_CLOSE();
//frame.dispose();
//this.dispose();
//frame.setVisible(false);
//System.out.println ("dsakjf;dsalkhfsa;lklf");
//System.exit(0);
//JFrame test = ScannerUI.frame;
//test.dispose();
// p = false;
System.out.println ("asdfasfas");
System.exit(frame.dispose());
}
});
You could use the SwingUtilities method, getWindowAncestor, to help you get the window that holds the button and then call dispose on it:
btnBack.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
AbstractButton button = (AbstractButton) e.getSource();
Window window = SwingUtilities.getWindowAncestor(button);
window.dispose();
}
});
Another option is to get the enclosing object of the current class (if it is the JFrame). You can get this from within your anonymous inner class by using the class name, a period, followed by this, or for you: ScannerUI.this:
btnBack.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
ScannerUI.this.dispose();
}
});
You can also check out Closing an Application and use the ExitAction. This is a more generic solution that will simulate a user clicking the "X" on the window. In this case any WindowsListeners you have added to the frame will be invoked first before the window is closed.
May not be applicable in this case, but just something to think about.