I have 2 textfields in my project. The first textfield is txtNumA and the second is txtNumB. I disabled txtNumB. When txtNumA is not empty, txtNumB will be enabled.
Well, this is part of code I've tried:
private void txtNumKeyTyped(java.awt.event.KeyEvent evt) {
if(!(txtNumA.getText().trim().equals(""))){
txtNumB.setEnabled(true);
}
else {
txtNumB.setText(null);
txtNumB.setEnabled(false);
}
}
Actually it works, but not perfect. It works only if I typed 2 or more characters in txtNumA. What I need is when I typed one character and more, txtNumB will be enabled.
What's wrong with my code?
What is happening here is,
In case of KeyTyped and KeyPressed events the input is not still given to the TextField.That's why it is not working and works after you type the second character and by that time first character must have reached the TextField.So use KeyReleased method to handle this case.
t is the first TextField and t1 is second.
t.addKeyListener(new KeyListener(){
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
JTextField bt = (JTextField)e.getSource();
if(bt.getText().trim().length()>0){
t1.setEnabled(true);
}
else
t1.setEnabled(false);
}
});
The correct way is to add a DocumentListener to the Document of your JTextField:
public final class TextFieldListener implements DocumentListener {
public static void main(final String... args) {
SwingUtilities.invokeLater(() -> new TextFieldListener().go());
}
private final JFrame frame = new JFrame();
private final JTextField field = new JTextField();
private final JTextField field2 = new JTextField();
private TextFieldListener() {
field.getDocument().addDocumentListener(this);
frame.setLayout(new GridLayout(2, 0));
frame.add(field);
frame.add(field2);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
onFieldUpdated();
}
private void go() {
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private void onFieldUpdated() {
setField2Enabled(!field.getText().isEmpty());
}
private void setField2Enabled(final boolean enabled) {
field2.setEnabled(enabled);
}
#Override
public void insertUpdate(final DocumentEvent e) {
onFieldUpdated();
}
#Override
public void removeUpdate(final DocumentEvent e) {
onFieldUpdated();
}
#Override
public void changedUpdate(final DocumentEvent e) {}
}
It is not correct to add a KeyListener to your text field if you are interested in changes to its content.
Further reading:
JTextComponent
Document
Text Component Features
How to Use Text Fields
How to Write a Document Listener
I think the problem with this working for 2 characters is because getText() method returns not updated value, i.e. it returns the value BEFORE the change. What you need to do is somehow update that value before you compare it to empty string.
You may need to investigate KeyEvent to see if user adds another character or is it e.g. backspace...
Related
I want to know how to be able to change a JLabel in java Swing to the button I press but I don't know what I'm missing something. Please help.
What it should end up looking like is on the top of the screen it will show the key being pressed and will update the JLabel as you press it. Don't worry about the Imports, I have them all in the actual code. Thanks :)
public class RandomFrame extends JFrame{
Dimension Size = new Dimension(800,800);
ListenForKeys LFK = new ListenForKeys();
JLabel JInput = new JLabel("");
JPanel P1 = new JPanel();
public static void main(String[] args) {
new RandomFrame();
}
public RandomFrame() {
super("RandomFrame");
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(Size);
P1.add(JInput);
this.add(P1);
this.setVisible(true);
}
private class ListenForKeys implements KeyListener {
#Override
public void keyPressed(KeyEvent e) {
String Key = String.valueOf(e.getKeyChar());
JInput.setText(Key);
}
#Override
public void keyReleased(KeyEvent e) {}
#Override
public void keyTyped(KeyEvent e) {}
}
}
Austin pointed out that LFK wasn't attached to anything and sure enough, I added it to the JFrame using the line this.addKeyListener(LFK) and sure enough it worked. Thank you :)
(Note: I am aware of the existence of the MouseAdapter-class, but since I am probably overriding all methods later on, the advantage of it is lost?)
I have a class MainProgram.java in which I'm adding several components. Most of them have a Listener (ActionListener, MouseListener, ...), which get's a bit crowded in my main class.
Therefore I am trying to "externalize" those Listeners into their own classes. So far I have used inner classes in my main-class, which makes accessing the variables, components, ... pretty easy and straightforward.
But with the external Listeners I am not sure what is the best way to implement them.
For example, when I want to find out, which of the lables has been clicked, I am getting the event, get the source of the event, cast it to a JLabel and then get the text on the label with which I compare a string!
This works, but seems very prone to errors (what if I change the JLabel-text in my main-class? -> Listener breaks) and pretty unclean.
I've tried to search via google and on StackOverflow for better ways to do this, but only found the inner class approach.
So is there a better way to get access to my components / externalize my listeners?
public class MainProgram extends JFrame {
public MainProgram() {
super("Landing Page");
setSize(400, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel westPanel = new JPanel();
JLabel lbl_orderStatus = new JLabel("Order Status");
JLabel lbl_technicalDocu = new JLabel("Technical Documentation");
JLabel lbl_checkReport = new JLabel("Check Report");
MouseListenerBoldFont mouseListenerLabelBoldPlain = new MouseListenerBoldFont();
lbl_orderStatus.addMouseListener(mouseListenerLabelBoldPlain);
lbl_technicalDocu.addMouseListener(mouseListenerLabelBoldPlain);
lbl_checkReport.addMouseListener(mouseListenerLabelBoldPlain);
westPanel.add(lbl_orderStatus);
westPanel.add(lbl_technicalDocu);
westPanel.add(lbl_checkReport);
add(westPanel);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
MainProgram window = new MainProgram();
window.setVisible(true);
}
catch (Exception e) {
e.printStackTrace();
}
}
});
}
The MouseListenerBoldFont.java:
public class MouseListenerBoldFont implements MouseListener{
Object lbl_westPanel;
#Override
public void mouseClicked(MouseEvent e) {
if(((JLabel)e.getSource()).getText().equals("Order Status")){
System.out.println("Order Status clicked");
};
if(((JLabel)e.getSource()).getText().equals("Technical Documentation")){
System.out.println("Technical Documentation clicked");
};
if(((JLabel)e.getSource()).getText().equals("Check Report")){
System.out.println("Check Report clicked");
};
}
#Override
public void mouseEntered(MouseEvent e) {
lbl_westPanel = e.getSource();
((JComponent) lbl_westPanel).setFont(new Font("tahoma", Font.BOLD, 12));
}
#Override
public void mouseExited(MouseEvent e) {
lbl_westPanel = e.getSource();
((JComponent) lbl_westPanel).setFont(new Font("tahoma", Font.PLAIN, 11));
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
}
sure this is not the best way but may be useful for your problem
public class MyLabel extends JLabel implements MouseListener {
public MyLabel() {
addMouseListener(this);
}
public MyLabel(String txt) {
super(txt);
addMouseListener(this);
}
public void mouseClicked(MouseEvent e) {
System.out.println(getText() + " clicked");
}
public void mouseEntered(MouseEvent e) {
setFont(new Font("tahoma", Font.BOLD, 12));
}
public void mouseExited(MouseEvent e) {
setFont(new Font("tahoma", Font.PLAIN, 11));
}
public void mousePressed(MouseEvent e) { }
public void mouseReleased(MouseEvent e) { }
}
then
JLabel lbl_orderStatus = new MyLabel("Order Status");
JLabel lbl_technicalDocu = new MyLabel("Technical Documentation");
JLabel lbl_checkReport = new MyLabel("Check Report");
// MouseListenerBoldFont mouseListenerLabelBoldPlain = new MouseListenerBoldFont();
//
// lbl_orderStatus.addMouseListener(mouseListenerLabelBoldPlain);
// lbl_technicalDocu.addMouseListener(mouseListenerLabelBoldPlain);
// lbl_checkReport.addMouseListener(mouseListenerLabelBoldPlain);
My recommendation is to write inline (anonymous-class) handlers that forward the actual handling to another, non-anonymous function. This would give you something like:
JLabel lblOrderStatus = new JLabel("Order Status");
lblOrderStatus.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent evt) {
doWhateverClickOnOrderStatusRequires();
}
});
// much later
private void doWhateverClickOnOrderStatusRequires() { ... }
The name of the external not-quite-handler method (doWhateverClickOnOrderStatusRequires) should capture the task that it attempts to achieve (for example, launchRockets); and with this pattern, you can call the same not-quite-handler method from multiple handlers. Since the compiler will check that the calls are valid a compile-time, there are no fragile string-constants involved.
You probably still want to use a class which extends MouseAdapter, since it can be used as a MouseListener, a MouseMotionListener, and a MouseWheelListener all at once (You just have to add it as all of those into a component). I'm not sure why you need to get the text on a JLabel to detect if it's the one that has been clicked. You should create a class which extends MouseAdapter and make it solely for JLabels, then add it to that JLabel. You should define a custom constructor if you want that takes a JLabel for an argument so that it will automatically know what JLabel is being interacted with. You can then add a method which passes an event to the main class.
I want to write a live search using Swing components. I am using a keyListener to keep track of the input. Basically i dont want the keyListener to take action every time a button is pressed but instead wait (for some period of time) for more incoming input. This period of time is refreshed every time a button is pressed and the input gets evaluated when it eventually times out (e.g. no button is being pressed within the period meaning that the input is complete). How do I implement that into my keyListener?
Code snippet of main method:
static JTextField nameTextField = new JTextField();
public static void main(String args[]) throws Exception {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(nameTextField, BorderLayout.NORTH);
nameTextField.addKeyListener(new KeyListener() {
public void keyTyped(KeyEvent keyEvent) {
//
}
#Override
public void keyPressed(KeyEvent e) {
//
}
#Override
public void keyReleased(KeyEvent e) {
if(waitForMoreInput(50)) {
doSomething(nameTextField.getText());
}
}
}
}
}
);
frame.setSize(250, 100);
frame.setVisible(true);
}
Thanks in advance
Much better is for you to use a DocumentListener or DocumentFilter, depending on if you want to listen before or after text has been fully registered with the text component.
The DocumentListener will register any time the text has changed, be it via a key press, via a copy and paste, via a deletion of text. The Timer will then wait however long you wish to do whatever action is required on the text. For example:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
public class DocListenerFoo extends JPanel {
private JTextField nameTextField = new JTextField(20);
public DocListenerFoo() {
add(new JLabel("Add Text:"));
add(nameTextField);
int timerDelay = 1000; // one second
nameTextField.getDocument().addDocumentListener(new MyDocListener(timerDelay));
}
private class MyDocListener implements DocumentListener {
private Timer docTimer;
private int timerDelay;
public MyDocListener(int timerDelay) {
this.timerDelay = timerDelay;
}
#Override
public void changedUpdate(DocumentEvent e) {
textChangedAction(e);
}
#Override
public void insertUpdate(DocumentEvent e) {
textChangedAction(e);
}
#Override
public void removeUpdate(DocumentEvent e) {
textChangedAction(e);
}
private void textChangedAction(DocumentEvent e) {
Document doc = e.getDocument();
try {
String text = doc.getText(0, doc.getLength());
if (docTimer != null && docTimer.isRunning()) {
docTimer.stop();
}
docTimer = new Timer(timerDelay, new TimerListener(text));
docTimer.setRepeats(false);
docTimer.start();
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
}
private class TimerListener implements ActionListener {
private String text;
public TimerListener(String text) {
this.text = text;
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO do check on text here
System.out.println("Checking text here: " + text);
}
}
private static void createAndShowGui() {
DocListenerFoo mainPanel = new DocListenerFoo();
JFrame frame = new JFrame("DocListenerFoo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Don't wait inside the key or document event, it just blocks the program from being processed further. Instead save the current time or (re)start a timer in the event and execute your action later somewhere else.
I'm guessing that you're trying to use a KeyListener with a Swing text component such as a JTextField (I have to guess since you don't tell or show us). If so, then the best solution is don't. Using a KeyListener with these components can mess up the functionality of the components. Much better is for you to use a DocumentListener or DocumentFilter, depending on if you want to listen before or after text has been fully registered with the text component.
For a better more complete answer, post a better more complete question, including your minimal code example and details about your problem.
I made a button and did a .setText() on it because I have to compare the value of the .setText() with something else.
I applied the .setText() to a JButton, but I don't want the text to be visible in my button.
If I do setVisible(false) then it hides the whole button, but I only want it to hide the text.
Is there an option for this? I've considered making a custom font and apply it on the text in the .setText() but I'm wondering if there's a more efficient option to my problem.
Thanks in advance guys.
EDIT: I can't use .setText(" ") because I have to compare the value within it.
You state:
EDIT: I can't use .setText(" ") because I have to compare the value within it.
Nonsense. As I've mentioned in a comment, set the JButton's text to " ", and don't use the JButton's text for comparison. Instead use its actionCommand easily obtained via getActionCommand(). Or use a HashMap<JButton, SomethingElse>.
You may consider changing the JButton's Action when you need to change its behavior and state which is easily done by calling setAction(...)
For example,
import java.awt.event.ActionEvent;
import javax.swing.*;
public class ButtonActions {
private static void createAndShowGui() {
JPanel mainPanel = new JPanel();
JButton myButton = new JButton();
StartAction startAction = new StartAction();
PauseAction pauseAction = new PauseAction();
BlankAction blankAction = new BlankAction();
startAction.setNextAction(pauseAction);
pauseAction.setNextAction(blankAction);
blankAction.setNextAction(startAction);
myButton.setAction(startAction);
mainPanel.add(myButton);
JFrame frame = new JFrame("ButtonActions");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class SwappingAction extends AbstractAction {
private Action nextAction;
public SwappingAction(String text) {
super(text);
}
public void setNextAction(Action nextAction) {
this.nextAction = nextAction;
}
public Action getNextAction() {
return nextAction;
}
#Override
/**
* super method needs to be called in child for swap to work
*/
public void actionPerformed(ActionEvent e) {
System.out.println("ActionCommand: " + e.getActionCommand());
((AbstractButton)e.getSource()).setAction(nextAction);
}
}
class StartAction extends SwappingAction {
public static final String START = "Start";
public StartAction() {
super(START);
}
#Override
public void actionPerformed(ActionEvent e) {
super.actionPerformed(e);
// start-specific code goes here
}
}
class PauseAction extends SwappingAction {
public static final String PAUSE = "Pause";
public PauseAction() {
super(PAUSE);
}
#Override
public void actionPerformed(ActionEvent e) {
super.actionPerformed(e);
// pause-specific code goes here
}
}
class BlankAction extends SwappingAction {
public static final String BLANK = " ";
public BlankAction() {
super(BLANK);
}
#Override
public void actionPerformed(ActionEvent e) {
super.actionPerformed(e);
}
}
Write buttonName.setText(" ") this will not display any name to the button. And whenever you feel like displaying the name (on any event) then set it again buttonName.setText("some text")
If you insist not to use setText(""), try setting same colour as a background colour and text colour. Check the below links
setBackground(java.awt.Color)
setForeground(java.awt.Color)
Why don't you name the first button " " (1 space).
the second: " " (2 spaces)
the third: " "(3 spaces) and so on ..
Now, compare:
if((event.getActionCommand()).equals(" "))
{ //1st button }
if((event.getActionCommand()).equals(" "))
{ //2nd button }
..and so on
where event is an object of ActionEvent
This way the buttons will have a unique names and be invisible.
Horrible coding, I know. But it does the trick ;)
Instead of .setText(), use .setTag() and .getTag() to attach some value to a View - including a Button - for later retrieval.
These methods are there directly for that kind of purpose.
I have a text area that I would like to become blank when the enter button is pressed. I know this would normally be done with a setText method. However when I do this, the text is removed but the new line function created by the return key being pressed. My question is, is the anyway of stopping this default action from happening?
thanks
Are you listening for the ENTER key on the text area and then clearing it? The following works for me:
final JTextArea ta = new JTextArea();
ta.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ENTER){
ta.setText("");
}
}
#Override
public void keyPressed(KeyEvent e) {
}
});
Hi
I have a text area that I would like to become blank when the enter button is pressed.
This, I understand. Here's how you can do that:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Main {
public static void main(String[]args) {
final JFrame frame = new JFrame();
final JTextArea area = new JTextArea();
area.setPreferredSize(new Dimension(200, 200));
area.addKeyListener(new KeyAdapter(){
#Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ENTER) {
area.setText("");
}
}
});
frame.add(area);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
I know this would normally be done with a setText method. However when I do this, the text is removed but the new line function created by the return key being pressed. My question is, is the anyway of stopping this default action from happening?
That, I don't understand.
The problem is probably that you are not consuming the keystroke event, and although the text area is cleared, the normal processing of the keystroke ends up inserting a newline.
Rather than trapping the keystroke event (which isn't necessarily portable) I would recommend using a DocumentFilter. There is a tutorial here that shows you how to write one. Implement the filter so that when there is a 'newline' in the insert or replace string, replace the entire contents of the document with "".
However this approach can't tell the difference between a newline typed at the keyboard and one pasted into the text area.
Before you clear the text you need to remove the new line code the return button left. You do that with the consume() method.
So to clear your text:
yourkeyevent.consume();
yourTextObject.setText("");
Instead, you can also use:
yourTextarea.setText(null);
yourTextarea.setCaretPosition(-1);
I solved your problem overriding the code in the method "public void keyTyped(KeyEvent e)" instead of "public void keyPressed(KeyEvent e)" and it works.
Here the code:
package versione1;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class WhiteEnter {
final JFrame frame = new JFrame();
private JTextArea area = new JTextArea();
public static void main(String[]args) {
WhiteEnter prova = new WhiteEnter();
prova.run();
}
public void run(){
area.setPreferredSize(new Dimension(200, 200));
area.addKeyListener(new PressEnterKeyListener());
frame.add(area);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public class PressEnterKeyListener implements KeyListener{
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
if (e.getKeyChar() == (KeyEvent.VK_ENTER)){
try{
area.setText(null);
area.setCaretPosition(0);
} catch(Exception ex){
ex.printStackTrace();
}
}
}
}
}