How to send focus lost event before mouse pressed event? - java

I have a simple GUI with two components: a JTextField, and a custom component (MyComponent).
Initially the text field has focus, and clicking on the custom component causes that to have focus.
Currently I am manually setting the focus using requestFocusInWindow, but the focusLost event happens after the mousePressed event has finished. Is there any way to get the focusLost event to happen before the mousePressed event finishes?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class Example {
public static void main(String[] args) {
JFrame frame = new JFrame("Example");
frame.setLayout(new FlowLayout());
JTextField textField = new JTextField(10);
textField.addFocusListener(new FocusAdapter() {
public void focusLost(FocusEvent event) {
System.out.println("focusLost");
}
});
frame.add(textField);
frame.add(new MyComponent());
frame.pack();
frame.setVisible(true);
}
private static class MyComponent extends JComponent {
public MyComponent() {
setFocusable(true);
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent event) {
requestFocusInWindow();
System.out.println("mousePressed");
}
});
}
public Dimension getPreferredSize() {
return new Dimension(400, 300);
}
}
}

It also needs to be validated (and stored)
You can use an InputVerifier on the JTextField. It will validate the text in the text field before focus is transferred. If the data is not valid focus will stay on the text field.
Edit:
Can I remove this behaviour and instead revert the text field to the previous value if the data is not valid when losing focus?
Instead of using a JTextField use a JFormattedTextField it will revert the data to the previous value. You don't need to use an InputVerifier. Read the section from the Swing tutorial on How to Use Formatted Text Fields for more information and examples.

Related

Update an entire JFrame, including all JComponents

I'm trying to update a JFrame, and all of the components in the frame, including JPanel, JLabel components, etc. I tried using revalidate(), but that didn't seem to be working. I have a JLabel in the frame displaying an int, and I have the int iterating by 1 when I click a JButton. I can see that the value of the int changes, but the actual text on the label doesn't change. I know I can use JLabel.setText(), but is there a method to use for all components, that would update the displayed text/image upon pressing a button?
Here is my code below:
package repainttest;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Window extends JFrame {
int test = 1;
JLabel label;
public Window() {
setLayout(new FlowLayout());
label = new JLabel(Integer.toString(test));
add(label);
JButton button = new JButton("Add");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
test +=1;
System.out.println(test);
refresh();
}
});
add(button);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void refresh() {
SwingUtilities.updateComponentTreeUI(this);
revalidate();
repaint();
}
}
If you do not set the new text (test) on the JLabel, it is never going to know that the value of test is changing. So, please insert following statement:
label.setText(String.valueOf(test));
in public void actionPerformed(ActionEvent e) after following statement:
test +=1;
and see the results.

How to disable automatic focus on textField

When I was creating a bunch of JTextFields I saw that first one is selected. I want to deselect it, because I have focus listener and it's running automatically. Any clues?
SSCCE:
JTextField tf = new JTextField("hello");
tf.setForeground(Color.decode("0x8C8C8C")); // for nice comment inside the text field
textFieldKwotaWplacona.addFocusListener(new FocusListener() {
#Override
public void focusGained(FocusEvent e)
{
if(tf.getForeground() != Color.BLACK)
{
tf.setText("");
tf.setForeground(Color.BLACK);
}
} #Override
public void focusLost(FocusEvent arg0) {}});
//for deleting "nice comment" after click
tf.setBounds(//some bounds);
add(tf);
Repeat that process for another text field
EDIT2 :
actual code (I believe its sscce :P)
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
public class Main extends JFrame implements ActionListener
{
JTextField textFieldKwotaWplacona, textFieldOprocentowanie, textFieldDlugoscLokaty, textFieldKwotaOtrzymana;
Main()
{ setSize(500,300);
setLayout(null);
setTitle("Program do liczenia procentu składanego");
setDefaultCloseOperation(EXIT_ON_CLOSE);
textFieldKwotaWplacona = new JTextField("Ilość pieniędzy wpłaconych");
textFieldKwotaWplacona.setForeground(Color.decode("0x8C8C8C"));
textFieldKwotaWplacona.addActionListener(this);
textFieldKwotaWplacona.addFocusListener(new FocusListener() {
#Override
public void focusGained(FocusEvent e)
{
if(textFieldKwotaWplacona.getForeground() != Color.BLACK)
{
textFieldKwotaWplacona.setText("");
textFieldKwotaWplacona.setForeground(Color.BLACK);
}
} #Override
public void focusLost(FocusEvent arg0) {}});
textFieldKwotaWplacona.setBounds(10, 10, 100, 20);
add(textFieldKwotaWplacona);
textFieldOprocentowanie = new JTextField("Oprocentowanie");
textFieldOprocentowanie.setForeground(Color.decode("0x8C8C8C"));
textFieldOprocentowanie.addActionListener(this);
textFieldOprocentowanie.addFocusListener(new FocusListener() {
#Override
public void focusGained(FocusEvent e)
{
if(textFieldOprocentowanie.getForeground() != Color.BLACK)
{
textFieldOprocentowanie.setText("");
textFieldOprocentowanie.setForeground(Color.BLACK);
}
}
#Override
public void focusLost(FocusEvent arg0) {}});
textFieldOprocentowanie.setBounds(10, 40, 100, 20);
add(textFieldOprocentowanie);
}
#Override
public void actionPerformed(ActionEvent arg0)
{
// TODO Auto-generated method stub
}
public static void main(String[] args)
{
Main a=new Main();
a.setVisible(true);
}
}
I want to set focus to window or sth else, in order to prevent text from disappearing.
As discussed in the comments, I added a radio button to take the focus instead:
public class Main extends JFrame {
JTextField textFieldKwotaWplacona, textFieldOprocentowanie;
Main() {
setTitle("Program do liczenia procentu składanego");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new FlowLayout());
textFieldKwotaWplacona = new JTextField("Ilość pieniędzy wpłaconych");
textFieldKwotaWplacona.setForeground(Color.decode("0x8C8C8C"));
textFieldKwotaWplacona.addFocusListener(new FieldFocusListener(textFieldKwotaWplacona));
add(textFieldKwotaWplacona);
textFieldOprocentowanie = new JTextField("Oprocentowanie");
textFieldOprocentowanie.setForeground(Color.decode("0x8C8C8C"));
textFieldOprocentowanie.addFocusListener(new FieldFocusListener(textFieldOprocentowanie));
add(textFieldOprocentowanie);
JRadioButton btn = new JRadioButton("text");
add(btn);
pack();
btn.requestFocusInWindow();
}
private class FieldFocusListener extends FocusAdapter {
private JTextField field;
FieldFocusListener(JTextField field) {
this.field = field;
}
#Override
public void focusGained(FocusEvent e) {
if (field.getForeground() != Color.BLACK) {
field.setText("");
field.setForeground(Color.BLACK);
}
}
}
public static void main(String[] args) {
Main a = new Main();
a.setVisible(true);
}
}
Explanation
From the tutorial:
If you want to ensure that a particular component gains the focus the first time a window is activated, you can call the requestFocusInWindow method on the component after the component has been realized, but before the frame is displayed.
That means btn.requestFocusInWindow() must appear after pack() and before a.setVisible(true).
The reason you need another component to take the focus is that when a window is focused, a component inside it must gain the focus.
Notes:
If you want a better text field hint, see #camickr's answer.
Don't use null layout. Pick one that serves your GUI design (I picked FlowLayout just because it's fast to use, though probably not what you need).
Instead of setting the size of the frame, pack() after all components had been added.
Instead of creating the same focus listener for every text field, just create it as a class and reuse it. I show one way with passing the component to a constructor, but you can get rid of that and use e.getComponent() to get the text field instance.
In your constructor, you could use the method requestFocusInWindow().
This is what was working for me here-
After creating the JFrame, call frame.requestFocusinWindow();. This will make sure your text field is not focused.
Then, when you focus on the text field, the event is being fired.
tf.setForeground(Color.decode("0x8C8C8C")); // for nice comment inside the text field
Maybe you are trying to set a prompt for the text field that disappears when the text field gains focus?
If so, check out Text Field Prompt for a solution.
If not, then post a proper SSCCE, because I still can't guess what you are trying to do.

mouseEntered and mouseExited method questions

Working on a homework assignment and I'm having issues with figuring out how to print a line of text when a mouse cursor enters and exits a certain colored area (a JPanel called panel in this case) while using the MouseListener interface.
I choose a color from the bottom panel (either Red, blue, or yellow) and then when I move to the upper panel it should be able to print which color the mouse has entered in while the mouse is in the panel and which color I exited from when my mouse finds itself outside of said panel...
Hopefully that makes sense. Here's a code snippet of what I have so far. This is for the color RED:
class RedButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
panel.setBackground(Color.RED);
class RedMouseListener implements MouseListener
{
public void mouseEntered(MouseEvent event)
{
}
public void mouseExited(MouseEvent event)
{
}
public void mousePressed(MouseEvent event) { }
public void mouseReleased(MouseEvent event) { }
public void mouseClicked(MouseEvent event) { }
}
}
}
ActionListener redListener = new RedButtonListener();
bRed.addActionListener(redListener);
Here's a relevant question from Stack Overflow Mouse moved event within JPanel
I'd recommend once you ensure that triggers are being correctly listened to (try printing "Hello World") From there you need to get the communication of the color state within the mouse event. If everything is within the same instance you can just access the variables needed within the event listener.
Here are the docs on MouseEvent http://docs.oracle.com/javase/7/docs/api/java/awt/event/MouseEvent.html
Make sure you added the mouse listener try the following
panel.addMouseListener(new RedMouseListener());
start simple making the following work
public void mouseEntered(MouseEvent event)
{
System.out.println("Hello World!");
}
if you need to access the color of the panel within the event listener try the following snippet
panel.getBackground();
This returns a Color object.
Its worth mentioning the extra class declaration can be avoided by using an anonymous inner class. see How are Anonymous (inner) classes used in Java? These overridden methods are essentially a sub class of MouseListener but we don't need to call it by name.
panel.addMouseListener(new MouseListener(){
#Override
public void mouseReleased(MouseEvent e) {}
#Override
public void mousePressed(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseClicked(MouseEvent e) {}
});
Introduction
Since this is such an old question, I thought I'd put together a simple Swing GUI to illustrate how a MouseListener works.
Here's the GUI before I do anything.
The main panel in the center will take on the selector color when the mouse is moved into the selection area. The main panel will return to it's original color when the mouse is moved out of the selection area.
Here's the GUI when my mouse is in the blue selection area.
Explanation
If you're not familiar with Java Swing, Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Learning Swing with the NetBeans IDE section. Pay close attention to the Concurrency in Swing and the Laying Out Components Within a Container sections.
When I create a Swing GUI, I use the model/view/controller (MVC) pattern. This pattern allows me to separate my concerns and focus on one part of the application at a time.
The MVC pattern implies that you create the model first, then the view, then the controller. This is more of an iterative process than a waterfall.
In Java Swing, the MVC pattern means:
The view reads information from the model.
The view may not update the model.
The controller updates the model and repaints / revalidates the view.
The model consists of one or more plain Java getter/setter classes.
The view consists of a JFrame and however many JPanels it takes to create the GUI.
There's usually not one controller "to rule them all". Each listener acts as an independent controller to manage its part of the model and view.
This is a simple application, so it consists of two model classes, one view class, and one controller class. The model is not updated at all in this example.
I did not code this entire application at one time. I wrote a few lines of code and ran tests. I made lots of changes to the code before I was satisfied with how it worked.
Model
The ColorSelection class is a plain Java getter/setter class that holds the color name, background color, and foreground color.
The MouseMovementModel class is a plain Java getter/setter class that holds the ColorSelection instances. The GUI builds the selection JPanel based on this information. If you want to add another selection color, you would add it here.
View
The view consists of a JFrame, a selection JPanel, and the main JPanel.
The JFrame has a default BorderLayout. The selection JPanel goes into the NORTH section and the main JPanel goes into the CENTER section. Only one component can be placed in a section. That component is usually a JPanel.
The selection JPanel uses a FlowLayout to hold the color selection JPanels. The color selection JPanels are created based on the number of ColorSelection instances in the application model.
A color selection JPanel is a simple JPanel created to use the information from a ColorSelection instance.
The main JPanel is a simple JPanel that will show a background color. The controller will be responsible for changing the background color.
Controller
The ColorListener class extends a MouseAdapter. The MouseAdapter class implements the MouseListener, MouseMotionListener, and MouseWheelListener interfaces. Using the MouseAdapter class allows me to implement just the mouse listener methods I'm writing code for.
The mouseEntered method sets the main JPanel to the ColorSelection color. The code is really simple. It updates the view with the ColorSelection background color.
The mouseExited method sets the main JPanel back to its original color.
Code
Here's the complete runnable code. I made the additional classes inner classes so I could post the code as one block.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class MouseMovementExample implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new MouseMovementExample());
}
private final JPanel mainPanel;
private final JPanel[] colorPanel;
private final MouseMovementModel model;
public MouseMovementExample() {
this.model = new MouseMovementModel();
this.mainPanel = createMainPanel();
this.colorPanel = new JPanel[model.getSelections().length];
}
#Override
public void run() {
JFrame frame = new JFrame("Mouse Movement Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createSelectionPanel(), BorderLayout.NORTH);
frame.add(mainPanel, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createSelectionPanel() {
JPanel panel = new JPanel(new FlowLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
ColorSelection[] selections = model.getSelections();
for (int index = 0; index < selections.length; index++) {
ColorSelection selection = selections[index];
ColorListener listener = new ColorListener(this, selection);
colorPanel[index] = createColorPanel(selection, listener);
panel.add(colorPanel[index]);
}
return panel;
}
private JPanel createColorPanel(ColorSelection selection, ColorListener listener) {
JPanel panel = new JPanel(new BorderLayout());
panel.setBackground(selection.getBackgroundColor());
panel.addMouseListener(listener);
panel.setPreferredSize(new Dimension(200, 100));
JLabel label = new JLabel(selection.getColorName());
label.setFont(panel.getFont().deriveFont(Font.BOLD, 36f));
label.setForeground(selection.getForegroundColor());
label.setHorizontalAlignment(JLabel.CENTER);
panel.add(label, BorderLayout.CENTER);
return panel;
}
private JPanel createMainPanel() {
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(200, 200));
return panel;
}
public Color getMainPanelBackground() {
return this.mainPanel.getBackground();
}
public void setMainPanelBackground(Color color) {
this.mainPanel.setBackground(color);
}
public class ColorListener extends MouseAdapter {
private final Color originalBackgroundColor;
private final ColorSelection selection;
private final MouseMovementExample view;
public ColorListener(MouseMovementExample view, ColorSelection selection) {
this.view = view;
this.selection = selection;
this.originalBackgroundColor = view.getMainPanelBackground();
}
#Override
public void mouseEntered(MouseEvent e) {
view.setMainPanelBackground(selection.getBackgroundColor());
}
#Override
public void mouseExited(MouseEvent e) {
view.setMainPanelBackground(originalBackgroundColor);
}
}
public class MouseMovementModel {
private final ColorSelection[] selections;
public MouseMovementModel() {
this.selections = new ColorSelection[3];
this.selections[0] = new ColorSelection("Red", Color.RED, Color.WHITE);
this.selections[1] = new ColorSelection("Green", Color.GREEN, Color.BLACK);
this.selections[2] = new ColorSelection("Blue", Color.BLUE, Color.WHITE);
}
public ColorSelection[] getSelections() {
return selections;
}
}
public class ColorSelection {
private final Color backgroundColor, foregroundColor;
private final String colorName;
public ColorSelection(String colorName, Color backgroundColor, Color foregroundColor) {
this.colorName = colorName;
this.backgroundColor = backgroundColor;
this.foregroundColor = foregroundColor;
}
public Color getBackgroundColor() {
return backgroundColor;
}
public Color getForegroundColor() {
return foregroundColor;
}
public String getColorName() {
return colorName;
}
}
}

component not getting added into the frame as expected

i was studying event handling and performed the following:
Created a JFrame without any component in it
i overridden the keyPressed() method in such a way that whenever a key is pressed from the keyboard,A button should appear in the frame(by using add() and then calling repaint()).
Now the thing i want to ask is that at the time of key press from the keyboard,nothing was being added to the frame,however after pressing the key when i resized the frame WINDOW,the button came out from nowhere in the frame....
what's happening?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class MyFrame extends JFrame implements KeyListener
{
private JButton bt=new JButton();
MyFrame()
{
addKeyListener(this);
}
public void keyPressed(KeyEvent ke)
{
this.add(bt);
repaint();
}
public void keyTyped(KeyEvent ke)
{
}
public void keyReleased(KeyEvent ke)
{
}
}
public class MyClass /*class containing the main method*/
{
public static void main(String args[])
{
MyFrame frm=new MyFrame();
frm.setVisible(true);
frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
,nothing was being added to the frame,
The component was added to the frame. The problem is it has a size of (0, 0) so there is nothing to paint
however after pressing the key when i resized the frame WINDOW,the button came out from nowwhere in the frame
The layout manager gets invoked and the component is given a size and location based on the rules of the layout manager. So now you see the component.
When you add a component to a visible GUI the code is:
panel.add(...);
panel.revalidate();
panel.repaint();
You need to call revalidate after adding a component to the JFrame
this.add(bt);
revalidate();
repaint();
revalidate revalidates the component hierarchy to account for any new components that may have been added.
KeyListeners don't work well for Swing applications as KeyEvents require focus to work.
This is why in Swing it is better to use Key Bindings which allow you to map an Action to a KeyStroke even when a component doesn't have focus.

Displaying a TextField on user interaction

I want to display a TextField only when user has entered a value in Input field
Here is my code:
import java.awt.BorderLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class PlayingAround {
JFrame frame;
JTextField display;
JTextField input;
public static void main(String[] args) {
PlayingAround obj = new PlayingAround();
obj.create();
}
private void create() {
frame = new JFrame();
display = new JTextField();
input = new JTextField();
display.setEditable(false);
display.setVisible(false);
input.addKeyListener(new Listener());
frame.add(BorderLayout.NORTH, display);
frame.add(BorderLayout.SOUTH, input);
frame.setSize(300, 300);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
class Listener implements KeyListener {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
display.setVisible(true);
display.setText(input.getText());
}
}
}
But my problem is that the Display JTextField doesn't becomes visible until there are some events like Resizing the Window, Minimizing and maximizing the Window.
I tried calling frame.repaint() in the keyReleased Method but even it has not helped.
You should call revalidate() and repaint() on the container that holds the JTextField after placing the text field component in the container. The revalidate() call sends a request to the container's layout managers to re-layout its components. The repaint() then requests that the JVM request of the paint manager to redraw the newly laid out container and its child components. The repaint() is not always needed but is usually a good idea.
Also, don't use a KeyListener for this, but rather a DocumentListener on the first text component's Document. This way, if the user empties the first text component, you can make the second text component disappear if desired. Also, text can be entered without key presses, and you want to allow for that.

Categories

Resources