I currently have a JTextField and inside that, I have default text.
The problem I currently have is getting that JTextField to have a working ActionListener. I have added an action listener to the component, but when I use FocusListener to check for focus, it will not give any output/reply.
Any help will be much appreciated. And please supply me with some example code of what I should change, thanks.
PS. I am using this class as a component from another class, so in another class I wrote:
window.add(smartTextField);
SmartText.java
package com.finn.multiweb;
import java.awt.Color;
import javax.swing.JTextField;
public class SmartText extends JTextField {
private static final long serialVersionUID = 1L;
JTextField textField = new JTextField();
String defaultText;
boolean hasDefaultText;
public SmartText() {
super();
hasDefaultText = false;
notFocused();
}
public SmartText(String defaultText) {
super(defaultText);
this.defaultText = defaultText;
hasDefaultText = true;
notFocused();
}
private void notFocused() {
super.setForeground(Color.GRAY);
if (hasDefaultText == true) {
super.setText(defaultText);
} else if (hasDefaultText == false) {
super.setText("");
}
}
private void isFocused() {
super.setForeground(Color.BLACK);
super.setText("");
}
private void focusGained(java.awt.event.FocusEvent evt) {
System.out.println("test");
}
}
You've not added a FocusListener to the field
// You need to implement the FocusListener interface
public class SmartText extends JTextField implements FocusListener {
private static final long serialVersionUID = 1L;
JTextField textField = new JTextField();
String defaultText;
boolean hasDefaultText;
public SmartText() {
super();
hasDefaultText = false;
notFocused();
// Then register yourself as interested in focus events
addFocusListener(this);
}
public SmartText(String defaultText) {
super(defaultText);
this.defaultText = defaultText;
hasDefaultText = true;
notFocused();
// Then register yourself as interested in focus events
addFocusListener(this);
}
// Then implement the contract of the FocusListener interface
public void focusGained(FocusEvent e) {
}
public void focusLost(FocusEvent e) {
}
Take a read through How to Write a Focus Listener for more details
From the looks of your code, you trying to add "prompt support" to the field, you may consider using the PromptSupport from the SwingLabs, SwingX libraries, for example
You can use the Text Prompt which is a single class.
To work with FocusListener Interface and in order to listen’s the keyboards gaining or losing focus, the listener object created from class is need to registered with a component using the component’s addFocusListener() method. The two important method focusGained(FocusEvent e) and void focusLost(FocusEvent e) which helps to find which component is focused.
Take a read through What is FocusListener Interface and How it Work and Validate Text Field Using FocusListener Interface in Java for more details with proper examples.
Related
What the program is supposed to do is to mimic the "spin" button with the enter key. The program works and it doesn't crashes but eclipse console is giving me a "Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: javax.swing.JTextField cannot be cast to javax.swing.JButton" error.
//.. gui code
spin = new JButton("Spin");
bet = new JTextField("");
play p = new play();
spin.addActionListener(p);
keys k = new keys();
bet.addKeyListener(k);
}
private class play implements ActionListener{
public void actionPerformed(ActionEvent e) {
JButton src = (JButton) e.getSource();
if(src.equals(spin)) {
//do something
}
}
private class keys implements KeyListener{
#Override
public void keyTyped(KeyEvent e) {
char c= e.getKeyChar();
if(c == KeyEvent.VK_ENTER) {
spin.doClick();
}
}
//.. the other override methods
}
EDIT
there are 2 more buttons, I just didn't include them since they worked fine and functioned differently.
JTextField has a KeyListener because I was filtering out numbers from letters so I would consume the event. Can't have a user bet with letters right?
I would guess that your ActionListener is receiving events from multiple objects, one of which is a JTextField. The exception occurs when you try to cast this object to JButton:
(JButton) e.getSource();
There may be a better solution but from what you've shown us the easiest way to prevent the exception is to check that the object generating is an event is an instance of JButton before casting:
private class play implements ActionListener{
public void actionPerformed(ActionEvent e) {
Object src = e.getSource();
// Check type before casting
if (src instanceof JButton) {
JButton bsrc = (JButton)src;
if(bsrc.equals(spin)) {
//do something
}
}
}
}
First, don't use KeyListener for this task, JTextField already supports ActionListener and you could make use of JRootPane's "default button" support as well, so a number of better solutions are available.
You should also take advantage of the actionComamnd support of the ActionEvent (and ActionListener), which will mean you don't have to cast the source, which is safer and makes the solution more re-usable (as it's decoupled).
For example...
Play p = new Play();
spin = new JButton("Spin");
spin.setActionCommand(Play.COMMAND);
bet = new JTextField("");
bet.setActionCommand(Play.COMMAND);
spin.addActionListener(p);
bet.addActionListener(p);
//...
private static class Play implements ActionListener {
public static String COMMAND = "Spin";
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals(COMMAND)) {
//do something
}
}
}
Alternatively, you could make use of the existing Actions API. This allows you to design a self contained unit of work that can be applied directly to a number of Swing components (which already support the ActionListener API), but which are also self configurable, neat...
private class SpinAction extends AbstractAction {
public SpinAction() {
putValue(NAME, "Spin");
}
#Override
public void actionPerformed(ActionEvent event) {
// Spin me baby
}
}
And then simply apply it...
SpinAction action = new SpinAction();
spin = new JButton(action);
bet = new JTextField("");
bet.setAction(action);
See How to use actions for more details
I also wanted to make the input dynamic so that it changes the value as i press any key. Thanks i dont know how to use a keylistener or something that would process my code.
public static void DecimalToAll(String varInput){
//DeciToHexa
int varDeciToHexa = Integer.parseInt(varInput);
String DeciToHexaAnswer = Integer.toHexString(varDeciToHexa);
System.out.println(DeciToHexaAnswer.toUpperCase());
//DeciToOctal
int varDeciToOctal = Integer.parseInt(varInput);
String DeciToOctalAnswer = Integer.toOctalString(varDeciToOctal);
System.out.println(DeciToOctalAnswer);
//DeciToBinary
int varDeciToBinary = Integer.parseInt(varInput);
String DeciToBinaryAnswer = Integer.toBinaryString(varDeciToBinary);
System.out.println(DeciToBinaryAnswer);
An example making use of DocumentListener:
JTextField can't add a "ChangeListener" like other components. To "monitor' changes in a JTextField, you can add a DocumentListener to the textfield:
private class MyDocumentListener implements DocumentListener
{
public void changedUpdate(DocumentEvent e){
//Do nothing
}
public void insertUpdate(DocumentEvent e){
//Do things when text are inserted
}
public void removeUpdate(DocumentEvent e){
//Do things when text are deleted
}
}
To add the DocumentListener, get the Document object from JTextField and add it:
JTextField txt = new JTextFeld();
txt.getDocument().addDocumentListener(new MyDocumentListener());
I'm trying to do a simple calculator program by building my swing interface on netbeans.
I want to have 3 Classes:
GUI Class - which holds the codes for building the interface
Listener Class - holds all the listener in the GUI interface
Boot Class - this will start the application
For simplicity, I will post my code for a single button. My goal here is to change the Buttons visible text from "1" to "11" to test my design. After verifying that my design works I will continue on working on other buttons.
calculatorGUI.class
import javax.swing.JButton;
public class calculatorGUI extends javax.swing.JFrame {
public calculatorGUI() {
initComponents();
}
private void initComponents() {
oneBtn = new javax.swing.JButton();
oneBtn.setText("1");
}
private javax.swing.JButton oneBtn;
public JButton getOneBtn() {
return oneBtn;
}
public void setOneBtn(String name) {
oneBtn.setText(name);
}
}
Listener.class
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Listener {
class oneBtnListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent ev) {
calculatorGUI g = new calculatorGUI();
g.setOneBtn("11");
}
}
}
Boot.class
public class Boot {
public static void main(String[] args) {
calculatorGUI gui = new calculatorGUI();
Listener listen = new Listener();
Listener.oneBtnListener oneListen = listen.new oneBtnListener();
gui.getOneBtn().addActionListener(oneListen);
gui.setVisible(true);
}
}
The problem is, nothing happens when I click the button. It seems that the actionListener is not being registered to the button. Can I ask for your help guys on which angle I missed?
The issue I am seeing is how you are initializing calculatorGUI twice, once with the default value and another with the changed value. Take out the initialization of calculatorGUI within your Listener class and pass it from your Boot class and it should work fine.
Although if I were you, I would add the GUI implementations within the GUI class, having it within the listener class that is using within the main function is not something I have seen before and would probably not advise.
Modify your code accordingly,
class Listener {
class oneBtnListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent ev) {
if(ev.getActionCommand() == "1")
{
JButton btn = (JButton)ev.getSource();
btn.setText("11");
}
}
}
}
class calculatorGUI extends javax.swing.JFrame {
public calculatorGUI() {
initComponents();
}
private void initComponents() {
oneBtn = new javax.swing.JButton();
oneBtnListener btnListener = new Listener().new oneBtnListener();
oneBtn.setText("1");
oneBtn.setBounds(100,100,100,25);
oneBtn.addActionListener(btnListener);
add(oneBtn);
setLayout(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400,400);
}
private javax.swing.JButton oneBtn;
public JButton getOneBtn() {
return oneBtn;
}
public void setOneBtn(String name) {
oneBtn.setText(name);
}
}
You can change now other part according to your requirement, I just
gave you "1" -> "11", but you can do more.
Best of Luck.
There's a text field and when lost focus it will validate the inputs, if not passed, print out the error message (to be simple here just has an empty check). And there's a button next to the text field, it will print out the text once click on it.
As I tried, when input some text and then click the button it will trigger both the focus lost event of text field and the event of button. In a other word, it will do the validation first and then print out the input text.
Here comes my question, what is the good approach to prevent printing out the text if the validation not passed? Or is there a way to "ignore" the click event on button if validation not passed?
I tried to use a boolean flag which indicate the validation result and check the flag when perform the action for button, but I do not think it is a good approach. As I know there's an event dispatcher thread in Swing which deal with the events, is it possible I can cancel the events from here?
Below is a piece of code which explain the question:
public class SimpleDemo
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel content = new JPanel(new FlowLayout());
frame.setContentPane(content);
final JTextField textField = new JTextField(10);
textField.addFocusListener(new FocusAdapter()
{
#Override
public void focusLost(FocusEvent e)
{
String text = textField.getText();
// do some validation here, if not validated
// do not trigger the event on button.
if ("".equals(text))
{
System.out.print("please input a text!");
}
}
});
content.add(textField);
JButton button = new JButton("Print Text");
button.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
// action performed for button
String text = textField.getText();
System.out.println(text);
}
});
content.add(button);
frame.setVisible(true);
frame.pack();
}
}
I faces similar issue while working on an application. I solved it like below
I created a abstract class ApplicationFrame which every frame in the application extends
public abstract class ApplicationFrame extends JFrame implements ActionListener {
#Override
final public void actionPerformed(ActionEvent event) {
if(validateInput()){
performAction(event);
}
}
/*
* Sub class should override this method to receive any action
*/
protected void performAction(ActionEvent event) {};
/*
* Sub class should override this method to perform validation
*/
abstract protected boolean validateInput();
}
All Frames will now extend this base frame, as below:
public class Frame1 extends ApplicationFrame{
#Override
protected void performAction(ActionEvent event) {
// perform action
}
#Override
protected boolean validateInput() {
// return true or false depending upon the validation results
}
// if you want to add Action Listener, you need to add like this:
btnSomeButton.addActionListener(this);
}
If you need to handle Focus events, you can make ApplicationFrame or the base frame implement FocusListener.
This is my custom implementation to solve the problem, hope this helps.
Make the button disabled on start-up
Upon lost focus, validate the text & enable button only when the input passes validation.
Upon start of text change, disable the button
It's always makes sense to make ui to communicate with user. So you can show "please input a text" as the default text of the textField when nothing is entered by user.
Here is the code for such custom textField:
public class TextFieldWithDefaultText extends JTextField implements FocusListener{
private final String hint;
public TextFieldWithDefaultText (String $text)
{
super($text);
this.hint = $text;
addFocusListener(this);
}
#Override
public void focusGained (FocusEvent $e)
{
if (this.getText().isEmpty())
{
super.setText("");
}
}
#Override
public void focusLost (FocusEvent $e)
{
if (this.getText().isEmpty())
{
super.setText(hint);
}
}
#Override
public String getText ()
{
String typed = super.getText();
return typed.equals(hint) ? "" : typed;
}
}
Write the acttionListerner for your button like this:
JButton button = new JButton("Print Text");
button.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
if(!textField.getText().isEmpty())
System.out.println(textField.getText());
}
});
And ur textField implementation should be :
final TextFieldWithDefaultText textField = new TextFieldWithDefaultText ("please input a text");
Hope this helps :)
I am working on an assignment, and I need to enter an SQL Query in a textfield. The user can either press the custom 'execute query' button, or they can press the enter key. When either of these are used, it is to trigger an ActionListener (no other listener is allowed). Is it as simple as writing:
if (e.getSource()=='querybutton' || e.getSource=='enter')
Or is there more to it than this?
As I said, it is a simple question (I know).
edit:
I would write this bit in my ActionPerformed as:
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==gui.executeQueryButton || e.getSource()==gui.enter)
{
String query = gui.queryText.getText();
//more code to follow
}
}
e.getSource() actually returns the object responsible for firing the event (not the name of the variable you used when creating the control). In this case, your button. You could in principle compare e.getSource() with the actual button instances. However, are you actually adding this action listener to buttons other than those two? Presumably you'd only have to add this listener to the two buttons for which you want this behavior -- in which case you wouldn't have to have this if check.
" Is it as simple as writing:
if (e.getSource()=='querybutton' || e.getSource=='enter')"
It's not simple to write this, but rather it is wrong to write it.
For one you don't want to compare Strings with ==, for another, you don't declare Strings with single quotes, and for a third, the enter key is not obtained in this way, but rather by adding the appropriate ActionListener object to the JTextField itself, and finally there should be in a single ActionListener class that handles this action, so the if block is completely unnecessary. This can probably be best done with a small inner private ActionListener class. You'd then create one object of this class and add it as an ActionListener for the querybutton and for the JTextField.
edit 1:
A more complete example of what I mean is shown below, a demo class that has a private inner handler class:
import java.awt.event.*;
import javax.swing.*;
public class ActionListenerEg extends JPanel {
private JButton queryButton = new JButton("Query");
private JTextField textField = new JTextField("hello", 20);
public ActionListenerEg() {
QueryListener qListener = new QueryListener();
queryButton.addActionListener(qListener);
textField.addActionListener(qListener);
add(queryButton);
add(textField);
}
private class QueryListener implements ActionListener {
public void actionPerformed(ActionEvent arg0) {
String textInField = textField.getText();
System.out.println("Use text in field, \"" + textInField + "\" to call SQL query in a background SwingWorker thread.");
}
}
private static void createAndShowUI() {
JFrame frame = new JFrame("ActionListenerEg");
frame.getContentPane().add(new ActionListenerEg());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
The ActionListener is fired either by pressing the button or by pressing enter from within the JTextField. I'd then have in my control class, code that is called inside of the actinoPerformed method.
edit 2: Having most handler or "control" code in its own Handler or Control class can be a good idea, but it doesn't have to implement ActionListener interface itself, but rather just have the code that will be called from within the ActionListener codes. For example, here I try to put all the handler code in its own class. It will have different methods that are called for various situations. e.g.,
import java.awt.Component;
import java.awt.event.*;
import javax.swing.*;
public class ActionListenerEg extends JPanel {
private ActionListenerHandler handler;
private JButton queryButton = new JButton("Query");
private JButton displayButton = new JButton("Display");
private JTextField textField = new JTextField("hello", 20);
// pass in handler or handler
public ActionListenerEg(final ActionListenerHandler handler) {
this.handler = handler;
QueryListener qListener = new QueryListener();
queryButton.addActionListener(qListener);
textField.addActionListener(qListener);
displayButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (handler != null) {
handler.displayActionPerformed(e);
}
}
});
add(queryButton);
add(textField);
add(displayButton);
}
private class QueryListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (handler != null) {
String textInField = textField.getText();
handler.doQueryAction(e, textInField);
}
}
}
private static void createAndShowUI() {
ActionListenerHandler handler = new ActionListenerHandler();
JFrame frame = new JFrame("ActionListenerEg");
frame.getContentPane().add(new ActionListenerEg(handler));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
class ActionListenerHandler {
public void displayActionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog((Component) e.getSource(), "Display things!");
}
public void doQueryAction(ActionEvent e, String textInField) {
String text = "We will use \"" + textInField + "\" to help create and run the SQL Query";
JOptionPane.showMessageDialog((Component) e.getSource(), text);
}
}
Please ask questions if it's clear as mudd, or if anything is wrong.