Mouse events from JTextField do not get propagated - java

I am trying to listen to mouse events coming from both a JLabel and a JTextField. However, I am only able to listen to mouse events from JLabel, but not JTextField.
Consider this code:
class FieldPanel extends JPanel{
JLabel label;
JTextField text;
public FieldPanel(){
label = new JLabel("This is a test label");
text = new JTextField("This is a test field");
add(label);
add(text);
}
}
class OuterPanel extends JPanel{
FieldPanel fieldPanel;
public OuterPanel(){
fieldPanel = new FieldPanel();
fieldPanel.addMouseListener(new MouseAdapter(){
#Override
public void mousePressed(MouseEvent event) {
System.out.println("Mouse pressed !!");
}
});
add(fieldPanel);
}
}
public class UITest{
public static void main (String args[]){
JFrame frame = new JFrame();
OuterPanel outerPanel = new OuterPanel();
frame.getContentPane().add(outerPanel);
frame.pack();
frame.setVisible(true);
}
}
The 'Mouse Pressed !!' message is displayed when I click on the JLabel. However, it does not get displayed when I click on the JTextField. Why is this the case?
Thanks!

I think this is an interesting question which kinda stomp on the finding accidentally. I will explain using the snippet code below.
class FieldPanel extends JPanel
{
//JLabel label;
JTextField text;
public FieldPanel()
{
//label = new JLabel("This is a test label");
text = new JTextField("This is a test field");
//add(label);
add(text);
}
}
when you run the code with the changes above, what we expect the output only the text field right? Then if you click on the area near to the textfield outside region, check in your console output, it actually print out Mouse pressed !!
So I went a little deeper to study into JTextField, it actually consist of the JTextField and JTextComponent. When you called the constructor new JTextField("This is a test field");, the text is actually set into the JTextComponent and not JTextField and I guess that is why when you click the text, it does not trigger the mousePressed event but it trigger only the JTextField only.
Below is my full code. If you want the text field to aware of the mouse pressed, consider implements MouseAdapter() in your FieldPanel class and add addMouseListener(this) for text and label.
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class MyMouseEvent extends JPanel
{
public MyMouseEvent()
{
FieldPanel fieldPanel;
fieldPanel = new FieldPanel();
fieldPanel.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent event)
{
System.out.println("Mouse pressed !!");
}
});
add(fieldPanel);
}
class FieldPanel extends JPanel
{
//JLabel label;
JTextField text;
public FieldPanel()
{
//label = new JLabel("This is a test label");
text = new JTextField("This is a test field");
//add(label);
add(text);
}
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyMouseEvent evt = new MyMouseEvent();
evt.setOpaque(true);
frame.setContentPane(evt);
frame.pack();
frame.setVisible(true);
}
public static void main (String args[])
{
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run()
{
createAndShowGUI();
}
});
}
}

Thanks for all the answers.
I found some sort of workaround. I am changing my code so that I listen directly to the JTextField component, as opposed to listening to the panel.

Related

How to make Text Field in GUI submit text into Console?

I am not sure how to make this all work together but I am supposed to make the text field display the text typed but only when we press submit. It is supposed to display the text in the console. So I need some help adding onto this to finish the code.
import java.awt.*;
import javax.swing.*;
public class testExample1 extends JFrame {
JTextField textField1;
JButton mybutton;
public testExample1() {
setSize(300, 100);
setTitle("Text Action");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new FlowLayout());
textField1 = new JTextField(10);
mybutton = new JButton("Submit");
add(textField1);
add(mybutton);
setVisible(true);
System.out.println()
}
public static void main(String args[]) {
new testExample1();
}
}
You need to add an ActionListener to your submit button.
mybutton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(textField1.getText());
}
});
Or
With Java 8 Lambda expressions:
mybutton.addActionListener(e -> System.out.println(textField1.getText()));

Update JLabel text

I'm working on a simple GUI. On Button press i want to increase/decrease a variable and update the corresponding JLabel.
class JFrameSetUp
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JFrameSetUp extends JFrame implements ActionListener {
private int RecHeight = 0;
private int RecWidth = 0;
//Here Buttons
JButton HeightIncrease = new JButton("+");
JButton HeightDecrease = new JButton("-");
JLabel height = new JLabel(Integer.toString(RecHeight));
JLabel width = new JLabel(Integer.toString(RecWidth));
GridLayout gridLayout = new GridLayout(2, 4);
public JFrameSetUp(){
}
public void addComponentsToPane(final Container pane){
//Create GridPanel and set Layout
JPanel grid = new JPanel();
grid.setLayout(gridLayout);
//Create buttondrawPanel and set Layout
JPanel buttondraw = new JPanel();
buttondraw.setLayout(new GridLayout(2, 0));
//Adding Components to GridPanel
//Adding Layouts to pane
pane.add(grid, BorderLayout.NORTH);
pane.add(new JSeparator(), BorderLayout.CENTER);
pane.add(buttondraw, BorderLayout.SOUTH);
}
#Override
public void actionPerformed(ActionEvent e) {
//Setting up ActionListener to Buttons
if (e.getSource() == this.HeightDecrease) {
RecHeight -= 1;
height.setText(Integer.toString(RecHeight));
} else if (e.getSource() == this.HeightIncrease) {
RecHeight += 1;
height.setText(Integer.toString(RecHeight));
}
}
}
Class with MainMethod
import javax.swing.JFrame;
public class Program {
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
//Create and set up the window.
JFrameSetUp frame = new JFrameSetUp();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Set up the content pane.
frame.addComponentsToPane(frame.getContentPane());
//Display the window.
frame.pack();
frame.setVisible(true);
}
}
I'm aware, that's kind a newbish question. I think I'm wrong with my Code Structure. Any help is appreciated.
Thanks in advance.
You never register any ActionListeners to the buttons...
HeightIncrease.addActionListener(this);
HeightDecrease.addActionListener(this);
You also never add the buttons to the GUI
buttondraw.add(HeightIncrease);
buttondraw.add(HeightDecrease);
You also never add the labels to the GUI either...
grid.add(height);
grid.add(width);
I reworked the code, because your example was messing with my mind, hope you don't mind...
It's conceptually the same idea, just done slightly more efficently
import java.awt.BorderLayout;
import java.awt.EventQueue;
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.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private int recHeight = 0;
private int recWidth = 0;
//Here Buttons
JButton heightIncrease = new JButton("+");
JButton heightDecrease = new JButton("-");
JLabel height = new JLabel(Integer.toString(recHeight));
JLabel width = new JLabel(Integer.toString(recWidth));
GridLayout gridLayout = new GridLayout(2, 4);
public TestPane() {
setLayout(new BorderLayout());
//Create GridPanel and set Layout
JPanel grid = new JPanel();
grid.setLayout(gridLayout);
grid.add(height);
grid.add(width);
//Create buttondrawPanel and set Layout
JPanel buttondraw = new JPanel();
buttondraw.setLayout(new GridLayout(2, 0));
heightIncrease.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
recHeight += 1;
height.setText(Integer.toString(recHeight));
}
});
heightDecrease.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
recHeight -= 1;
height.setText(Integer.toString(recHeight));
}
});
buttondraw.add(heightIncrease);
buttondraw.add(heightDecrease);
//Adding Components to GridPanel
//Adding Layouts to pane
add(grid, BorderLayout.NORTH);
add(new JSeparator(), BorderLayout.CENTER);
add(buttondraw, BorderLayout.SOUTH);
}
}
}
I would encourage you to spend some time having a look at How to Use Buttons, Check Boxes, and Radio Buttons and How to Write an Action Listeners for more details
After changing the value call
frame.repaint();
Good to see you learning Java! A few things I should point out.
Firstly, your variable names are good, but they don't follow the Java naming convention. Even though it seems small, it's just good practice to follow.
Of course, your actual problem; the action listener you've implemented is on the JFrame. (See how you extend JFrame and implement ActionListener?) This ActionListener should be on the button. You'll can do this a few ways.
Method 1: By adding it inline with your code
JButton heightButton = new JButton("Increase Height");
heightButton.addActionListener(new ActionListener(){
#Override
public void run(){
//run method here
}
});
Method 2: Create a class which implements ActionListener
class ButtonListener implements ActionListener{
#Override
public void run(){
//actionListener code here
}
}
And then instantiate an object of this type and add it directly to your code.
ActionListner buttonListener = new ButtonListener(); //or ButtonListener buttonListener = new ButtonListener();
JButton heightButton = new JButton("Increase Height");
heightButton.addActionListener(buttonListener);
Of course, as in MadProgrammers answer, don't forget to add the labels and such to your JFrame or JPanel. Good luck learning Java!
I bet that your program just shows nothing, isn't it? That's because in addComponentsToPane method, you didn't add any component but empty JPanels. After the comment //Adding Components to GridPanel, you should:
buttondraw.add(HeightIncrease);
buttondraw.add(HeightDecrease);
grid.add(height);
grid.add(width);
Then, to listen to button event, you should also add :
HeightIncrease.addActionListener(this);
HeightDecrease.addActionListener(this);
"this" is because your frame JFrameSetUp implements ActionListener, so when either bootton is clicked the method actionPerformed is invoked.
As JLabel.setText method will repaint itself and consequently its component hierarchi is repainted as well, you haven't to do anything othr.

Update JList in a JPanel

I have created a JFrame in Eclipse, and also placed a JList in the frame using the Swing design option. Eclipse puts the list in a JPanel. Next to the list, there are a few text fields(ID, name, etc.). Once the user fills the fields, and clicks 'Add', the information gets stored in a SQLite JDBC table. However, when the user clicks add, I also want the JList to update itself and display the new record in the list. The list only refreshes only when I restart the program. I have tried to revalidate() and repaint the panel created by Eclipse after the record is added to the database, as well as tried to revalidate() and repaint the list.
Register and Listener implementation . Try this code
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MyFrame extends JFrame implements ActionListener {
private JButton button = new JButton("Click me!");
private DefaultListModel<String> listModel = new DefaultListModel<String>();
private JList<String> list = new JList<String>(listModel);
private int counter = 1;
public MyFrame() {
setTitle("Test Updates");
JTabbedPane tabs = new JTabbedPane();
add(tabs, BorderLayout.CENTER);
JPanel panel = new JPanel();
panel.add(list);
tabs.add("Selections", panel);
panel = new JPanel();
button.addActionListener(this);
panel.add(button);
tabs.add("Options", panel);
pack();
}
#Override
public void actionPerformed(final ActionEvent event) {
if (button.equals(event.getSource())) {
listModel.addElement("Item " + counter++);
}
}
/* Test it! */
public static void main(String[] args) {
final MyFrame frame = new MyFrame();
frame.addWindowListener(new WindowAdapter(){
#Override public void windowClosing(final WindowEvent e) {
frame.setVisible(false);
frame.dispose();
System.exit(0);
}
});
frame.setVisible(true);
}
}

Composition vs inheritence in JButton

I'd like to create a simple table game by Swing. I have a JFrame and a JPanel variable.
I want to add JButtons to this JPanel, but I'd like to create an own class.
I made a class that extends JButton (inheritence):
public class GameField extends JButton {...}
So I could add GameFields to the JPanel.
But I'd like to create GameFields by composition:
public class GameField{
private JButton button;
}
But in this clase how I can add GameField to JPanel?
Can I solve this problem by compisition?
But in this clase how I can add GameField to JPanel? Can I solve this
problem by compisition?
You do this by adding a simple getter like this:
public class GameField{
private JButton button;
public GameField(String text) {
button = new JButton(text);
// do your stuff here
}
public JButton getButton() {
return button;
}
}
Then in your GUI:
public void createAndShowGUI() {
JPanel panel = new JPanel(new GridLayout(5,5));
panel.add(new GameField("Button # 1").getButton());
panel.add(new GameField("Button # 2").getButton());
...
JFrame frame = new JFrame("Game");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
Edit
You've stated in a comment:
Thanks, but in this case if I'd like to access this field (i.e.
panel.getComponent(i)), I can get only a JButton, and not a GameField.
You can keep a list with your GameField objects or you can use putClientProperty() method to keep a reference to the GameField object as shown in the example below:
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.JPanel;
import javax.swing.SwingUtilities;
public class Demo {
private void createAndShowGUI() {
ActionListener actionListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JButton button = (JButton)e.getSource();
GameField gameField = (GameField)button.getClientProperty("GameField");
if(gameField != null) {
System.out.println(gameField.getText());
}
}
};
GameField gameField1 = new GameField("Button # 1");
gameField1.getButton().addActionListener(actionListener);
GameField gameField2 = new GameField("Button # 2");
gameField2.getButton().addActionListener(actionListener);
JPanel content = new JPanel(new GridLayout());
content.add(gameField1.getButton());
content.add(gameField2.getButton());
JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(content);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
class GameField {
private String text;
private JButton button;
public GameField(String text) {
this.text = text;
button = new JButton(text);
button.putClientProperty("GameField", GameField.this);
}
public JButton getButton() {
return button;
}
public String getText() {
return text;
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Demo().createAndShowGUI();
}
});
}
}
If you wish your GameField objects to have JComponents and still be able to add them to other JComponents, have them extend JPanel instead of JButton.
You can then have your GameField objects as JPanels with other JComponents and add them to your JFrame.

How to add KeyListener to JComponent when mouse is entered?

I have created custom button class which extends JComponent and want to add KeyListener on mouseEntered event (and later remove on mouseExited). So my goal is - when the mouse enters this JComponent - then if I press Enter - some code will be executed, related to only this button. How can I do that?
Use Key Bindings instead of KeyListeners, since the latter is way to low level for Swing. Just bring your mouse over the JButton, and then press ENTER, then take your mouse outside the bounds of the JButton and try pressing ENTER again. Have a look at this example and see if this is what you wanted :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ButtonBinding {
private JPanel contentPane;
private JTextField tField;
private JButton button;
private KeyStroke keyStroke = KeyStroke.getKeyStroke("ENTER");
private Action action = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
System.out.println("Action Performed");
contentPane.setBackground(Color.BLUE);
}
};
private MouseAdapter mouseActions = new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent me) {
System.out.println("Mouse Entered");
JButton button = (JButton) me.getSource();
button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, "enter");
button.getActionMap().put("enter", action);
}
#Override
public void mouseExited(MouseEvent me) {
System.out.println("Mouse Exited");
JButton button = (JButton) me.getSource();
button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, "none");
contentPane.setBackground(Color.RED);
}
};
private void displayGUI() {
JFrame frame = new JFrame("Button Binding Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
contentPane = new JPanel();
contentPane.setOpaque(true);
tField = new JTextField(10);
button = new JButton("Click Me");
button.addMouseListener(mouseActions);
contentPane.add(tField);
contentPane.add(button);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
Runnable runnable = new Runnable() {
#Override
public void run() {
new ButtonBinding().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}

Categories