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();
}
}
Related
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.
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 been trying to implement mouse motion event dispatches but I continue to get a stack overflow error. It works for the mouseMoved(MouseEvent e) method but not for mouseDragged(MouseEvent e). Does anybody have a clue as to why? Are there any solutions?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test extends JFrame {
public Test() {
setLayout(null);
setSize(500,500);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addMouseMotionListener(new MouseMotionListener() {
public void mouseMoved(MouseEvent e) {
System.err.println("moved outside");
}
public void mouseDragged(MouseEvent e) {
System.err.println("dragged outside");
}
});
JPanel inside = new JPanel();
inside.setLocation(0, 0);
inside.setSize(100, 100);
inside.setBackground(Color.RED);
inside.addMouseMotionListener(new MouseMotionListener() {
public void mouseDragged(MouseEvent e) {
System.out.println("dragged inside");
//The error occurs here when I begin dragging
//here and continue dragging to any other location.
Test.this.dispatchEvent(e);
}
public void mouseMoved(MouseEvent e) {
System.out.println("moved inside");
Test.this.dispatchEvent(e);
}
});
add(inside);
}
public static void main(String[] args) {
Test client = new Test();
}
}
My actual project uses many inside components and my goal is to have each component implement their own mouse press/click/release actions and have the frame handle mouse motions and dragging that influences all of the components.
Here is a similar code that does work for both mouse motion methods.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test2 {
public static void main(String... args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
final JComponent outside = new JPanel();
JComponent inside = new JPanel();
inside.setBackground(Color.red);
inside.setPreferredSize(new Dimension(200, 200));
inside.addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e) {
System.out.println("dragged inside");
outside.dispatchEvent(e);
}
public void mouseMoved(MouseEvent e) {
System.out.println("moved inside");
outside.dispatchEvent(e);
}
});
outside.add(inside);
outside.setPreferredSize(new Dimension(300, 300));
outside.addMouseMotionListener(new MouseAdapter() {
public void mouseMoved(MouseEvent e) {
System.err.println("moved outside");
}
public void mouseDragged(MouseEvent e) {
System.err.println("dragged outside");
}
});
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(outside);
frame.pack();
frame.setVisible(true);
}
});
}
}
Help is appreciated.
Your MouseMotionListener in the inside is generating a new event. That event will be caught again by the very same MouseMotionListener, creating an endless loop. Since you are creating an event when the previous one is still unfinished, they will stack up until a StackOverflowError explodes your application.
Your second code does not have this problem because the inside delegates to the outside and it finishes there.
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);
}
}