Is there a way to retain the set mouse cursor even the JDialog is not in focus?
I have the following SSCCE:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test extends JDialog {
public Test() {
super((Frame) null, true);
setLayout(new BorderLayout());
setModalityType(Dialog.ModalityType.MODELESS);
setType(Window.Type.UTILITY);
setUndecorated(true);
setAlwaysOnTop(true);
setBackground(Color.BLACK);
setSize(300, 300);
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
getContentPane().setBackground(Color.BLACK);
getContentPane().setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
setLocationRelativeTo(null);
var label = new JLabel("Focused");
label.setForeground(Color.WHITE);
addWindowFocusListener(new WindowAdapter() {
#Override
public void windowGainedFocus(WindowEvent e) {
label.setText("Focused");
}
#Override
public void windowLostFocus(WindowEvent e) {
label.setText("Not Focused");
}
});
add(label, BorderLayout.CENTER);
}
public static void main(String[] args) {
// Create the GUI on the event-dispatching thread
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Test sw = new Test();
// Display the window.
sw.setVisible(true);
}
});
}
}
Here is what is happening:
My goal is for the resize cursor to be retained on mouse hover even if the JDialog is not focused.
Tried on AdoptOpenJDK 11 & 15 and Liberica JDK 11 on MacOS Catalina 10.15.4
Add a mouse listener for your dialog. By using the MouseAdapter implementation, you can override only the methods that you want.
addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
super.mouseEntered(e);
setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
}
#Override
public void mouseExited(MouseEvent e) {
super.mouseExited(e);
setCursor(Cursor.getDefaultCursor());
}
});
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);
}
I am trying to figure out how can we exit the application with button click.
The problem i faced which makes me unable to exit the application is because i am using "extend JFRame" from the main class.
For an example,
app.class
public class app{
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable(){
public void run(){
JFrame frame = new MainFrame("Exercise one");
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
.. .. ..
frame.setVisible(true);
})
}
}
MainFrame.java
public class MainFrame extends JFrame(){
public MainFrame(String title){
super(title)
//set layout manager
setLayout(new BorderLayout());
//swing components
JButton exit = new JButton("Exit");
//add container
Container container = getContentPane();
container.add(exit);
//create actionlist logic
exit.addActionListener(new ActionListener()){
#Override
public void actionPerformed(ActionEvent arg0){
// on click , this logic will end the application
}
}
}
}
I fully understand how i can cancel the application from app class.But in scenarios where i want to cancel the application from MainFrame.Can it be done ?
Thank you in advance.
The defaultCloseOperation is only processed by the frame when it encounters a WINDOW_CLOSING event, neither setVisible or dispose trigger this event, which means the the defaultCloseOperation won't be processed
The only way to ensure that this operation is triggered is to manually dispatch a WINDOW_CLOSING event
frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
One of the main reasons for wanting to follow this path is that it ensures the application is following the configured defaultCloseOperation and making up it's own mind (like calling System.exit manually)
The following demonstrates hiding, disposing and dispatching approaches. Only the dispatch approach will close the window and terminate the JVM
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.AbstractAction;
import static javax.swing.Action.NAME;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.HORIZONTAL;
frame.add(new JButton(new HideAction(frame)), gbc);
frame.add(new JButton(new DisposeAction(frame)), gbc);
frame.add(new JButton(new DispatchAction(frame)), gbc);
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.out.println("Closing");
}
#Override
public void windowClosed(WindowEvent e) {
System.out.println("Closed");
}
});
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class HideAction extends AbstractAction {
private JFrame frame;
public HideAction(JFrame frame) {
this.frame = frame;
putValue(NAME, "Hide");
}
#Override
public void actionPerformed(ActionEvent e) {
frame.setVisible(false);
}
}
public class DisposeAction extends AbstractAction {
private JFrame frame;
public DisposeAction(JFrame frame) {
this.frame = frame;
putValue(NAME, "Dispose");
}
#Override
public void actionPerformed(ActionEvent e) {
frame.dispose();
}
}
public class DispatchAction extends AbstractAction {
private JFrame frame;
public DispatchAction(JFrame frame) {
this.frame = frame;
putValue(NAME, "Dispatch");
}
#Override
public void actionPerformed(ActionEvent e) {
frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
}
}
}
If I run this in my IDE, unless I use the dispatch option, the JVM is left running and I have to terminate the session to close it fully.
I also noted that calling dispose only triggers the WINDOW_CLOSED event, while the dispatch method will trigger the WINDOW_CLOSING event
Problem solved.
Credits to #XtremeBaumer.
Basically, when using "classname" extend JFRame.
We can input dispose() which will kill the application completely. This will causes the JFrame window to be destroyed and cleaned up by the operating system. :)
Indeed, dispose() is the right solution. I also suggest to add a pack() call so the UI shows up properly:
public class MainFrame extends JFrame {
public MainFrame(String title) {
super(title);
...
// create actionlist logic
exit.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("--> closing app programmatically");
MainFrame.this.dispose();
}
});
this.pack();
}
}
You can test the events with a WindowListener on the MainFrame. They are invoked as if the user pressed the close button:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new MainFrame("Exercise one");
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
// .. .. ..
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.out.println("--> closing...");
}
public void windowClosed(WindowEvent e) {
System.out.println("--> closed...");
}
});
}
});
}
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'm trying to get the WindowOpened event from JDialog, but it is fired just once.
Why windowClosing works correctly and WindowOpened just once? Is there any way to fire the open event for JDialog every time?
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
public class NewClass extends JDialog {
public void init() {
setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
setModal(true);
setSize(100,100);
setLocationRelativeTo(null);
}
public void addListener() {
addWindowListener(
new java.awt.event.WindowAdapter() {
public void windowOpened(WindowEvent e) {
System.out.println("Invoking WindowOpened from JDialog");
}
public void windowClosing(WindowEvent e) {
System.out.println("Invoking WindowClosing from JDialog");
dispose();
}
});
}
public static void main( String args[]) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(200,70);
final NewClass d = new NewClass();
d.init();
d.addListener();
JButton b = new JButton("Show Dialog");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
d.setVisible(true);
}
});
f.getContentPane().add(b);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
ComponentListener#componentShown(ComponentEvent e) is fired whenever your Window is made visible.
I don't believe WindowActivated is a good choice (like others said) because it can be fired in some others circumstances. For instance, if your Dialog is not modal, WindowActivated will be fired whenever the window regains focus.
addWindowListener(new WindowAdapter() {
#Override
public void windowActivated(WindowEvent e) {
// TODO Auto-generated method stub
super.windowActivated(e);
}
});