Do I have to work with an ActionListener or AbstractAction?
EDITED BASED ON ANSWERS
So, the best way this is the best way to do it?
Action closeaction = new AbstractAction("Afsluiten"){
#Override
public void actionPerformed(ActionEvent ae) {
System.exit(1);
}
};
menuItem = new JMenuItem(closeaction);
As #kleopatra comments, Action is the preferred abstraction, and AbstractAction is the right base class. In your handler, a non-zero status signifies an error condition. As an alternative, consider sending a WINDOW_CLOSING event, as shown here for JDialog.
Addendum: The WINDOW_CLOSING event is convenient if your application needs to take some action before terminating. Add a WindowListener to the example to see the effect:
this.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.out.println(e);
}
});
Related
I am building a text editor and I don't know how to handle a listener on Swing exit button, which is create automatically.
I want to use dialogs when user doesn't save file, for example press exit button.
final JFrame f = new JFrame("Good Location & Size");
// make sure the exit operation is correct.
f.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
f.addWindowListener( new WindowAdapter() {
public void windowClosing(WindowEvent we) {
// pop the dialog here, and if the user agrees..
System.exit(0);
}
});
As seen in this answer to Best practice for setting JFrame locations, which serializes the frame location & size before exiting.
Assuming you have a handle on your window, assuming it's a Window object (e.g. a JFrame or other kind of window), you can listen to WindowEvent events. Here is an example with windowClosed, you can replace it with windowClosing if you need to intercept it before.
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosed(WindowEvent e) {
// do something here
}
});
Go stepwise:
Declare a boolean variable saved and set its default value to false.
When user saves the file, change it to true
When exit button is pressed, check the variable.
If true, exit, else, prompt user for saving file.
So, finally this code snippet looks like:
public boolean saved = false;
saveButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
saved = true;
//Code to save file
}
});
exitButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(saved)
System.exit(0);
else {
//Code to prompt user to save file
}
}
});
I have a Question on performing other buttons action with single button click. Some example code for three buttons:
JButton a = new JButton("a");
a.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Action of a is Here
}
});
JButton b = new JButton("b");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Action of b is Here
}
});
Those should come together, like:
JButton c = new JButton("c");
c.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Action of c is Here
// Action of a
// Action of b
}
});
In the above example i have three buttons a,b,c with its own action; but as you can see, C also has to run the actions of A and B. What are good ways to address this?
The other answers are all correct, but there is one important aspect missing here: be careful about dong "too many things" on the AWT event dispatcher thread.
Meaning: when a button is clicked, an event gets created, and the UI framework uses that special thread to trigger the registered listeners. If one of the listeners now decides to do a intensive computation ... the UI event threads stays busy doing "that". And while doing "that thing"; this thread isn't available to dispatch any other UI event.
So, this is "not only" about creating methodA(), methodB(), methodC() and invoking them in your third action listener. It is also about understanding if combining multiple calls becomes subject to "I should better run those things in a separate thread; to not block the event dispatcher thread".
In that sense: the other answers tell you where to go from here; but be really careful about the "amount of activity" that your "joined actions" button is about to create!
1) Methods
Use methods for each action and call those in the ActionListener.actionPerformed
public void methodA(){}
public void methodB(){
methodA();
}
2) Action instance
You could create your own classes of ActionListener to perform the actions
First action :
class ActionA implements ActionListener{
public void actionPerformed(ActionEvent e) {
...
}
}
An improved action
class ActionB extends ActionA{
public void actionPerformed(ActionEvent e) {
super.actionPerformed(e); //Will call the first action
...
}
}
This is limited since you can't have multiple extends but is also a nice solution
3) Click
Last but I don't like it, use AbstractButton.doClick to dynamicly click on other buttons.
4) Add multiple action
Just notice that the methods is not a setActionListener but a addActionListener meaning that it will accept multiple ActionListener.
So define create two instances
ActionListener listenerA = new ActionLisener ..
ActionListener listenerB = new ActionLisener ..
buttonA.addActionListener(listenerA);
buttonB.addActionListener(listenerB);
buttonC.addActionListener(listenerA);
buttonC.addActionListener(listenerB);
With a small test, I notice that the actions are execute in the order B -> A (might not be a generality).
As said in comment, this should be us knowing the risk, this will . If an action failed because of an exception, should the next one be executed ? By default it won't because the process will not hide exceptions.
I would restrict this solution to GUI management like reseting fields, disabling, ... that could be use in different buttons.
Whatever you want to do on Button click a, you can put in a method and call it from wherever you want.
public void methodForA(){
// do here what you want
}
You can call this now in the methods you want it to call from. In your case from button click A and button click C
JButton a = new JButton("a");
a.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
methodForA();
}
});
// and also in your c-Button
JButton c = new JButton("c");
c.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Action of c is Here
methodForA();
}
});
Create 3 methods for each button indepently from the actionListeners action Perform method and call them from the actionPerfomed methods:
private void btnAClicked(){};
private void btnBClicked(){};
private void btnCClicked(){};
JButton c = new JButton("c");
c.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
btnCClicked();
btnAClicked();
btnBClicked();
}
});
I've already this project, but I'm having more problems. The dialog for SetMusicDialog opens, but it won't close when I try to exit out. I have a System.exit, but I'm not sure why the window won't close.
import java.awt.*;
import java.io.*;
public class SetMusicDialog extends Dialog
{
public static String sng;
public SetMusicDialog()
{
super ((Dialog)null, "Set Music");
Panel mpanel;
Font l = new Font("Helvetica", Font.ITALIC, 12);
setFont(l);//sets font
setBackground(Color.cyan);
Panel f = new Panel();
f.add("West", new Button("Death Grips"));
f.add("East", new Button("Siren"));
add("South",f);
pack(); // make it just fit
resize(preferredSize());
move(200,200);
}
public boolean handleEvent1 (Event evt)
{
switch (evt.id)
{
case Event.WINDOW_DESTROY:
System.exit(0);
dispose();
return true;
case Event.ACTION_EVENT:
if("Death Grips".equals(evt.arg))
{
sng= "breakmirrors.wav";
}
else if("Siren".equals(evt.arg))
{
sng= "bip.wav";
}
dispose();
}
return false;
}
}
You can add this:
addWindowListener( new WindowAdapter() {
public void windowClosing(WindowEvent e){
dispose();
System.exit(0);
}
});
windowClosed won't detect if the user tries to close the window. It will only run if the window has been closed. So use windowClosing.
Also, by using WindowAdapter you do not need to write all the methods of WindowListener.
I added this code in your constructor, and it works properly.
If you are using AWT, you should create a WindowListener as MadProgrammer stated. Basically, a WindowListener is a class that has methods that are run when certain window-related actions occur. To write code that will run when a Dialog (which extends Window) is closed:
//d is a dialog
d.addWindowListener(new WindowListener() {
//You'll need to implement all the abstract methods. leave them empty.
#Override
public void windowClosed(WindowEvent e) {
//Your code
}
});
Basically, you're anonymously implementing the abstract class WindowEvent. Make sure you implement all the other methods too, or you will get compiler errors. Your IDE should automatically implement all the methods.
I am working on a Java application and interfacing with an RFID reader that acts as a keyboard input device.
The application will be used for employee time tracking, so the employee should not see the code that his/her RFID tag contains.
Currently, the application opens a jFrame that asks the employee to scan their tag. This is where I would like to listen for the keyboard input.
All of the RFID tags are 10 digits, so I would like to use some kind of regex to detect when a card is scanned if possible.
If someone could point me in the right direction, or contribute some code I would be grateful.
Thanks in advance.
UPDATE:
I was able to read the input of the scanner by adding the following to the constructor of my JFrame.
addKeyListener(new KeyListener(){
#Override
public void keyPressed(KeyEvent e){ System.out.print(e.getKeyChar());}
#Override
public void keyReleased(KeyEvent e) { }
#Override
public void keyTyped(KeyEvent e) { }
});
So it is now confirmed that the Reader is just standard Keyboard input.
Here is an example of what I get for a tag: 0006459027
Now, the big question is, how do I take the characters that I got, and detect that it is a 10 digit string, and from there trigger an event to open a new frame?
First, I'd see if the RFID reader is triggering an ActionEvent to be fired when the tag is scanned. This would be the simplest approach.
Failing that, you would need to attach a DocumentListener to the fields underlying document and monitor for changes.
You'll need to decide how best to interrupt the results (as you're likely to get each letter of the RFID at a time). You could monitor the length of the document or have a javax.swing.Timer which triggers after a short delay (you'd reset the timer on each update event triggered by the DocumentListener)
Check out
JTextField.addActionListener
JTextField.getDocument().addDocumentListener
I'd suggest taking a look at DocumentFilter as well, but your interested in the final result, not modifying it.
UPDATED with DocumentListener Example
// In the classes variable decleration section...
private JTextField rfidField;
// In the classes constructor or UI init method...
rfidField = new JTextField(12);
rfidField.getDocument().addDocumentListener(new DocumentListener() {
public void handleUpdate(DocumentEvent e) {
if (e.getDocument().getLength() == 10) {
System.out.println("Trigger me happy...");
SwingUtilities.invokeLater(new Runnable() {
public void run() {
rfidField.setText(null);
}
});
}
}
#Override
public void insertUpdate(DocumentEvent e) {
handleUpdate(e);
}
#Override
public void removeUpdate(DocumentEvent e) {
handleUpdate(e);
}
#Override
public void changedUpdate(DocumentEvent e) {
handleUpdate(e);
}
});
// Now don't forget to add the field to your forms container ;)
//////
One of things I would be do when you "trigger" the code event is, once you've read it from the text field, is clear the text field (JTextField.setText(null)) - IMHO
If the RFID reader acts as a keyboard input device, try with key events:
JFrame frame = new JFrame();
// frame setup
frame.addKeyListener(new KeyAdapter(){
public void KeyPressed(KeyEvent ke)
{
System.out.println(ke);
}
});
Otherwise you have to check which kind of event it fires.
I was in a similar situation but with a bar-code scanner.
I really worked hard on a custom DocumentListener that would take care of all scenarios, and none of it worked.
Out of desperation, I added an ActionListener and it then worked very well.
Here is a code snap-shot :
try {
txtStockItemRef.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println(txtStockItemRef.getText());
DatabaseManager.peformStockItemLookupByBarcodeRef(txtStockItemRef.getText());
}
});
} catch(Exception exc) {
LiveCityRetailTools.handleExceptionWithUserMessage(exc);
}
I've implemented right mouse click for open menu listener on my main Jframe, it works fine except one problem. One out of 5 (give or take) clicks it not responding, this can be very annoying for the user. Here is my code:
contentPane = new JPanel();
contentPane.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3)
{
//Do Stuff
}
}
});
Can you please help me
You won't get clicks from sub-components of contentPane.
I think your problem is that you have added things to your panel. When the user clicks at regions occupied by a sub-component, that sub-component get's the click event.
Quick fix: I would recommend you to add the same mouse listener to all sub-components.
You are not "clicking"
A click is when the mouse is pressed and release really quickly. If you are not careful you might get events for (for instance) "pressed, moved, released" instead of "clicked".
Quick fix: use mouseReleased event instead.
Use this Code instead:
private MouseAdapter listener = new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
if (downer) {
downer = false;
if (new Rectangle(e.getComponent().getLocationOnScreen(), e.getComponent().getSize())
.contains(e.getLocationOnScreen())) {
downer = false;
// CODE
new Thread(new Runnable(){
public void run(){
//Your Listener code
}
}).start();
/// COde
}
}
}
boolean downer = false;
public void mousePressed(java.awt.event.MouseEvent e) {
downer = true;
}
};
This code only reacts if you press on the component and release on the component AND starts a new Thread for the custom task. This should work allways, because the AWT Thread isnt blocked with long calculations.