【问题标题】:How to properly destroy a JDialog?如何正确销毁 JDialog?
【发布时间】:2015-09-18 15:48:44
【问题描述】:

我目前正在处理一个具有始终存在的主要JFrame 的工作应用程序。我目前有一个孩子JDialog,它会在按下按钮时出现。此框架有一个JMenu,其中包含一个“退出显示”项目。我的任务是确保当按下退出显示选项时这个孩子JDialog 消失。注销时,通过以下方式将主显示设置为不可见:

mainFrame.setVisible(false);

子JDialog有默认关闭操作:

DISPONSE_ON_CLOSE

当用户重新登录时,首先要做的是:

mainFrame.setVisible(true); 

发生这种情况时,子对话框会重新显示。查看JDialog Javadoc,这似乎是预期的行为。但是我还没有找到打破父母/孩子关系或完全摧毁孩子JDialog的方法。似乎JDialog 将一直保留到 GC 为止,这可能不会及时发生。

这是一个模拟我看到的行为的示例程序:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;

import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;

public class WindowTest { 

    public static void createAndShowGUI() {
        JFrame aFrame = new JFrame("LAUNCHER");
        final JFrame aParent = new JFrame("PARENT"); 
        final JDialog aChild = new JDialog(aParent);

        aParent.setSize(200,200);

        final JToggleButton showParentButton = new JToggleButton("HIDE");

        showParentButton.addActionListener(new ActionListener() { 
            public void actionPerformed(ActionEvent e) {
                showParentButton.setText(!showParentButton.isSelected() ? "SHOW": "HIDE");
                aParent.setVisible(!showParentButton.isSelected());
            }
        });

        aChild.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); 
        aChild.setSize(200,200);
        aParent.addComponentListener(new ComponentAdapter() {

            public void componentHidden(ComponentEvent e) {
                aChild.dispose(); 
                aChild.setVisible(false);
            }
        });
        aFrame.setContentPane(showParentButton);
        aFrame.pack();
        aFrame.setVisible(true);
        aParent.setVisible(true);
        aChild.setVisible(true);
    }
    public static void main(String [] args) {
        SwingUtilities.invokeLater(new Runnable(){
            public void run() {
                createAndShowGUI();
            }
        });
     }
 }

当父级被隐藏时,子级被释放。当父母出现时,孩子会重新出现。真正奇怪的是,当我在孩子身上按下 X 时:当父母被隐藏然后再次显示时,孩子并没有重新出现。

我看到的唯一区别是单击 X 也会触发 WindowClosing 事件。我在上面的componentHidden方法中尝试了dispatch:

//Added into the constructor
//add to the imports: import java.awt.event.WindowEvent;
aParent.addComponentListener(new ComponentAdapter() {

        public void componentHidden(ComponentEvent e) {
            aChild.dispose(); 
            aChild.setVisible(false); 
            WindowEvent closingEvent = 
                new WindowEvent(aChild, WindowEvent.WINDOW_CLOSING); 
            aChild.dispatchEvent(closingEvent);
        }
    });

这并没有解决问题。

目前看来我唯一的选择是将孩子的类型更改为JFrame。我只是想知道是否有适当的方式处置孩子JDialog

我目前在 Redhat Enterprise Linux Server 6.4 版上运行 Java 版本:1.7.0_76 64 位。

【问题讨论】:

  • 默认情况下是不可能的 - dispose == setVisible(false),重用 JDialog 进行花药操作,使用 HIDE_ON_CLOSE
  • 我无法重复使用该对话框。 (需求、糟糕的设计、现有代码等)
  • @mKorbel 该问题的答案似乎表明 Dialog 实际上有资格进行垃圾收集,一旦它被处置。与往常一样,不能保证没有引用它的对象会立即被垃圾收集。
  • 所以基本上这是不可能的。您无法从父框架中删除子框架似乎很奇怪。
  • Here is a sample program that simulates the behavior I'm seeing:- 1) 变量名不应以大写字符开头。 2)代码应该是完整的,所以我们可以复制/粘贴/编译。它没有编译,所以我无法测试它。

标签: java swing jdialog


【解决方案1】:

我不知道命名约定会影响编译。

它没有。约定是为了一致性、可读性和可维护性而制定的。编写代码的人并不总是维护代码的人。因此,如果您希望其他人阅读您的代码,尤其是在寻求帮助时,请遵循标准。

你可以从Java Programming Style Guidelines开始

我正在按照我公司的标准从另一个屏幕手动复制代码。

这完全是浪费时间。您的代码没有任何专有信息。同样,当您提出问题时,代码应采用SSCCE 的形式,以便说明问题。这使您可以删除所有不必要的代码。

很容易弄清楚导入。

没错,所以你应该这样做。您希望我们帮助您,那么我们为什么要花时间弄清楚呢?让人们想帮助你尽可能容易。

添加导入没有帮助。您发布的代码仍然无法编译,所以我不知道它是否准确反映了您试图描述的问题。

再次发布代码的目的是让我们可以复制/粘贴/编译/测试。在您发布正确的 SSCCE 之前,我不会提供答案。

编辑:

根据我的测试,如果子窗口的可见性在父级变为不可见时被父级的可见性改变,那么子窗口的可见性在父级变为可见时也会被父级更改。所以看起来父级在可见性变化时保留了子窗口的状态。

所以解决办法是让子窗口在父窗口之前不可见:

showParentButton.setText(!showParentButton.isSelected() ? "SHOW": "HIDE");
aChild.setVisible(false); // add this
aParent.setVisible(!showParentButton.isSelected());

如果您没有对子窗口的引用,那么我想您可以使用Windows.getOwnedWindows() 方法访问所有子窗口。

另一个编辑:

作为 hack,我创建了一个自定义对话框,一旦处理就无法再次显示:

    final JDialog aChild = new JDialog(aParent)
    {
        private boolean disposed = false;

        @Override
        public void dispose()
        {
            super.dispose();
            disposed = true;
        }

        @Override
        public void show()
        {
            if (disposed)
                return;

            super.show();
        }
    };

【讨论】:

  • 我继续更新示例并验证它可以编译。如果还有其他问题,请告诉我。很抱歉我没有遵循正确的标准;最初我将它作为伪代码复制下来,因为我是手动转换的,我觉得导入不会使任何人受益。很抱歉,如果我遇到苛刻的问题,我真的觉得这是一个挑剔的建议,而不是一个有用的建议。既然我知道其他人会拉下代码,我会努力确保我的问题更完整。
  • 投反对票,因为这并不能回答问题,尽管它很好地提醒了如何提出问题。
  • 哇,你真的很难提供帮助。我会把它作为评论发布,但是在一条评论中要说的太多了。它回答了有关如何提出问题以及如何遵循对未来有益的标准的问题。无论如何,我已经用我的发现更新了答案。
  • 对不起,我试图不为难,但失败了。我反应过度,因为我觉得我没有得到帮助。我深吸了一口气,明白你只是想帮忙。很抱歉,我将其视为严厉的批评,但这确实只是事实。再次抱歉,我会更新您的答案。
  • 我尝试将孩子的 setVisible 设置为 false,就像您的回答一样,孩子仍然出现。我将更新我的问题以包括我的环境。
猜你喜欢
  • 1970-01-01
  • 2023-03-30
  • 2011-04-06
  • 2017-01-20
  • 1970-01-01
  • 1970-01-01
  • 2013-06-14
  • 2011-01-15
  • 1970-01-01
相关资源
最近更新 更多