DragTabFrame关闭不一致

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

但是,一旦它们没有更多选项卡,就会出现关闭框架的问题,以及当没有更多可见窗口时关闭框架。 我我通过DragTabManagerTimer检查来修复它们:

  • 它检查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; } } 

固定

根据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; } } 

取消激活计时器,我发现的不一致是将最后一个标签拖动到新的(不存在的)框架中。 这是因为一个糟糕的其他地方没有让负责检查和关闭原始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问题。