DragTabFrame关闭不一致

时间:2013-09-03 08:43:57

标签: java swing jframe draggable jtabbedpane

下面的代码应该与您在FF,IE或Chrome等浏览器中看到的多文档界面(MDI)有点相似。它在选项卡式窗格中显示“文档”(黑色缓冲图像作为间隔符),以便用户可以将它们从窗格拖动到新(或现有)窗口中。

但是,一旦它们没有更多选项卡,它就会关闭帧,以及在没有其他可见窗口时关闭JVM。我认为我通过Timer中的DragTabManager检查来解决这些问题:

  • 检查DragTabFrame
  • 实例的开放帧
  • 如果找到,则检查标签计数。如果为0,则框架设置为不可见并处理。
  • 如果找不到可见的框架实例,则会结束Timer以允许JRE退出。

至少应该如何运作。它似乎在这里可靠地工作,并且我看到没有'空框架或VM无法关闭'进行了相当多的测试。它是否像其他人一样宣传,还是需要进一步观察?

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.EmptyBorder;

public class DragTabFrame extends JFrame {

    private JTabbedPane tabbedPane = new JTabbedPane();
    private final static DragTabManager dragTabManager = new DragTabManager();

    final MouseAdapter ma = new MouseAdapter() {

        @Override
        public void mouseClicked(MouseEvent e) {
            JComponent c = (JComponent) e.getSource();
            dragTabManager.setCurrentComponent(c);
            DragTabFrame dtf = (DragTabFrame)c.getTopLevelAncestor();
            dragTabManager.setCurrentFrame(dtf);
            JTabbedPane tp = dtf.getTabbedPane();
            int index = tp.indexOfComponent(c);
            if (index<0) index = 0;
            String title = tp.getTitleAt(index);
            dragTabManager.setCurrentTitle(title);
        }

        @Override
        public void mousePressed(MouseEvent e) {
            JComponent c = (JComponent) e.getSource();
            DragTabFrame dtf = (DragTabFrame)c.getTopLevelAncestor();
            dragTabManager.setCurrentComponent(c);
            dragTabManager.setCurrentFrame(dtf);
            JTabbedPane tp = dtf.getTabbedPane();
            int index = tp.indexOfComponent(c);
            if (index<0) index = 0;
            String title = tp.getTitleAt(index);
            dragTabManager.setCurrentTitle(title);
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            JComponent c = (JComponent) e.getSource();
            if (c.getTopLevelAncestor().getBounds().contains(e.getLocationOnScreen())) {
                // do nothing, the drop point is the same frame
            } else {
                DragTabFrame dtf = getTargetFrame(e.getLocationOnScreen());
                if (dtf == null) {
                    dtf = new DragTabFrame();
                    dtf.init();
                    dtf.setLocation(e.getLocationOnScreen());
                } else {
                    DragTabFrame fromFrame = dragTabManager.getCurrentFrame();
                    fromFrame.removeTabComponent(c);
                    JTabbedPane tp = fromFrame.getTabbedPane();
                    if (tp.getTabCount() == 0) {
                        fromFrame.setVisible(false);
                        fromFrame.dispose();
                    } 
                }
                dtf.addTabComponent(dragTabManager.getCurrentTitle(), c);
                dtf.pack();
                dtf.setVisible(true);
            }
        }
    };

    public JTabbedPane getTabbedPane() {
        return tabbedPane;
    }

    public DragTabFrame getTargetFrame(Point p) {
        Frame[] frames = Frame.getFrames();
        for (Frame frame : frames) {
            if (frame instanceof DragTabFrame
                    && frame.getBounds().contains(p)) {
                return (DragTabFrame) frame;
            }
        }

        return null;
    }

    public void init() {
        // the GUI as seen by the user (without frame)
        JPanel gui = new JPanel(new BorderLayout());
        gui.setBorder(new EmptyBorder(2, 3, 2, 3));
        gui.add(tabbedPane, BorderLayout.CENTER);
        add(gui);

        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        // See https://stackoverflow.com/a/7143398/418556 for demo.
        setLocationByPlatform(true);
    }

    public void addTabComponent(String name, Component c) {
        tabbedPane.addTab(name, c);
        c.addMouseListener(ma);
        c.addMouseMotionListener(ma);
    }

    public void removeTabComponent(Component c) {
        tabbedPane.remove(c);
        c.removeMouseListener(ma);
        c.removeMouseMotionListener(ma);
    }
    public static void main(String[] args) {
        Runnable r = new Runnable() {

            @Override
            public void run() {

                DragTabFrame dtf = new DragTabFrame();
                dtf.init();
                BufferedImage bi = new BufferedImage(
                        200, 40, BufferedImage.TYPE_INT_RGB);
                for (int ii = 1; ii < 4; ii++) {
                    JLabel l = new JLabel(new ImageIcon(bi));
                    dtf.addTabComponent("Tab " + ii, l);
                }
                dtf.pack();
                // should be done last, to avoid flickering, moving,
                // resizing artifacts.
                dtf.setVisible(true);
            }
        };
        // Swing GUIs should be created and updated on the EDT
        // http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
        SwingUtilities.invokeLater(r);
    }
}

class DragTabManager {
    private DragTabFrame currentFrame;
    private JComponent currentComponent;
    private String currentTitle;
    private Timer timer;

    public DragTabManager() {
        ActionListener actionListener = new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                Frame[] frames = Frame.getFrames();
                if (frames.length==0) {
                    timer.stop();
                }
                System.out.println("frames.length: " + frames.length);
                boolean allInvisible = true;
                for (Frame frame : frames) {
                    if (frame instanceof DragTabFrame) {
                        DragTabFrame dtf = (DragTabFrame)frame;
                        if (dtf.isVisible()) {
                            allInvisible = false;
                        }
                        if (dtf.getTabbedPane().getTabCount()==0) {
                            dtf.setVisible(false);
                            dtf.dispose();
                        }
                    }
                }
                if (allInvisible) {
                    timer.stop();
                }
            }
        };
        timer = new Timer(200,actionListener);
        timer.start();
    }

    /**
     * @return the currentFrame
     */
    public DragTabFrame getCurrentFrame() {
        return currentFrame;
    }

    /**
     * @param currentFrame the currentFrame to set
     */
    public void setCurrentFrame(DragTabFrame currentFrame) {
        this.currentFrame = currentFrame;
    }

    /**
     * @return the currentComponent
     */
    public JComponent getCurrentComponent() {
        return currentComponent;
    }

    /**
     * @param currentComponent the currentComponent to set
     */
    public void setCurrentComponent(JComponent currentComponent) {
        this.currentComponent = currentComponent;
    }

    /**
     * @return the currentTitle
     */
    public String getCurrentTitle() {
        return currentTitle;
    }

    /**
     * @param currentTitle the currentTitle to set
     */
    public void setCurrentTitle(String currentTitle) {
        this.currentTitle = currentTitle;
    }
}

修复

根据answer of DSquare中的建议,这里是固定来源,还有其他一些调整。

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.EmptyBorder;

public class DragTabFrame extends JFrame {

    private JTabbedPane tabbedPane = new JTabbedPane();
    private final static DragTabManager dragTabManager = new DragTabManager();
    final MouseAdapter ma = new MouseAdapter() {

        @Override
        public void mousePressed(MouseEvent e) {
            JComponent c = (JComponent) e.getSource();
            DragTabFrame dtf = (DragTabFrame) c.getTopLevelAncestor();
            dragTabManager.setCurrentComponent(c);
            dragTabManager.setCurrentFrame(dtf);
            JTabbedPane tp = dtf.getTabbedPane();
            int index = tp.indexOfComponent(c);
            String title = tp.getTitleAt(index);
            dragTabManager.setCurrentTitle(title);
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            JComponent c = (JComponent) e.getSource();
            if (c.getTopLevelAncestor().getBounds().contains(
                    e.getLocationOnScreen())) {
                // do nothing, the drop point is the same frame
            } else {
                DragTabFrame dtf = getTargetFrame(e.getLocationOnScreen());
                if (dtf == null) {
                    dtf = new DragTabFrame();
                    dtf.init();
                    dtf.setLocation(e.getLocationOnScreen());
                }
                DragTabFrame fromFrame = dragTabManager.getCurrentFrame();
                fromFrame.removeTabComponent(c);
                JTabbedPane tp = fromFrame.getTabbedPane();
                if (tp.getTabCount() == 0) {
                    fromFrame.setVisible(false);
                    fromFrame.dispose();
                }
                dtf.addTabComponent(dragTabManager.getCurrentTitle(), c);
                dtf.pack();
                dtf.setVisible(true);
            }
        }
    };

    public JTabbedPane getTabbedPane() {
        return tabbedPane;
    }

    public DragTabFrame getTargetFrame(Point p) {
        Frame[] frames = Frame.getFrames();
        for (Frame frame : frames) {
            if (frame instanceof DragTabFrame
                    && frame.getBounds().contains(p)) {
                return (DragTabFrame) frame;
            }
        }

        return null;
    }

    public void init() {
        // the GUI as seen by the user (without frame)
        JPanel gui = new JPanel(new BorderLayout());
        gui.setBorder(new EmptyBorder(2, 3, 2, 3));
        gui.add(tabbedPane, BorderLayout.CENTER);
        add(gui);

        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        // See https://stackoverflow.com/a/7143398/418556 for demo.
        setLocationByPlatform(true);
    }

    public void addTabComponent(String name, Component c) {
        tabbedPane.addTab(name, c);
        c.addMouseListener(ma);
        c.addMouseMotionListener(ma);
    }

    public void removeTabComponent(Component c) {
        tabbedPane.remove(c);
        c.removeMouseListener(ma);
        c.removeMouseMotionListener(ma);
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {

            @Override
            public void run() {

                DragTabFrame dtf = new DragTabFrame();
                dtf.init();
                BufferedImage bi = new BufferedImage(
                        200, 40, BufferedImage.TYPE_INT_RGB);
                for (int ii = 1; ii < 4; ii++) {
                    JLabel l = new JLabel(new ImageIcon(bi));
                    dtf.addTabComponent("Tab " + ii, l);
                }
                dtf.pack();
                dtf.setVisible(true);
            }
        };
        SwingUtilities.invokeLater(r);
    }
}

class DragTabManager {

    private DragTabFrame currentFrame;
    private JComponent currentComponent;
    private String currentTitle;

    /**
     * @return the currentFrame
     */
    public DragTabFrame getCurrentFrame() {
        return currentFrame;
    }

    /**
     * @param currentFrame the currentFrame to set
     */
    public void setCurrentFrame(DragTabFrame currentFrame) {
        this.currentFrame = currentFrame;
    }

    /**
     * @return the currentComponent
     */
    public JComponent getCurrentComponent() {
        return currentComponent;
    }

    /**
     * @param currentComponent the currentComponent to set
     */
    public void setCurrentComponent(JComponent currentComponent) {
        this.currentComponent = currentComponent;
    }

    /**
     * @return the currentTitle
     */
    public String getCurrentTitle() {
        return currentTitle;
    }

    /**
     * @param currentTitle the currentTitle to set
     */
    public void setCurrentTitle(String currentTitle) {
        this.currentTitle = currentTitle;
    }
}

1 个答案:

答案 0 :(得分:7)

取消激活计时器,我发现的不一致是将最后一个标签拖动到新的(不存在的)框架中。这是因为一个糟糕的其他地方没有让负责检查和关闭原始Frame的代码运行。我已经像这样修改了它,到目前为止它没有计时器:

    @Override
    public void mouseReleased(MouseEvent e) {
        JComponent c = (JComponent) e.getSource();
        if (c.getTopLevelAncestor().getBounds().contains(e.getLocationOnScreen())) {
            // do nothing, the drop point is the same frame
        } else {
            DragTabFrame dtf = getTargetFrame(e.getLocationOnScreen());
            if (dtf == null) {
                dtf = new DragTabFrame();
                dtf.init();
                dtf.setLocation(e.getLocationOnScreen());
            }// else {
            DragTabFrame fromFrame = dragTabManager.getCurrentFrame();
            fromFrame.removeTabComponent(c);
            JTabbedPane tp = fromFrame.getTabbedPane();
            if (tp.getTabCount() == 0) {
                fromFrame.setVisible(false);
                fromFrame.dispose();
            } 
            //}
            dtf.addTabComponent(dragTabManager.getCurrentTitle(), c);
            dtf.pack();
            dtf.setVisible(true);
        }
    }

[...]

public DragTabManager() {
    /* unused actionlistener code here */

    //timer = new Timer(200,actionListener);
    //timer.start();
}

我不认为应该有任何其他问题,但我不知道你提到的关闭JVM问题。