如何在 Swing 中将一个窗口停靠到另一个窗口?

发布于 11-01 20:10 字数 102 浏览 2 评论 0原文

我打开了两个 JFrame。我让窗口 B 在窗口 A 的右侧生成,紧贴窗口 A 的右边缘。我希望它粘在窗口 A 上并随窗口 A 一起移动。我怎样才能让它做到这一点?

I have two JFrames open. I have window B spawn to the right of window A, snugged up to window A's right edge. I want it to stick to and move with window A. How can I make it do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

嗫嚅2024-11-08 20:10:47

我创建了一个名为 DockingManager 的类,它可以让您停靠伪 Winamp 风格的对话框和框架,

它还可以让您创建不同的集群并设置磁性级别来选择哪个框架拖动其他框架)

package com.gsteren.docking;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.Timer;
import javax.swing.UIManager;

public class DockingManager {

    public static enum DockingMode {
        EAST, WEST, NORTH, SOUTH, NONE
    }

    int magneticDistance = 20;

    public static Map<Component, DockingApplier> monitoredComponents = new HashMap<Component, DockingApplier>();

    /**
     * Para saber cual es el último Component movido por el usuario.
     */
    private static DockingApplier focusedApplier;

    public void registerComponent(Component component) {
        this.registerComponent(component, 1);
    }

    public void registerComponent(Component component, int magneticLevel) {
        DockingApplier applier = new DockingApplier(component, magneticLevel);
        monitoredComponents.put(component, applier);
    }

    /**
     * Indica el grupo completo de componentes pegados al que pertenece un
     * componente.
     * 
     * @author Guillermo
     * 
     */
    protected class DockingApplierCluster {
        Set<DockingApplier> appliers = new HashSet<DockingApplier>();
        DockingApplier leader = null;

        public DockingApplierCluster(DockingApplier applier) {
            this.addToCluster(applier);
        }

        public DockingApplierCluster(Set<DockingApplier> appliers) {
            for (DockingApplier applier : appliers) {
                this.addToCluster(applier);
            }
        }

        public void addToCluster(DockingApplier applier) {
            appliers.add(applier);
            applier.setCluster(this);
            if (null == leader || applier.getMagneticLevel() < leader.getMagneticLevel()) {
                this.setLeader(applier);
            }
        }

        public int getSize() {
            return getAppliers().size();
        }

        public void mergeCluster(DockingApplierCluster cluster) {
            DockingApplierCluster bigCluster;
            DockingApplierCluster smallCluster;
            if (getSize() > cluster.getSize()) {
                bigCluster = this;
                smallCluster = cluster;
            } else {
                bigCluster = cluster;
                smallCluster = this;
            }
            for (DockingApplier applier : smallCluster.getAppliers()) {
                bigCluster.addToCluster(applier);
            }

        }

        public Set<DockingApplier> getAppliers() {
            return this.appliers;
        }

        /**
         * @return the leader
         */
        public DockingApplier getLeader() {
            return leader;
        }

        /**
         * @param leader
         *            the leader to set
         */
        public void setLeader(DockingApplier leader) {
            this.leader = leader;
        }

        public void remove(DockingApplier applier) {
            if (this.getAppliers().size() == 1) {
                /* No sacamos el único elemento */
                return;
            }

            this.getAppliers().remove(applier);

            if (this.leader == applier) {
                this.leader = findLeader();
            }

            /* Pude haber dividido en varios clusters */
            this.recalculateClustersAfterRemoval();
        }

        public void recalculateClustersAfterRemoval() {
            Set<DockingApplier> myAppliersCopy = new HashSet<DockingManager.DockingApplier>(getAppliers());
            Set<DockingApplier> visitedAppliers = new HashSet<DockingManager.DockingApplier>();
            for (DockingApplier applier : myAppliersCopy) {
                if (visitedAppliers.contains(applier)) {
                    continue;
                }
                Set<DockingApplier> newClusterComponents = findClusteredAppliers(applier);
                if (newClusterComponents.size() == myAppliersCopy.size()) {
                    /* No se dividieron los clusters */
                    return;
                }
                visitedAppliers.addAll(newClusterComponents);
                /* Creo un nuevo cluster, y le agrego los elementos */
                new DockingApplierCluster(newClusterComponents);
            }

        }

        /**
         * Devuelve todos los DockingAppliers anexos entre si.
         * 
         * @param anApplier
         * @return
         */
        public Set<DockingApplier> findClusteredAppliers(DockingApplier anApplier) {
            return findClusteredAppliers(anApplier, new HashSet<DockingManager.DockingApplier>());
        }

        public Set<DockingApplier> findClusteredAppliers(DockingApplier anApplier, Set<DockingApplier> currentSet) {
            currentSet.add(anApplier);
            for (DockingApplier applier : anApplier.getAttachedComponents()) {
                if (currentSet.contains(applier)) {
                    continue;
                }
                currentSet.add(applier);
                currentSet.addAll(findClusteredAppliers(applier, currentSet));
            }
            return currentSet;
        }

        private DockingApplier findLeader() {
            DockingApplier leaderCandidate = null;
            for (DockingApplier applier : getAppliers()) {
                if (leaderCandidate == null || applier.getMagneticLevel() < leaderCandidate.getMagneticLevel()) {
                    leaderCandidate = applier;
                    if (applier.getMagneticLevel() == 1) {
                        /* Encontramos óptimo */
                        break;
                    }
                }
            }
            return leaderCandidate;
        }

    }

    protected class DockingApplier implements ComponentListener, FocusListener {

        private Component component = null;
        private DockingApplierCluster cluster;

        public DockingApplier(Component component, int magneticLevel) {
            this.component = component;
            this.cluster = new DockingApplierCluster(this);
            this.magneticLevel = magneticLevel;
            this.updateLastLocation();

            /*
             * Esto no es necesario ya que registerComponent es quien crea el
             * applier
             */
            if (!monitoredComponents.containsKey(component)) {
                monitoredComponents.put(component, this);
            }

            this.component.addComponentListener(this);
            this.component.addFocusListener(this);
            componentFinishedMovingDetector.setRepeats(false);
        }

        public void setCluster(DockingApplierCluster cluster) {
            this.cluster = cluster;
        }

        /**
         * @return the cluster
         */
        public DockingApplierCluster getCluster() {
            return cluster;
        }

        boolean isClusterLeader() {
            return getCluster().getLeader() == this;
        }

        /**
         * @return the magneticLevel
         */
        public Integer getMagneticLevel() {
            return magneticLevel;
        }

        /**
         * @param magneticLevel
         *            the magneticLevel to set
         */
        public void setMagneticLevel(Integer magneticLevel) {
            this.magneticLevel = magneticLevel;
        }

        /**
         * @return the isDocking
         */
        protected boolean isDocking() {
            return isDocking;
        }

        /**
         * @param isDocking
         *            the isDocking to set
         */
        protected void setDocking(boolean isDocking) {
            this.isDocking = isDocking;
        }

        /**
         * @return the attachedComponents
         */
        public Set<DockingApplier> getAttachedComponents() {
            return attachedComponents;
        }

        int northY;
        int southY;
        int westX;
        int eastX;

        public void recalculateBorderCoordinates() {
            Point compLoc = component.getLocation();
            Dimension compDim = component.getSize();
            northY = compLoc.y;
            southY = northY + compDim.height;
            westX = compLoc.x;
            eastX = westX + compDim.width;
        }

        public DockingMode calculateWhereToDock(DockingApplier other, int magneticDistance) {
            return calculateWhereToDock(this, other, magneticDistance);
        }

        /**
         * Indica si me debería lockearse con other
         * 
         * @param me
         * @param other
         * @return
         */
        public DockingMode calculateWhereToDock(DockingApplier me, DockingApplier other, int magneticDistance) {

            /* Talvez innecesario */
            me.recalculateBorderCoordinates();
            other.recalculateBorderCoordinates();

            if (me.getAttachedComponents().contains(other)) {
                /* Ya estan conectados */
                return DockingMode.NONE;
            }

            int dockDistN = me.northY - other.southY;
            int dockDistS = other.northY - me.southY;
            int dockDistW = me.westX - other.eastX;
            int dockDistE = other.westX - me.eastX;

            if (dockDistN > 0 && magneticDistance > dockDistN && checkOverlappingEastWest(me, other)) {
                return DockingMode.NORTH;
            } else if (dockDistS > 0 && magneticDistance > dockDistS && checkOverlappingEastWest(me, other)) {
                return DockingMode.SOUTH;
            } else if (dockDistW > 0 && magneticDistance > dockDistW && checkOverlappingNorthSouth(me, other)) {
                return DockingMode.WEST;
            } else if (dockDistE > 0 && magneticDistance > dockDistE && checkOverlappingNorthSouth(me, other)) {
                return DockingMode.EAST;
            }
            return DockingMode.NONE;
        }

        /**
         * Checks whether components overlap in north/south direction.
         */
        protected boolean checkOverlappingEastWest(DockingApplier me, DockingApplier other) {
            return checkOverlappingEastWest_aux(me, other) || checkOverlappingEastWest_aux(other, me);
        }

        /**
         * Checks whether components overlap in east/west direction.
         */
        protected boolean checkOverlappingEastWest_aux(DockingApplier me, DockingApplier other) {
            return me.westX >= other.westX && me.westX <= other.eastX || me.eastX >= other.westX
                    && me.eastX <= other.eastX;
        }

        /**
         * Checks whether components overlap in north/south direction.
         */
        protected boolean checkOverlappingNorthSouth(DockingApplier me, DockingApplier other) {
            return checkOverlappingNorthSouth_aux(me, other) || checkOverlappingNorthSouth_aux(other, me);
        }

        /**
         * Checks whether components overlap in north/south direction.
         */
        protected boolean checkOverlappingNorthSouth_aux(DockingApplier me, DockingApplier other) {
            return me.northY >= other.northY && me.northY <= other.southY || me.southY >= other.northY
                    && me.southY <= other.southY;
        }

        public Point calculateDockedLocation(DockingApplier other, DockingMode mode) {
            return calculateDockedLocation(this, other, mode);
        }

        public Point calculateDockedLocation(DockingApplier me, DockingApplier other, DockingMode mode) {
            final Point meLoc = me.getComponent().getLocation();
            final Point otherLoc = other.getComponent().getLocation();
            final Dimension otherDim = other.getComponent().getSize();
            final Dimension meDim = me.getComponent().getSize();

            /* Posiciones relativas a other */
            switch (mode) {
            case NORTH:
                return new Point(meLoc.x, otherLoc.y + otherDim.height);
            case SOUTH:
                return new Point(meLoc.x, otherLoc.y - meDim.height);
            case WEST:
                return new Point(otherLoc.x + otherDim.width, meLoc.y);
            case EAST:
                return new Point(otherLoc.x - meDim.width, meLoc.y);
            default:
                return new Point(meLoc.x - otherLoc.x, meLoc.y);
            }
        }

        /**
         * Retrasa la accion a ejecutar en onComponentFinishedMoving hasta que
         * pasan 10ms sin que se mueva el componente afectado.
         */
        Timer componentFinishedMovingDetector = new Timer(300, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                onComponentFinishedMoving();
            }
        });

        /**
         * Resetea el componentFinishedMovingDetector, se debe llamar cada vez
         * que se mueve o cambia el tamaño de la ventana.
         */
        protected void startComponentFinishedMovingDetector() {
            if (componentFinishedMovingDetector.isRunning()) {
                componentFinishedMovingDetector.restart();
            } else {
                componentFinishedMovingDetector.start();
            }
        }

        /* Mientras es menor, más probable es ser lider */
        int magneticLevel = 1;

        /* Indica si el componente esta en proceso de hacer dock */
        boolean isDocking = false;

        /* Para desconectarlos en resize */
        Set<DockingApplier> attachedComponents = new HashSet<DockingApplier>();
        /* Indica la posición del componente */
        private Point lastLocation;

        public boolean isDocked() {
            return getCluster().getSize() > 1;
        }

        /**
         * @return the component
         */
        protected Component getComponent() {
            return component;
        }

        public void componentResized(ComponentEvent e) {
            startComponentFinishedMovingDetector();
            this.recalculateBorderCoordinates();
            this.unDock();
        }

        public void componentMoved(ComponentEvent e) {

            this.recalculateBorderCoordinates();

            /*
             * Si el movimiento es consecuencia de hacer dock lo ignoro y marco
             * como que el docking se completó
             */
            if (this.isDocking()) {
                this.setDocking(false);
                return;
            }

            startComponentFinishedMovingDetector();

            if (this != focusedApplier) {
                return;
            }

            if (getCluster().getSize() == 1) {
                return;
            }

            if (!this.isClusterLeader()) {
                this.updateLastLocation();
                this.unDock();
                return;
            }

            positionAttachedComponents();

        }

        public void onComponentFinishedMoving() {
            this.recalculateBorderCoordinates();
            for (DockingApplier otherDockingApplier : getMonitoredComponents().values()) {
                if (otherDockingApplier == this) {
                    continue;
                }
                DockingMode dockMode = calculateWhereToDock(this, otherDockingApplier);
                if (!DockingMode.NONE.equals(dockMode)) {
                    System.out.println("shouldAttach");
                    this.dock(otherDockingApplier, dockMode);                   
                    this.updateLastLocation();
                } else {
                    System.out.println("shouldNotAttach");
                }
            }
        }

        public void setLocation(int x, int y) {
            this.setLocation(new Point(x, y));
        }

        public void setLocation(Point location) {
            this.getComponent().removeComponentListener(this);
            this.getComponent().setLocation(location);
            this.setLastLocation(location);
            this.getComponent().addComponentListener(this);
        }

        private void setLastLocation(Point location) {
            this.lastLocation = location;
        }

        public Point getLocation() {
            return this.getComponent().getLocation();
        }

        /**
         * @return the lastLocation
         */
        public Point getLastLocation() {
            return lastLocation;
        }

        protected void dock(DockingApplier otherDockingApplier, DockingMode dockMode) {
            this.setDocking(true);
            Point dockInfo = this.calculateDockedLocation(otherDockingApplier, dockMode);
            this.setLocation(dockInfo.x, dockInfo.y);
            this.bindAppliers(otherDockingApplier);
            /* Uno los clusters */
            otherDockingApplier.getCluster().mergeCluster(this.getCluster());
        }

        public void bindAppliers(DockingApplier otherDockingApplier) {
            this.getAttachedComponents().add(otherDockingApplier);
            otherDockingApplier.getAttachedComponents().add(this);
        }

        public void unDock() {
            if (this.getCluster().getSize() == 1) {
                return;
            }
            /*
             * Primero lo quito de sus vecinos, luego del cluster, el orden es
             * importante para el calculo de clusters en caso de división.
             */
            Set<DockingApplier> attachedComponentsCopy = new HashSet<DockingManager.DockingApplier>(
                    this.getAttachedComponents());
            for (DockingApplier applier : attachedComponentsCopy) {
                this.unbind(applier);
            }

            this.getCluster().remove(this);
            this.setCluster(new DockingApplierCluster(this));
        }

        public void unbind(DockingApplier dockingApplier) {
            this.getAttachedComponents().remove(dockingApplier);
            dockingApplier.getAttachedComponents().remove(this);
        }

        private DockingMode calculateWhereToDock(DockingApplier component, DockingApplier otherDockingApplier) {
            return this.calculateWhereToDock(otherDockingApplier, magneticDistance);
        }

        public void componentShown(ComponentEvent e) {
            getMonitoredComponents().get(component).recalculateBorderCoordinates();
            // positionAttachedComponents(e);
        }

        public void componentHidden(ComponentEvent e) {
            getMonitoredComponents().get(component).recalculateBorderCoordinates();
            // positionAttachedComponents(e);
        }

        private void positionAttachedComponents() {

            /* El lider del cluster debe arrastrar a los otros componentes */
            Point currentLocation = getComponent().getLocation();
            int xDiff = currentLocation.x - getLastLocation().x;
            int yDiff = currentLocation.y - getLastLocation().y;

            if (xDiff == 0 && yDiff == 0) {
                return;
            }

            this.updateLastLocation();

            for (DockingApplier otherApplier : getCluster().getAppliers()) {
                if (otherApplier == this) {
                    continue;
                }
                Point otherComponentLocation = otherApplier.getComponent().getLocation();
                otherApplier.getComponent().removeComponentListener(otherApplier);
                otherApplier.setDocking(true);
                otherApplier.getComponent().setLocation(otherComponentLocation.x + xDiff,
                        otherComponentLocation.y + yDiff);
                otherApplier.getComponent().addComponentListener(otherApplier);
            }
        }

        public void updateLastLocation() {
            this.setLastLocation(getComponent().getLocation());
        }

        @Override
        public void focusGained(FocusEvent e) {
            DockingManager.setFocusedApplier(this);
        }

        @Override
        public void focusLost(FocusEvent e) {
            // TODO Auto-generated method stub

        }
    }

    public DockingManager() {

    }

    public static void setFocusedApplier(DockingApplier applier) {
        DockingManager.focusedApplier = applier;
    }

    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
        }
        JFrame frame1 = new JFrame("Frame 1");
        JDialog dialog2 = new JDialog((JFrame) null, "Dialog 2");
        frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame1.setSize(200, 50);
        dialog2.setSize(200, 50);
        frame1.setVisible(true);
        dialog2.setVisible(true);

        JDialog dialog1 = new JDialog((JFrame) null, "Dialog 1");
        dialog1.setSize(200, 50);
        dialog1.setVisible(true);

        DockingManager manager = new DockingManager();

        manager.registerComponent(frame1, 1);
        manager.registerComponent(dialog2, 2);
        manager.registerComponent(dialog1, 2);

    }

    /**
     * @return the monitoredComponents
     */
    protected static Map<Component, DockingApplier> getMonitoredComponents() {
        return monitoredComponents;
    }
}

I made a class called DockingManager that lets you dock Dialogs and Frames pseudo Winamp Style

It also lets you make different clusters and set magnetic levels to choose which frame drags the others)

package com.gsteren.docking;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.Timer;
import javax.swing.UIManager;

public class DockingManager {

    public static enum DockingMode {
        EAST, WEST, NORTH, SOUTH, NONE
    }

    int magneticDistance = 20;

    public static Map<Component, DockingApplier> monitoredComponents = new HashMap<Component, DockingApplier>();

    /**
     * Para saber cual es el último Component movido por el usuario.
     */
    private static DockingApplier focusedApplier;

    public void registerComponent(Component component) {
        this.registerComponent(component, 1);
    }

    public void registerComponent(Component component, int magneticLevel) {
        DockingApplier applier = new DockingApplier(component, magneticLevel);
        monitoredComponents.put(component, applier);
    }

    /**
     * Indica el grupo completo de componentes pegados al que pertenece un
     * componente.
     * 
     * @author Guillermo
     * 
     */
    protected class DockingApplierCluster {
        Set<DockingApplier> appliers = new HashSet<DockingApplier>();
        DockingApplier leader = null;

        public DockingApplierCluster(DockingApplier applier) {
            this.addToCluster(applier);
        }

        public DockingApplierCluster(Set<DockingApplier> appliers) {
            for (DockingApplier applier : appliers) {
                this.addToCluster(applier);
            }
        }

        public void addToCluster(DockingApplier applier) {
            appliers.add(applier);
            applier.setCluster(this);
            if (null == leader || applier.getMagneticLevel() < leader.getMagneticLevel()) {
                this.setLeader(applier);
            }
        }

        public int getSize() {
            return getAppliers().size();
        }

        public void mergeCluster(DockingApplierCluster cluster) {
            DockingApplierCluster bigCluster;
            DockingApplierCluster smallCluster;
            if (getSize() > cluster.getSize()) {
                bigCluster = this;
                smallCluster = cluster;
            } else {
                bigCluster = cluster;
                smallCluster = this;
            }
            for (DockingApplier applier : smallCluster.getAppliers()) {
                bigCluster.addToCluster(applier);
            }

        }

        public Set<DockingApplier> getAppliers() {
            return this.appliers;
        }

        /**
         * @return the leader
         */
        public DockingApplier getLeader() {
            return leader;
        }

        /**
         * @param leader
         *            the leader to set
         */
        public void setLeader(DockingApplier leader) {
            this.leader = leader;
        }

        public void remove(DockingApplier applier) {
            if (this.getAppliers().size() == 1) {
                /* No sacamos el único elemento */
                return;
            }

            this.getAppliers().remove(applier);

            if (this.leader == applier) {
                this.leader = findLeader();
            }

            /* Pude haber dividido en varios clusters */
            this.recalculateClustersAfterRemoval();
        }

        public void recalculateClustersAfterRemoval() {
            Set<DockingApplier> myAppliersCopy = new HashSet<DockingManager.DockingApplier>(getAppliers());
            Set<DockingApplier> visitedAppliers = new HashSet<DockingManager.DockingApplier>();
            for (DockingApplier applier : myAppliersCopy) {
                if (visitedAppliers.contains(applier)) {
                    continue;
                }
                Set<DockingApplier> newClusterComponents = findClusteredAppliers(applier);
                if (newClusterComponents.size() == myAppliersCopy.size()) {
                    /* No se dividieron los clusters */
                    return;
                }
                visitedAppliers.addAll(newClusterComponents);
                /* Creo un nuevo cluster, y le agrego los elementos */
                new DockingApplierCluster(newClusterComponents);
            }

        }

        /**
         * Devuelve todos los DockingAppliers anexos entre si.
         * 
         * @param anApplier
         * @return
         */
        public Set<DockingApplier> findClusteredAppliers(DockingApplier anApplier) {
            return findClusteredAppliers(anApplier, new HashSet<DockingManager.DockingApplier>());
        }

        public Set<DockingApplier> findClusteredAppliers(DockingApplier anApplier, Set<DockingApplier> currentSet) {
            currentSet.add(anApplier);
            for (DockingApplier applier : anApplier.getAttachedComponents()) {
                if (currentSet.contains(applier)) {
                    continue;
                }
                currentSet.add(applier);
                currentSet.addAll(findClusteredAppliers(applier, currentSet));
            }
            return currentSet;
        }

        private DockingApplier findLeader() {
            DockingApplier leaderCandidate = null;
            for (DockingApplier applier : getAppliers()) {
                if (leaderCandidate == null || applier.getMagneticLevel() < leaderCandidate.getMagneticLevel()) {
                    leaderCandidate = applier;
                    if (applier.getMagneticLevel() == 1) {
                        /* Encontramos óptimo */
                        break;
                    }
                }
            }
            return leaderCandidate;
        }

    }

    protected class DockingApplier implements ComponentListener, FocusListener {

        private Component component = null;
        private DockingApplierCluster cluster;

        public DockingApplier(Component component, int magneticLevel) {
            this.component = component;
            this.cluster = new DockingApplierCluster(this);
            this.magneticLevel = magneticLevel;
            this.updateLastLocation();

            /*
             * Esto no es necesario ya que registerComponent es quien crea el
             * applier
             */
            if (!monitoredComponents.containsKey(component)) {
                monitoredComponents.put(component, this);
            }

            this.component.addComponentListener(this);
            this.component.addFocusListener(this);
            componentFinishedMovingDetector.setRepeats(false);
        }

        public void setCluster(DockingApplierCluster cluster) {
            this.cluster = cluster;
        }

        /**
         * @return the cluster
         */
        public DockingApplierCluster getCluster() {
            return cluster;
        }

        boolean isClusterLeader() {
            return getCluster().getLeader() == this;
        }

        /**
         * @return the magneticLevel
         */
        public Integer getMagneticLevel() {
            return magneticLevel;
        }

        /**
         * @param magneticLevel
         *            the magneticLevel to set
         */
        public void setMagneticLevel(Integer magneticLevel) {
            this.magneticLevel = magneticLevel;
        }

        /**
         * @return the isDocking
         */
        protected boolean isDocking() {
            return isDocking;
        }

        /**
         * @param isDocking
         *            the isDocking to set
         */
        protected void setDocking(boolean isDocking) {
            this.isDocking = isDocking;
        }

        /**
         * @return the attachedComponents
         */
        public Set<DockingApplier> getAttachedComponents() {
            return attachedComponents;
        }

        int northY;
        int southY;
        int westX;
        int eastX;

        public void recalculateBorderCoordinates() {
            Point compLoc = component.getLocation();
            Dimension compDim = component.getSize();
            northY = compLoc.y;
            southY = northY + compDim.height;
            westX = compLoc.x;
            eastX = westX + compDim.width;
        }

        public DockingMode calculateWhereToDock(DockingApplier other, int magneticDistance) {
            return calculateWhereToDock(this, other, magneticDistance);
        }

        /**
         * Indica si me debería lockearse con other
         * 
         * @param me
         * @param other
         * @return
         */
        public DockingMode calculateWhereToDock(DockingApplier me, DockingApplier other, int magneticDistance) {

            /* Talvez innecesario */
            me.recalculateBorderCoordinates();
            other.recalculateBorderCoordinates();

            if (me.getAttachedComponents().contains(other)) {
                /* Ya estan conectados */
                return DockingMode.NONE;
            }

            int dockDistN = me.northY - other.southY;
            int dockDistS = other.northY - me.southY;
            int dockDistW = me.westX - other.eastX;
            int dockDistE = other.westX - me.eastX;

            if (dockDistN > 0 && magneticDistance > dockDistN && checkOverlappingEastWest(me, other)) {
                return DockingMode.NORTH;
            } else if (dockDistS > 0 && magneticDistance > dockDistS && checkOverlappingEastWest(me, other)) {
                return DockingMode.SOUTH;
            } else if (dockDistW > 0 && magneticDistance > dockDistW && checkOverlappingNorthSouth(me, other)) {
                return DockingMode.WEST;
            } else if (dockDistE > 0 && magneticDistance > dockDistE && checkOverlappingNorthSouth(me, other)) {
                return DockingMode.EAST;
            }
            return DockingMode.NONE;
        }

        /**
         * Checks whether components overlap in north/south direction.
         */
        protected boolean checkOverlappingEastWest(DockingApplier me, DockingApplier other) {
            return checkOverlappingEastWest_aux(me, other) || checkOverlappingEastWest_aux(other, me);
        }

        /**
         * Checks whether components overlap in east/west direction.
         */
        protected boolean checkOverlappingEastWest_aux(DockingApplier me, DockingApplier other) {
            return me.westX >= other.westX && me.westX <= other.eastX || me.eastX >= other.westX
                    && me.eastX <= other.eastX;
        }

        /**
         * Checks whether components overlap in north/south direction.
         */
        protected boolean checkOverlappingNorthSouth(DockingApplier me, DockingApplier other) {
            return checkOverlappingNorthSouth_aux(me, other) || checkOverlappingNorthSouth_aux(other, me);
        }

        /**
         * Checks whether components overlap in north/south direction.
         */
        protected boolean checkOverlappingNorthSouth_aux(DockingApplier me, DockingApplier other) {
            return me.northY >= other.northY && me.northY <= other.southY || me.southY >= other.northY
                    && me.southY <= other.southY;
        }

        public Point calculateDockedLocation(DockingApplier other, DockingMode mode) {
            return calculateDockedLocation(this, other, mode);
        }

        public Point calculateDockedLocation(DockingApplier me, DockingApplier other, DockingMode mode) {
            final Point meLoc = me.getComponent().getLocation();
            final Point otherLoc = other.getComponent().getLocation();
            final Dimension otherDim = other.getComponent().getSize();
            final Dimension meDim = me.getComponent().getSize();

            /* Posiciones relativas a other */
            switch (mode) {
            case NORTH:
                return new Point(meLoc.x, otherLoc.y + otherDim.height);
            case SOUTH:
                return new Point(meLoc.x, otherLoc.y - meDim.height);
            case WEST:
                return new Point(otherLoc.x + otherDim.width, meLoc.y);
            case EAST:
                return new Point(otherLoc.x - meDim.width, meLoc.y);
            default:
                return new Point(meLoc.x - otherLoc.x, meLoc.y);
            }
        }

        /**
         * Retrasa la accion a ejecutar en onComponentFinishedMoving hasta que
         * pasan 10ms sin que se mueva el componente afectado.
         */
        Timer componentFinishedMovingDetector = new Timer(300, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                onComponentFinishedMoving();
            }
        });

        /**
         * Resetea el componentFinishedMovingDetector, se debe llamar cada vez
         * que se mueve o cambia el tamaño de la ventana.
         */
        protected void startComponentFinishedMovingDetector() {
            if (componentFinishedMovingDetector.isRunning()) {
                componentFinishedMovingDetector.restart();
            } else {
                componentFinishedMovingDetector.start();
            }
        }

        /* Mientras es menor, más probable es ser lider */
        int magneticLevel = 1;

        /* Indica si el componente esta en proceso de hacer dock */
        boolean isDocking = false;

        /* Para desconectarlos en resize */
        Set<DockingApplier> attachedComponents = new HashSet<DockingApplier>();
        /* Indica la posición del componente */
        private Point lastLocation;

        public boolean isDocked() {
            return getCluster().getSize() > 1;
        }

        /**
         * @return the component
         */
        protected Component getComponent() {
            return component;
        }

        public void componentResized(ComponentEvent e) {
            startComponentFinishedMovingDetector();
            this.recalculateBorderCoordinates();
            this.unDock();
        }

        public void componentMoved(ComponentEvent e) {

            this.recalculateBorderCoordinates();

            /*
             * Si el movimiento es consecuencia de hacer dock lo ignoro y marco
             * como que el docking se completó
             */
            if (this.isDocking()) {
                this.setDocking(false);
                return;
            }

            startComponentFinishedMovingDetector();

            if (this != focusedApplier) {
                return;
            }

            if (getCluster().getSize() == 1) {
                return;
            }

            if (!this.isClusterLeader()) {
                this.updateLastLocation();
                this.unDock();
                return;
            }

            positionAttachedComponents();

        }

        public void onComponentFinishedMoving() {
            this.recalculateBorderCoordinates();
            for (DockingApplier otherDockingApplier : getMonitoredComponents().values()) {
                if (otherDockingApplier == this) {
                    continue;
                }
                DockingMode dockMode = calculateWhereToDock(this, otherDockingApplier);
                if (!DockingMode.NONE.equals(dockMode)) {
                    System.out.println("shouldAttach");
                    this.dock(otherDockingApplier, dockMode);                   
                    this.updateLastLocation();
                } else {
                    System.out.println("shouldNotAttach");
                }
            }
        }

        public void setLocation(int x, int y) {
            this.setLocation(new Point(x, y));
        }

        public void setLocation(Point location) {
            this.getComponent().removeComponentListener(this);
            this.getComponent().setLocation(location);
            this.setLastLocation(location);
            this.getComponent().addComponentListener(this);
        }

        private void setLastLocation(Point location) {
            this.lastLocation = location;
        }

        public Point getLocation() {
            return this.getComponent().getLocation();
        }

        /**
         * @return the lastLocation
         */
        public Point getLastLocation() {
            return lastLocation;
        }

        protected void dock(DockingApplier otherDockingApplier, DockingMode dockMode) {
            this.setDocking(true);
            Point dockInfo = this.calculateDockedLocation(otherDockingApplier, dockMode);
            this.setLocation(dockInfo.x, dockInfo.y);
            this.bindAppliers(otherDockingApplier);
            /* Uno los clusters */
            otherDockingApplier.getCluster().mergeCluster(this.getCluster());
        }

        public void bindAppliers(DockingApplier otherDockingApplier) {
            this.getAttachedComponents().add(otherDockingApplier);
            otherDockingApplier.getAttachedComponents().add(this);
        }

        public void unDock() {
            if (this.getCluster().getSize() == 1) {
                return;
            }
            /*
             * Primero lo quito de sus vecinos, luego del cluster, el orden es
             * importante para el calculo de clusters en caso de división.
             */
            Set<DockingApplier> attachedComponentsCopy = new HashSet<DockingManager.DockingApplier>(
                    this.getAttachedComponents());
            for (DockingApplier applier : attachedComponentsCopy) {
                this.unbind(applier);
            }

            this.getCluster().remove(this);
            this.setCluster(new DockingApplierCluster(this));
        }

        public void unbind(DockingApplier dockingApplier) {
            this.getAttachedComponents().remove(dockingApplier);
            dockingApplier.getAttachedComponents().remove(this);
        }

        private DockingMode calculateWhereToDock(DockingApplier component, DockingApplier otherDockingApplier) {
            return this.calculateWhereToDock(otherDockingApplier, magneticDistance);
        }

        public void componentShown(ComponentEvent e) {
            getMonitoredComponents().get(component).recalculateBorderCoordinates();
            // positionAttachedComponents(e);
        }

        public void componentHidden(ComponentEvent e) {
            getMonitoredComponents().get(component).recalculateBorderCoordinates();
            // positionAttachedComponents(e);
        }

        private void positionAttachedComponents() {

            /* El lider del cluster debe arrastrar a los otros componentes */
            Point currentLocation = getComponent().getLocation();
            int xDiff = currentLocation.x - getLastLocation().x;
            int yDiff = currentLocation.y - getLastLocation().y;

            if (xDiff == 0 && yDiff == 0) {
                return;
            }

            this.updateLastLocation();

            for (DockingApplier otherApplier : getCluster().getAppliers()) {
                if (otherApplier == this) {
                    continue;
                }
                Point otherComponentLocation = otherApplier.getComponent().getLocation();
                otherApplier.getComponent().removeComponentListener(otherApplier);
                otherApplier.setDocking(true);
                otherApplier.getComponent().setLocation(otherComponentLocation.x + xDiff,
                        otherComponentLocation.y + yDiff);
                otherApplier.getComponent().addComponentListener(otherApplier);
            }
        }

        public void updateLastLocation() {
            this.setLastLocation(getComponent().getLocation());
        }

        @Override
        public void focusGained(FocusEvent e) {
            DockingManager.setFocusedApplier(this);
        }

        @Override
        public void focusLost(FocusEvent e) {
            // TODO Auto-generated method stub

        }
    }

    public DockingManager() {

    }

    public static void setFocusedApplier(DockingApplier applier) {
        DockingManager.focusedApplier = applier;
    }

    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
        }
        JFrame frame1 = new JFrame("Frame 1");
        JDialog dialog2 = new JDialog((JFrame) null, "Dialog 2");
        frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame1.setSize(200, 50);
        dialog2.setSize(200, 50);
        frame1.setVisible(true);
        dialog2.setVisible(true);

        JDialog dialog1 = new JDialog((JFrame) null, "Dialog 1");
        dialog1.setSize(200, 50);
        dialog1.setVisible(true);

        DockingManager manager = new DockingManager();

        manager.registerComponent(frame1, 1);
        manager.registerComponent(dialog2, 2);
        manager.registerComponent(dialog1, 2);

    }

    /**
     * @return the monitoredComponents
     */
    protected static Map<Component, DockingApplier> getMonitoredComponents() {
        return monitoredComponents;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文