I have a menu bar with a search-bar that is implemented with a JTextField like this:
public class Ui_Frame {
private static JFrame f;
private static DrawPanel drawPanel;
public static void main(String[] args) {
SwingUtilities.invokeLater(Ui_Frame::createAndShowGUI);
}
private static void createAndShowGUI() {
f = new JFrame("Frame");
drawPanel = new DrawPanel(); //A class that extends JPanel where I draw
JMenuBar menubar = new JMenuBar();
JMenu j_menu_data = new JMenu("Data");
JTextField j_menu_searchfield = new JTextField();
j_menu_searchfield.setSize(new Dimension(100,20));
menubar.add(j_menu_data);
menubar.add(j_menu_searchfield);
f.setJMenuBar(menubar);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(drawPanel);
f.pack();
f.setVisible(true);
}
}
I have KeyListeners for the DrawPanel class, these work just fine. The problem is that when I add the search bar JTextField to the menu bar as above, everything I write is being written to the text field and my key listeners do not trigger. I cannot "get out" of the text field, so If I click inside the area where I am drawing all the keys I press are still put into the text field.
I have tried getFocus() for the DrawPanel but to no avail.
How to solve this?
EDIT:
DrawPanel class so you have all the classes you need to run it:
public class DrawPanel extends JPanel {
public DrawPanel() {
addKeyListener(new CustomKeyListener());
this.setBackground(new Color(220,220,220));
setBorder(BorderFactory.createLineBorder(Color.black));
setFocusable(true);
setVisible(true);
}
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
protected void paintComponent(Graphics g) {
Graphics2D g2D = (Graphics2D) g;
super.paintComponent(g2D);
}
class CustomKeyListener implements KeyListener {
#Override
public void keyTyped(KeyEvent e) {
if (e.getKeyChar() == KeyEvent.VK_SPACE) {
System.out.println("Pressed SPACE");
}
}
#Override
public void keyPressed(KeyEvent e) { }
#Override
public void keyReleased(KeyEvent e) { }
}
}
When you launch your Swing application, the JTextField initially has the keyboard focus. You know this because you see the cursor flashing inside the JTextField.
Clicking on the DrawPanel with the mouse does not transfer the keyboard focus to the DrawPanel. You know this because after clicking the mouse inside the DrawPanel, the cursor is still flashing inside the JTextField.
You can transfer the keyboard focus from the JTextField to the DrawPanel by hitting the TAB key on the keyboard since that is the default focus traversal key. You know that the JTextField no longer has keyboard focus because there is no flashing cursor in it.
If you really want the DrawPanel to gain keyboard focus by clicking the mouse in it, you can add a MouseListener to DrawPanel, as demonstrated in the below code which is essentially your code (for class DrawPanel) with a MouseListener added.
Note that I did not change class Ui_Frame.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
public class DrawPanel extends JPanel implements MouseListener {
public DrawPanel() {
addKeyListener(new CustomKeyListener());
addMouseListener(this);
this.setBackground(new Color(220,220,220));
setBorder(BorderFactory.createLineBorder(Color.black));
setFocusable(true);
setVisible(true);
}
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
protected void paintComponent(Graphics g) {
Graphics2D g2D = (Graphics2D) g;
super.paintComponent(g2D);
}
class CustomKeyListener implements KeyListener {
#Override
public void keyTyped(KeyEvent e) {
if (e.getKeyChar() == KeyEvent.VK_SPACE) {
System.out.println("Pressed SPACE");
}
}
#Override
public void keyPressed(KeyEvent e) { }
#Override
public void keyReleased(KeyEvent e) { }
}
#Override
public void mouseClicked(MouseEvent mouseEvent) {
System.out.println(this.requestFocusInWindow());
}
#Override
public void mousePressed(MouseEvent mouseEvent) {
}
#Override
public void mouseReleased(MouseEvent mouseEvent) {
}
#Override
public void mouseEntered(MouseEvent mouseEvent) {
}
#Override
public void mouseExited(MouseEvent mouseEvent) {
}
}
Note that method requestFocusInWindow() returns true if it succeeds.
Related
I have a user that uses 3 monitors of different sizes, I want to use a mouse dragged event listener to detect when the user drags the window to another screen and resize it based on that screens size. When I add a mouse event listener to the jframe doesn't detect events on the title bar. Is there a way to detect titlebar events? or a better approach to this problem?
I tried also tried using AWTEventListener but had the same problem where it won't detect events in the titlebar.
Test Code showing issue:
import javax.swing.*;
import java.awt.event.*;
public class FrameTest extends JFrame
{
JPanel pnl;
JLabel lbl;
public FrameTest()
{
setSize(1100,800);
setLocationRelativeTo(null);
setTitle("Frame Test");
pnl = new JPanel();
lbl = new JLabel("This is my Frame");
add(pnl);
pnl.add(lbl);
setVisible(true);
FrameTest.this.addMouseListener(new MouseMotionEvents());
FrameTest.this.addMouseMotionListener(new MouseMotionEvents());
}
public class MouseMotionEvents implements MouseListener, MouseMotionListener
{
public MouseMotionEvents()
{
addMouseListener(this);
addMouseMotionListener(this);
}
public void mouseClicked(MouseEvent me)
{
}
public void mouseEntered(MouseEvent me)
{
}
public void mouseExited(MouseEvent me)
{
}
public void mousePressed(MouseEvent me)
{
}
public void mouseReleased(MouseEvent me)
{
}
public void mouseDragged(MouseEvent me)
{
System.out.println("Mouse Dragged Event Triggered");
}
public void mouseMoved(MouseEvent me)
{
}
}
public static void main( String[] args )
{
new FrameTest();
}
}
I have a main window:
public class MainPanel extends JFrame implements MouseListener {
public MainPanel() {
setLayout(new FlowLayout());
setDefaultCloseOperation(EXIT_ON_CLOSE);
addMouseListener(this);
ChildPanel child = new ChildPanel();
add(child);
JPanel spacer = new JPanel();
spacer.setPreferredSize(new Dimension(50, 50));
add(spacer);
pack();
setLocationRelativeTo(null);
}
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Mouse click event on MainPanel");
}
}
And a child JPanel:
public class ChildPanel extends JPanel implements MouseListener {
public ChildPanel() {
setBackground(Color.RED);
setPreferredSize(new Dimension(200, 200));
//addMouseListener(this);
}
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Mouse click event on ChildPanel");
}
}
With the call to addMouseListener commented out in the child panel, the parent receives click events when I click anywhere in the window, including on the child. If I uncomment that call and click on the child panel, only the child receives the click event and it doesn't propagate to the parent.
How do I stop the event from being consumed by the child?
In Swing, you generally want the clicked component to respond; but you can forward the mouse event to the parent, as shown below. Here's a related example.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
/** #see https://stackoverflow.com/questions/3605086 */
public class ParentPanel extends JPanel {
public ParentPanel() {
this.setPreferredSize(new Dimension(640, 480));
this.setBackground(Color.cyan);
this.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Mouse clicked in parent panel.");
}
});
JPanel child = new JPanel();
child.setPreferredSize(new Dimension(320, 240));
child.setBackground(Color.blue);
child.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Mouse clicked in child panel.");
ParentPanel.this.processMouseEvent(e);
}
});
this.add(child);
}
private void display() {
JFrame f = new JFrame("MouseEventTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new ParentPanel().display();
}
});
}
}
I don't think you can. I believe it's a Swing design principle that only one component receives an event.
You can get the behavior you want, however, but pass the JFrame to the ChildPanel and calling its mouseClicked(MouseEvent) or whatever method you want. Or just get the parent component.
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Mouse click event on ChildPanel");
this.frame.mouseClicked(e);
getParent().mouseClicked(e);
}
Is it possible to listen for mouse released event on the component on which it was not pressed?
I know that when mouse is released MouseListener.mouseReleased()is invoked on the listeners for that component when mouse press originated even if the cursor is above other component.
How to inform a component or its listeners that the mouse was over it and it was released?
If you add your MouseListener to the container that holds your components of interest, you can find out which component the mouse is over on press or drag. For instance in the code below, I've added my MouseAdapter (a combination MouseListener, MouseMotionListener, and MouseWheelListener) to the containing JPanel, and after getting the location of the mouse event on the container, I call getComponentAt(Point p) on my container to get the child component that the mouse was over:
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class TestMouseRelease extends JPanel {
private String[] panelNames = { "Panel A", "Panel B" };
public TestMouseRelease() {
setLayout(new GridLayout(1, 0));
MouseAdapter mAdapter = new MyMouseAdapter();
addMouseListener(mAdapter);
addMouseMotionListener(mAdapter);
for (String panelName : panelNames) {
JPanel panel = new JPanel();
panel.setName(panelName);
// panel.addMouseListener(mAdapter);
// panel.addMouseMotionListener(mAdapter);
panel.setBorder(BorderFactory.createTitledBorder(panelName));
panel.add(Box.createRigidArea(new Dimension(300, 300)));
add(panel);
}
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
displayInfo(e, "mousePressed");
}
#Override
public void mouseReleased(MouseEvent e) {
displayInfo(e, "mouseReleased");
}
#Override
public void mouseDragged(MouseEvent e) {
displayInfo(e, "mouseDragged");
}
private void displayInfo(MouseEvent e, String info) {
JComponent comp = (JComponent) e.getSource();
Component childComp = comp.getComponentAt(e.getPoint());
if (childComp != null) {
String name = childComp.getName();
System.out.println(name + ": " + info);
}
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("TestMouseRelease");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new TestMouseRelease());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Yeah, I handled something similar in my project. I use getBounds() on all component in the container and check if they contain the x,y coordinates of your mouse. Below is my code:
Component[] components = jPanel1.getComponents();
for (Component c : components) {
if (c.getBounds().contains(ev.getXOnScreen(), ev.getYOnScreen())) {
System.out.println(c.getClass());
y = ch.getPosY();
x = ch.getPosX();
}
}
I've started working on a project for my Java class - LAN gomoku/five in a row. The game board is represented by a 2-dimensional array filled with buttons (JButton). With the event handler (class clickHandler) I want to draw an oval on the button that I click (the parameter of a clickHandler object). My following code hasn't worked though (I don't know how to get rid of the null-value of variable g)... I'd appreciate any piece of advice. Thank You a lot.
class clickHandler implements ActionListener {
JButton button;
Dimension size;
Graphics g;
public clickHandler(JButton button) {
this.button = button;
this.size = this.button.getPreferredSize();
}
#Override
public void actionPerformed(ActionEvent ae) {
this.g.setColor(Color.BLUE);
this.g.fillOval(this.button.getHorizontalAlignment(), this.button.getVerticalAlignment(), this.size.width, this.size.height);
this.button.paint(this.g);
this.button.setEnabled(false);
}
}
(In a class that creates the GUI - the game board full of buttons - I assign each button a new Action Listener - an instance of clickHandler) this way:
gButton.addActionListener(new clickHandler(gButton));
You have to:
Extends the JButton class, and override the paintComponent(Graphics g) method.
Do override getPreferredSize() method, which will return on Dimension object and will help the Layout Manager in placing your JButton on the Container/Component, by providing it one appropriate size.
Make your circle code there.
add an onClickListener, and set a flag on the clicked button if it is clicked, and call it to repaint.
About the Graphics object: it's best to keep it in it's paintComponent method, and to use it only there. It will always get passed in on a repaint, and if you save it for other moments, strange things can happen (happy experimenting :) ).
A small Example :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ButtonExample
{
private MyButton customButton;
private void displayGUI()
{
JFrame frame = new JFrame("Custom Button Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
customButton = new MyButton();
customButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
MyButton.isClicked = true;
customButton.repaint();
}
});
frame.getContentPane().add(customButton, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new ButtonExample().displayGUI();
}
});
}
}
class MyButton extends JButton
{
public static boolean isClicked = false;
public Dimension getPreferredSize()
{
return (new Dimension(100, 40));
}
public void paintComponent(Graphics g)
{
if (!isClicked)
super.paintComponent(g);
else
{
g.setColor(Color.BLUE);
g.fillOval(getHorizontalAlignment(), getVerticalAlignment(), getWidth(), getHeight());
}
}
}
I have a bunch of JLabels and i would like to trap mouse click events. at the moment i am having to use:
public void mouseClicked(MouseEvent arg0) {
}
public void mouseExited(MouseEvent arg0) {
}
public void mouseEntered(MouseEvent arg0) {
}
public void mousePressed(MouseEvent arg0) {
}
public void mouseReleased(MouseEvent arg0) {
System.out.println("Welcome to Java Programming!");
}
I was wondering if there is a tidier way of doing this instead of having a bunch of events I do not wish trap?
EDIT:
class MyAdapter extends MouseAdapter {
public void mouseClicked(MouseEvent event) {
System.out.println(event.getComponent());
}
}
the above works but netBeans says add #override anotation. what does this mean?
EDIT: ok got it. fixed and solved.
Use MouseAdapter()
An abstract adapter class for receiving mouse events. The methods in this class are empty. This class exists as convenience for creating listener objects.
So you need to implement only the method you like such as following example:
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MainClass extends JPanel {
public MainClass() {
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent me) {
System.out.println(me);
}
});
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.getContentPane().add(new MainClass());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 200);
frame.setVisible(true);
}
}
One could use a MouseAdapter class, which implements the MouseListener interface, so one does not need to implement all the methods.
However, by overriding the methods of interest, one can get the desired behavior. For example, if one overrides the mouseClicked method, then one can define some behavior for the mouse click event.
For example (untested code):
JLabel label = new JLabel("Hello");
label.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
System.out.println("Clicked!");
}
});
In the code above, the JLabel will print "Clicked!" to the console upon being clicked on.
You can extend MouseAdapter instead, and just override the events you're really interested in.
You can inherit from java.awt.event.MouseAdapter and only override the methods for the event(s) you are interested in.
some example of mouse event clicked,
in the same way you can use mousePressed or other mouse events
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Work1 extends JFrame{
private JPanel panelNew;
public Work1(){
super("Work 1");
// create Panel
panelNew = new JPanel();
panelNew.setLayout(null);
panelNew.setBackground(Color.cyan );
add(panelNew);
// create Button
JButton btn = new JButton("click me");
// position and size of a button
btn.setBounds(100, 50, 150, 30);
panelNew.add(btn);
// add event to button
btn.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent me) {
// change text of button after click
if (btn.getText() == "abraCadabra"){
btn.setText("click me again") ;
}
else btn.setText("abraCadabra");
}
});
}
public static void main(String[] args){
Work1 go1 = new Work1();
go1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
go1.setSize(320,200);
go1.setVisible(true);
}
}