JFrame drag/move listener?
I'd like to implement a listener to my JFrames to invoke a method
when a window has been moved/dragged. I don't want it to be called
repeatedly while the window is dragged, but rather called a single
time after the mouse button is released and the new position is set.
My searching has yielded listeners for when it's closed or minimized...
but I can't seem to locate what I'm looking for. Can someone please share
what class and method(s) I'm looking for?
Thanks!
ComponentListener's componentMoved()
thanks, but componentMoved() is called repeatedly while the window
is being dragged.
i tried using MouseAdapter's mouseReleased(), but it doesn't seem
to be attached to the JFrame's title bar.
any other ideas? again, i only want the event to be triggered when the
mouse is released (the JFrame is done moving).
thanks again.
works OK on 1.4.0_01, only prints the coords after move completed
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class Testing extends JFrame
{
public Testing()
{
setSize(100,100);
setLocation(300,100);
setDefaultCloseOperation(EXIT_ON_CLOSE);
addComponentListener(new ComponentAdapter(){
public void componentMoved(ComponentEvent ce){
System.out.println("x = "+getX()+", y = "+getY());
}
});
}
public static void main(String[] args) {new Testing().setVisible(true);}
}
> works OK on 1.4.0_01, only prints the coords after move completed
On XP using 1.4.2_06 the componentMoved event fires continously.
One workaround, although not 100% what you want, is to use a Timer. The componentMoved event will keep restarting the Timer so it doesn't fire for "x" ms after the component has stopped moving. Not the same as using mouseReleased, but close.
yeah, on 1.5.0_07 it outputs very fast during movement...
x = 304, y = 103
x = 307, y = 104
x = 311, y = 110
x = 311, y = 110
x = 316, y = 113
x = 318, y = 116
x = 323, y = 119
x = 324, y = 120
x = 328, y = 122
x = 331, y = 125
x = 335, y = 128
x = 338, y = 130
x = 341, y = 131
x = 345, y = 132
x = 348, y = 134
it *would* work, but i'd rather not do the timer.
oddly, attaching a mouse event to the jframe fires if you click on the
border of the jframe, but not if you click on the title bar. is the title bar
a different kind of component or something? one that should have
its own, separate listener?
another idea is if there was a global mouse listener that knew if the
mouse was clicking regardless of components. if i had that i could
link the componentMoved() to that and come up with a solution that
way. is there such a thing?
thanks again.
> another idea is if there was a global mouse listener > is there such a thing?Yes. You use an AWTEventListener to listen for all generated events.However, I already tested it and it still doesn't work.
thanks for the heads-up on it not working on versions > what I'm using
try this (untested)
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class Testing extends JFrame
{
boolean moved = false;
public Testing()
{
setSize(200,100);
setLocation(300,100);
setDefaultCloseOperation(EXIT_ON_CLOSE);
addMouseListener(new MouseAdapter(){
public void mouseReleased(MouseEvent me){
if(moved == true) System.out.println("x = "+getX()+", y = "+getY());
moved = false;
}
});
addComponentListener(new ComponentAdapter(){
public void componentMoved(ComponentEvent ce){
moved = true;
}
});
}
public static void main(String[] args)
{
JFrame.setDefaultLookAndFeelDecorated(true);//<--note this change for mouseListener
new Testing().setVisible(true);
}
}
it never gets to the mouse released part from clicks on the jframe's title
bar, which doesnt make sense to me. it only reaches that if you click on
the border, such as an attempt to resize...
(possibly interior as well...untested, but i need the title bar to listen)
[gotta run...will follow up tomorrow. many thanks]
> try this (untested)Works fine in 1.4.2_06.
> it never gets to the mouse released part from clicks on the jframe's title might be another thing broken between versionsI'd upgrade, but later versions just crash this box(hmm... if I accidentally drop a sledge hammer, I might get a new PC)
> Works fine in 1.4.2_06.thanks - I'll put the sledge hammer away (for the moment)
the code above does work as is in 1.5.0, but I don't use JFrame.setDefaultLookAndFeelDecorated(true);in my project and I'm using another L&F entirely. Any other options?
probably the timer that was suggested earlier is your only other option.
try this (again untested, as my componentMoved doesn't fire continuously)
I've set it for 150ms, so this needs a lot of testing
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class Testing extends JFrame
{
boolean timerStarted = false;
int oldX, oldY;
javax.swing.Timer timer;
public Testing()
{
setSize(100,100);
setLocation(300,100);
setDefaultCloseOperation(EXIT_ON_CLOSE);
ActionListener al = new ActionListener(){
public void actionPerformed(ActionEvent ae){
if(getX() == oldX && getY() == oldY)
{
System.out.println("x = "+getX()+", y = "+getY());
timer.stop();
timerStarted = false;
}
else
{
oldX = getX();
oldY = getY();
}
}
};
timer = new javax.swing.Timer(150,al);
addComponentListener(new ComponentAdapter(){
public void componentMoved(ComponentEvent ce){
if(timerStarted == false)
{
timerStarted = true;
timer.start();
}
}
});
setVisible(true);
oldX = getX();
oldY = getY();
}
public static void main(String[] args) {new Testing();}
}
Thanks for the timer code.
I ended up finding a working solution. I was previously attempting to
add the mouse listener to the JFrame itself, what I needed to do was:
LFRootPaneUI rootPaneUI = (LFRootPaneUI) frame.getRootPane().getUI();
rootPaneUI.getTitlePane().addMouseListener(new FrameListener(C));
// where LFRootPaneUI is a class created in the LookAndFeel project
// I've imported. I assume an equivalent would be needed if I wanted to use
// UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
Thanks again for all of the efforts in this thread.