All Downloads are FREE. Search and download functionalities are using the official Maven repository.

freeseawind.lf.event.WindowMouseHandler Maven / Gradle / Ivy

The newest version!
package freeseawind.lf.event;

import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JRootPane;
import javax.swing.UIManager;
import javax.swing.event.MouseInputListener;

import freeseawind.lf.basic.rootpane.LuckRootPaneUIBundle;
import freeseawind.lf.geom.LuckProperty;
import freeseawind.lf.geom.LuckProperty.LuckPropertyType;
import freeseawind.lf.geom.LuckRectangle;
import freeseawind.lf.utils.LuckWindowUtil;


/**
 * 窗体移动和缩放事件处理类
 * 
 * @author freeseawind@github
 * @version 1.0
 *
 */
public class WindowMouseHandler implements MouseInputListener
{
    /**
     * 是否移动窗体,防止缩放和移动事件互相干扰
     */
    private boolean isMovingWindow;

    /**
     * X location the mouse went down on for a drag operation.
     */
    private int dragOffsetX;

    /**
     * Y location the mouse went down on for a drag operation.
     */
    private int dragOffsetY;

    /**
     * Width of the window when the drag started.
     */
    private int dragWidth;

    /**
     * Height of the window when the drag started.
     */
    private int dragHeight;

    /**
     * 光标默认图标
     */
    private Cursor lastCursor = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);

    /**
     * 可拖拽窗口区域
     */
    private LuckRectangle dragArea;

    /**
     * 标题栏区域,可双击放大或缩小窗口
     */
    private LuckRectangle titleArea;

    //
    private int dragCursor;

    public WindowMouseHandler(JComponent parent)
    {
        int titleHeight = UIManager.getInt(LuckRootPaneUIBundle.TITLEPANEL_HEIGHT);

        LuckProperty startxProp = new LuckProperty(0);

        LuckProperty startyProp = new LuckProperty(0);

        LuckProperty widthProp = new LuckProperty(0);

        LuckProperty heightProp = new LuckProperty(LuckPropertyType.FIX, titleHeight);

        titleArea = new LuckRectangle(startxProp, startyProp, widthProp, heightProp, parent);

        dragArea = titleArea;
    }

    /**
     * 处理JFrame的双击标题面板缩放事件
     */
    public void mouseClicked(MouseEvent e)
    {
        Window window = (Window) e.getSource();

        if(window instanceof JFrame)
        {
            JFrame frame = (JFrame) window;

            JRootPane root = frame.getRootPane();

            // 不包含窗体装饰直接返回
            if (root.getWindowDecorationStyle() == JRootPane.NONE)
            {
                return;
            }

            // 不在标题栏覆盖区域直接返回
            if(!titleArea.contains(e.getPoint()))
            {
                return;
            }

            if ((e.getClickCount() % 2) == 0 && ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0))
            {
                int state = frame.getExtendedState();

                if (frame.isResizable())
                {
                    if ((state & JFrame.MAXIMIZED_BOTH) != 0)
                    {
                        frame.setExtendedState(state & ~JFrame.MAXIMIZED_BOTH);
                    }
                    else
                    {
                        frame.setExtendedState(state | JFrame.MAXIMIZED_BOTH);
                    }
                }
            }
        }
    }

    /**
     *  v1.0.1:修复自定义拖拽区域BUG, 增加边界判断
     */
    public void mousePressed(MouseEvent e)
    {
        Window window = (Window) e.getSource();

        JRootPane root = LuckWindowUtil.getRootPane(window);

        // 不包含窗体装饰直接返回
        if (root == null || root.getWindowDecorationStyle() == JRootPane.NONE)
        {
            return;
        }
        
        if (window != null)
        {
            window.toFront();
        }

        // 如果是单击标题栏, 则标记接下来的拖动事件为移动窗口, 判断当前鼠标是否超出边界
        if (dragArea.contains(e.getPoint())
                && dragCursor == Cursor.DEFAULT_CURSOR)
        {
            if(window instanceof JFrame)
            {
                JFrame frame = (JFrame)window;

                // 如果当前窗体是全屏状态则直接返回
                if(frame.getExtendedState() == JFrame.MAXIMIZED_BOTH)
                {
                    return;
                }
            }

            // 设置为可以移动并记录当前坐标
            isMovingWindow = true;

            dragOffsetX = e.getPoint().x;

            dragOffsetY = e.getPoint().y;
        }
        else if(LuckWindowUtil.isResizable(window))
        {
            dragOffsetX = e.getPoint().x;

            dragOffsetY = e.getPoint().y;

            dragWidth = window.getWidth();

            dragHeight = window.getHeight();

            JRootPane rootPane = LuckWindowUtil.getRootPane(window);

            if(rootPane != null && LuckWindowUtil.isResizable(window))
            {
                dragCursor = getCursor(dragWidth, dragHeight, e.getPoint(), rootPane.getInsets());
            }
        }
    }

    public void mouseReleased(MouseEvent e)
    {
        Window window = (Window) e.getSource();
        
        if (dragCursor != 0 && window != null && !window.isValid())
        {
            // Some Window systems validate as you resize, others won't,
            // thus the check for validity before repainting.
            window.validate();
            
            if(window instanceof JFrame)
            {
                ((JFrame)window).getRootPane().repaint();
            }
        }
        
        // 松开鼠标时重置状态
        isMovingWindow = false;

        dragCursor = 0;
    }

    /**
     *  v1.0.1:修复自定义拖拽区域BUG, 保存游标状态
     */
    public void mouseMoved(MouseEvent e)
    {
        Window window = (Window)e.getSource();

        int w = window.getWidth();

        int h = window.getHeight();

        Point point = e.getPoint();

        JRootPane rootPane = LuckWindowUtil.getRootPane(window);

        int cursor = 0;

        if(rootPane != null && LuckWindowUtil.isResizable(window))
        {
            cursor = getCursor(w, h, point, rootPane.getInsets());
        }

        if(cursor != Cursor.DEFAULT_CURSOR)
        {
            window.setCursor(Cursor.getPredefinedCursor(cursor));
        }
        else
        {
            window.setCursor(lastCursor);
        }
        
        dragCursor = cursor;
    }

    public void mouseEntered(MouseEvent e)
    {
        mouseMoved(e);
    }

    public void mouseExited(MouseEvent e)
    {
        // 鼠标离开窗体时恢复为默认游标
        Window w = (Window)e.getSource();
        w.setCursor(lastCursor);
    }

    public void mouseDragged(MouseEvent e)
    {
        Window w = (Window) e.getSource();

        if (isMovingWindow)
        {
            Point prePoint = e.getLocationOnScreen();

            w.setLocation(prePoint.x - dragOffsetX, prePoint.y - dragOffsetY);
        }
        else if(dragCursor != Cursor.DEFAULT_CURSOR)
        {
            updateBound(e.getPoint(), w);
        }
    }

    public int getCursor(int w, int h, Point point, Insets inset)
    {
        int radius = -1;

        //
        int startX = inset.left + radius;
        int endX = w - inset.right + radius;
        int startY = inset.top + radius;
        int endY = h - inset.bottom + radius;

        if (point.x <= startX && point.y <= startY)
        {
            // 左上角
            return Cursor.NW_RESIZE_CURSOR;
        }
        else if (point.x >= endX && point.y <= startY)
        {
            // 右上角
            return Cursor.NE_RESIZE_CURSOR;
        }
        else if (point.x <= startX && point.y >= endY)
        {
            // 左下
            return Cursor.SW_RESIZE_CURSOR;
        }
        else if(point.x >= endX && point.y >=  endY)
        {
            // 右下
            return Cursor.SE_RESIZE_CURSOR;
        }
        else if(point.x <= startX && point.y > startY && point.y < endY)
        {
            // 西
            return Cursor.W_RESIZE_CURSOR;
        }
        else if(point.y <= startY && point.x > startX && point.x < endX)
        {
            // 北
            return Cursor.N_RESIZE_CURSOR;
        }
        else if(point.x >= endX && point.y > startY && point.y < endY)
        {
            // 东
            return Cursor.E_RESIZE_CURSOR;
        }
        else if(point.y >= endY && point.x > startX && point.x < endX)
        {
            // 南
            return Cursor.S_RESIZE_CURSOR;
        }
        else
        {
            return Cursor.DEFAULT_CURSOR;
        }
    }

    public void updateBound(Point pt, Window w)
    {
        Rectangle r = w.getBounds();
        Rectangle startBounds = new Rectangle(r);
        Dimension min = w.getMinimumSize();

        switch (dragCursor)
        {
            case Cursor.E_RESIZE_CURSOR:

                adjust(r, min, 0, 0, pt.x + (dragWidth - dragOffsetX) - r.width, 0);

                break;

            case Cursor.S_RESIZE_CURSOR:

                adjust(r, min, 0, 0, 0, pt.y + (dragHeight - dragOffsetY) - r.height);

                break;

            case Cursor.N_RESIZE_CURSOR:

                adjust(r, min, 0, pt.y - dragOffsetY, 0, -(pt.y - dragOffsetY));

                break;

            case Cursor.W_RESIZE_CURSOR:

                adjust(r, min, pt.x - dragOffsetX, 0, -(pt.x - dragOffsetX), 0);

                break;

            case Cursor.NE_RESIZE_CURSOR:

                adjust(r, min, 0, pt.y - dragOffsetY, pt.x + (dragWidth - dragOffsetX)
                        - r.width, -(pt.y - dragOffsetY));
                break;
            case Cursor.SE_RESIZE_CURSOR:

                adjust(r, min, 0, 0, pt.x + (dragWidth - dragOffsetX) - r.width,
                        pt.y + (dragHeight - dragOffsetY) - r.height);

                break;

            case Cursor.NW_RESIZE_CURSOR:

                adjust(r, min, pt.x - dragOffsetX, pt.y - dragOffsetY,
                        -(pt.x - dragOffsetX), -(pt.y - dragOffsetY));

                break;

            case Cursor.SW_RESIZE_CURSOR:

                adjust(r, min, pt.x - dragOffsetX, 0, -(pt.x - dragOffsetX),
                        pt.y + (dragHeight - dragOffsetY) - r.height);

                break;

            default:

                break;
        }

        if(!r.equals(startBounds))
        {
            w.setBounds(r);

            if (Toolkit.getDefaultToolkit().isDynamicLayoutActive())
            {
                w.validate();
                w.repaint();
            }
        }
    }


    private void adjust(Rectangle bounds,
                        Dimension min,
                        int deltaX,
                        int deltaY,
                        int deltaWidth,
                        int deltaHeight)
    {
        bounds.x += deltaX;
        bounds.y += deltaY;
        bounds.width += deltaWidth;
        bounds.height += deltaHeight;

        if (min != null)
        {
            if (bounds.width < min.width)
            {
                int correction = min.width - bounds.width;

                if (deltaX != 0)
                {
                    bounds.x -= correction;
                }

                bounds.width = min.width;
            }

            if (bounds.height < min.height)
            {
                int correction = min.height - bounds.height;

                if (deltaY != 0)
                {
                    bounds.y -= correction;
                }

                bounds.height = min.height;
            }
        }
    }

    public void setDragArea(LuckRectangle dragArea)
    {
        this.dragArea = dragArea;
    }

    public void setTitleArea(LuckRectangle titleArea)
    {
        this.titleArea = titleArea;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy