2

我创建了一个带有多个JInternalFrames的 Swing 应用程序,当鼠标单击时,这些 JInternalFrames 会被添加到 JDesktopPane 中。我只希望DesktopPane 上出现相同内部框架一个实例。当用户打开框架时,我不希望同一个框架出现两次。如果框架已经打开,则应出现错误消息。!

非常感谢 :)

4

3 回答 3

6

我用几个 JInternalFrames 创建了一个 Swing 应用程序......

我只想要一个相同内部框架的实例......

因此,将单例模式应用于您的每个 JInternalFrame 子类。如果类符合单例模式,您将只能使用该类的一个实例。

于 2012-03-11T17:23:40.323 回答
5

不要为单例反模式而烦恼。相反,只需给您的类一个 JInternalFrame 字段并在您的类的构造函数或变量声明中创建您的 JInternalFrame 的一个实例,并且不要在鼠标单击时创建一个新实例,而是显示已经创建的一个实例。例如在 mousePressed 方法中,只需调用myInternalFrame.setVisible(true). 这样,如果它是不可见的,现在它是可见的,如果它已经是可见的,那么它仍然是可见的并且没有改变。简单明了。

于 2012-03-11T17:52:07.927 回答
1

HovercraftFullOfEeels,一个合我心意的人,说不要使用单例模式,我不同意。单例可以是一种非常强大的方式来简化事物并避免样板代码,同时保持系统强大且易于维护。此外,他建议您仅显示已打开JInternalFrame的文件在两个方面存在缺陷:1)这在代码级别上难以管理,并且使您的系统脆弱且将来难以更新; 2)当最终用户关闭并且重新打开一个屏幕,他们期待一个新实例,其中包含更新的数据和全新的组件。预计关闭和重新打开不会是相同的情况。

另一个回答者说要使用 Singleton,但没有给出具体的例子。所以,我将给你我为我的应用程序开发的代码:

这是 Singleton 的类JInternalFrame(注意:它扩展的原因JPanel是我可以在 GUI Builder 中轻松使用它):

public abstract class VPanel extends JPanel {

    public static JDesktopPane desktopPane;

    public static void installDesktopPane(JDesktopPane desktopPane) {
        VPanel.desktopPane = desktopPane;
    }

    public VPanel(String name) {
        this.name = name;
        if(desktopPane == null)
            throw new IllegalStateException("VPanel is being used with a null desktop pane.");
    }
    static LinkedHashMap<Class, VPanel> self_panel_map;

    JInternalFrame self_jif;
    protected VPanel self_panel;
    boolean loading;
    boolean showing;

    public final String name;
    public abstract void init();

    public static VPanel showPanel(VPanel newInstance) {
        if(self_panel_map == null)
            self_panel_map = new LinkedHashMap<>();
        Class newInstanceClass = newInstance.getClass();
        if(self_panel_map.containsKey(newInstanceClass)) {
            VPanel oldInstance = self_panel_map.get(newInstanceClass);
            oldInstance.showing = oldInstance.self_jif.isVisible();
            if(!oldInstance.loading && !oldInstance.showing) {
                newInstance.loading = true;
                newInstance.self_panel = newInstance;
                newInstance.self_jif = new JInternalFrame(newInstance.name, true, true, true, true);
                newInstance.self_panel.init();
                self_panel_map.put(newInstanceClass, newInstance);
                return newInstance;
            } else if(oldInstance.showing) {
                try {
                    oldInstance.self_jif.setSelected(true);
                } catch (PropertyVetoException e) {
                    handleError(e);
                }
            }
            return oldInstance;
        } else {
            newInstance.loading = true;
            newInstance.self_panel = newInstance;
            newInstance.self_jif = new JInternalFrame(newInstance.name, true, true, true, true);
            newInstance.self_panel.init();
            self_panel_map.put(newInstanceClass, newInstance);
            return newInstance;
        }
    }

    public void setVisible() {

        self_jif.add(self_panel);
        self_jif.pack();
        self_jif.setVisible(true);
        desktopPane.add(self_jif);
        centerJIF();
        try {
            self_jif.setSelected(true);
        } catch (PropertyVetoException e) {
            handleError(e);
        }
        loading = false;
    }

    private static void handleError(Exception e) {
        e.printStackTrace();
    }

    public void centerJIF() {
        Dimension desktopSize = desktopPane.getSize();
        Dimension JInternalFrameSize = self_jif.getSize();
        int width = (desktopSize.width - JInternalFrameSize.width) / 2;
        int height = (desktopSize.height - JInternalFrameSize.height) / 2;
        self_jif.setLocation(width, height);
    }
}

这是一个实现它的示例代码:

public static void main(String[] args) {
    JFrame jf = new JFrame("MainFrame");
    JDesktopPane jdp = new JDesktopPane();
    jf.setExtendedState( jf.getExtendedState()|JFrame.MAXIMIZED_BOTH );

    VPanel.installDesktopPane(jdp); // This only needs to happen once throughout the entire application lifecycle.

    JMenuBar menuBar = new JMenuBar();
    JMenu menu = new JMenu("Panels");
    JMenuItem menuItem = new JMenuItem("Open Test Panel");
    menuItem.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            Test_VPanel.showPanel(new Test_VPanel()); // Every time you show the panel, you create a new instance.
            // But this new instance is only used if it is needed. The init() method is only called if it is going
            // To show a new instance.
        }
    });
    menu.add(menuItem);
    menuBar.add(menu);
    jf.setJMenuBar(menuBar);


    jf.setContentPane(jdp);

    jf.setVisible(true);
    jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

static class Test_VPanel extends VPanel {

    public Test_VPanel() {
        super("Test Panel");
    }

    @Override
    public void init() {
        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();

        JLabel label = new JLabel("JLabel");
        JTextField textField = new JTextField();

        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.weightx = 1;
        gbc.gridwidth = 1;
        gbc.gridy = 0;
        gbc.insets = new Insets(4,4,4,4);
        add(label, gbc);

        gbc.gridy = 1;
        add(textField, gbc);

        setVisible(); // This needs to be called at the end of init()
    }
}

我从不需要调用方法对新实例做任何事情,但只是以防万一,showPanel返回使用的实例,无论是旧实例还是新实例。所以,如果你需要对实例做一些事情,你可以这样做:

Test_VPanel panel = Test_VPanel.showPanel(new Test_VPanel());
panel.something();
...

一旦我决定使用 Singleton JIF 走这条路,我的生活就轻松多了。强烈推荐。

于 2014-05-19T20:13:17.910 回答