我下面有一个示例 Java Swing 应用程序,现在只要 JFrame 移动或调整大小,它就会输出 X、Y、W、H。我想要的是在释放鼠标时仅输出 X,Y,W,H,所以我的意思是:我需要在新的 JFrame 位置和大小最终确定后进行一些处理,而不是在调整大小过程中,我想保存最终的 X,Y,W,H。
但是现在如果我将 JFrame 从 [X=100,Y=200] 移动到 [X=150,Y=200],它将保存 50 次,因为在移动过程中,X 值从 100 更改为 150 ,所以每次改变X都会保存,这是不必要的,我只想保存鼠标释放后的最终结果[ X=150,Y=200 ],如何实现?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MouseMotionEventDemo extends JPanel
{
static JFrame frame=new JFrame();
public MouseMotionEventDemo()
{
setPreferredSize(new Dimension(500,300));
frame.addComponentListener(new ComponentListener()
{
public void componentResized(ComponentEvent e) { saveXYWH(frame); }
public void componentMoved(ComponentEvent e) { saveXYWH(frame); }
public void componentShown(ComponentEvent e) { }
public void componentHidden(ComponentEvent e) { }
});
}
void saveXYWH(JFrame frame)
{
System.out.println("Demo [ X = "+frame.getLocation().x+" , Y = "+frame.getLocation().y+" | W = "+frame.getSize().width+" , H = "+frame.getSize().height+" ]");
}
public static void main(String[] args)
{
javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } });
}
private static void createAndShowGUI()
{
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MouseMotionEventDemo demo=new MouseMotionEventDemo();
frame.setContentPane(demo);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
}
我在这里给你一个答案,但它使用 JNativeHook,它使用 JNI:
所以这里是中心类:
package gui.windows.mousedraghelper;
import java.awt.Component;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.function.Consumer;
import com.github.kwhat.jnativehook.GlobalScreen;
import com.github.kwhat.jnativehook.NativeHookException;
import com.github.kwhat.jnativehook.mouse.NativeMouseEvent;
import com.github.kwhat.jnativehook.mouse.NativeMouseListener;
public class MouseDragHelper implements AutoCloseable {
private final Consumer<ComponentEvent> mLambda;
ComponentEvent mLastDragEvent;
public MouseDragHelper(final Component pWindow, final Consumer<ComponentEvent> pLambda) throws NativeHookException {
mLambda = pLambda;
GlobalScreen.addNativeMouseListener(new NativeMouseListener() {
@Override public void nativeMousePressed(final NativeMouseEvent pNativeMouseEvent) {
mLastDragEvent = null;
}
@Override public void nativeMouseReleased(final NativeMouseEvent pNativeMouseEvent) {
checkRaiseEvent();
}
});
pWindow.addComponentListener(new ComponentAdapter() {
@Override public void componentMoved(final ComponentEvent pE) {
mLastDragEvent = pE;
}
});
GlobalScreen.registerNativeHook();
}
protected void checkRaiseEvent() {
final ComponentEvent lde = mLastDragEvent;
if (lde != null) mLambda.accept(lde);
}
@Override public void close() {
try {
GlobalScreen.unregisterNativeHook();
} catch (final NativeHookException e) {
e.printStackTrace();
/* we could actually simply ignore this */
}
}
}
连同外部示例(从外部控制窗口):
package gui.windows.mousedraghelper;
import java.awt.event.ComponentEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
import com.github.kwhat.jnativehook.NativeHookException;
public class Test_MouseDragHelper_External {
static class TestFrame extends JFrame {
private static final long serialVersionUID = -7239078731343703120L;
public TestFrame() {
setTitle("MouseDragHelper - External Test");
setBounds(400, 300, 400, 300);
}
}
public static void main(final String[] args) throws NativeHookException {
final TestFrame window = new TestFrame();
// we need this to catch the addWindowListener->WindowAdapter->windowClosed event
// we do NOT need this when WindowConstants.EXIT_ON_CLOSE is specified
window.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
window.setVisible(true);
@SuppressWarnings("resource") final MouseDragHelper mdh = new MouseDragHelper(window, e -> handleWindowDragDone(e));
window.addWindowListener(new WindowAdapter() {
@Override public void windowClosed(final WindowEvent pE) {
mdh.close();
}
});
}
static private void handleWindowDragDone(final ComponentEvent pE) {
System.out.println("The window was just dragged and released: " + pE);
}
}
以及内部示例(从内部控制窗口,您可能会在代码中使用它):
package gui.windows.mousedraghelper;
import java.awt.event.ComponentEvent;
import javax.swing.JFrame;
import com.github.kwhat.jnativehook.NativeHookException;
public class Test_MouseDragHelper_Internal {
static class TestFrame extends JFrame {
private static final long serialVersionUID = 3161758860296277990L;
private final MouseDragHelper mMouseDragHelper;
public TestFrame() throws NativeHookException {
mMouseDragHelper = new MouseDragHelper(this, e -> dragDone(e));
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setTitle("MouseDragHelper - Internal Test");
setBounds(400, 300, 400, 300);
}
@Override public void dispose() {
mMouseDragHelper.close();
super.dispose();
}
@SuppressWarnings("static-method") private void dragDone(final ComponentEvent pE) {
System.out.println("MouseDragHelper.TestFrame.dragDone() " + pE);
}
}
public static void main(final String[] args) throws NativeHookException {
final TestFrame window = new TestFrame();
window.setVisible(true);
}
}
在内部和外部示例中,我都确保再次取消注册本机挂钩,因为该库使用的线程不是守护线程。所以 JVM 不会自行关闭,除非你使用
System.exit()
或 window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
,但这相当不干净。