Pergunta

Criei uma aplicação Swing com vários JInternalFrames que é adicionado a um JDesktopPane no caso de um clique do mouse.Eu quero apenas uma instância do mesma estrutura interna estar presente no DesktopPane. Não quero que o mesmo quadro apareça duas vezes quando o usuário abrir o quadro.Se o quadro já estiver aberto, uma mensagem de erro deverá aparecer.!

Muito obrigado :)

Foi útil?

Solução

Não se preocupe com um antipadrão singleton.Em vez disso, simplesmente dê à sua classe um campo JInternalFrame e crie uma instância do seu JInternalFrame no construtor da sua classe ou na declaração da variável, e não crie um novo com um clique do mouse, mas sim exiba aquele que já foi criado.Por exemplo, no método mousePressed, simplesmente chame myInternalFrame.setVisible(true).Dessa forma, se era invisível, agora está visível, e se já está visível, ainda está visível e inalterado.Simples e direto.

Outras dicas

.

Eu criei um aplicativo de balanço com vários jinternalframes ...

e

.

Eu quero apenas uma instância do mesmo quadro interno ...

Então aplique o padrão singleton para cada uma das suas classes de crianças Jinternalframe. Você será capaz de usar apenas uma instância de uma classe se a classe estiver em conformidade com o padrão de singleton.

HovercraftFullOfEeels, um homem segundo meu coração, diz para não usar o padrão Singleton, e vou discordar.Singleton pode ser uma maneira muito poderosa de agilizar as coisas e evitar códigos clichês, ao mesmo tempo que mantém o sistema forte e fácil de manter.Além disso, sua sugestão de que você simplesmente exiba um arquivo já aberto JInternalFrame é falho de duas maneiras:1) Isso é difícil de gerenciar no nível do código e deixa seu sistema frágil e difícil de atualizar no futuro e 2) Quando os usuários finais fecham e reabrem uma tela, eles esperam uma nova instância, com dados atualizados e componentes totalmente novos.Não se espera que o fechamento e a reabertura sejam as mesmas instâncias.

O outro respondente diz para usar Singleton, mas não dá nenhum exemplo concreto.Então, vou fornecer o código que desenvolvi para minha aplicação:

Esta é a aula para o Singleton JInternalFrame (observação:a razão pela qual se estende JPanel é para que eu possa usá-lo facilmente em um 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);
    }
}

Aqui está um exemplo de código que o implementaria:

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()
    }
}

Eu nunca preciso que o método de chamada faça nada com a nova instância, mas por precaução, showPanel retorna a instância usada, seja a instância antiga ou a nova.Então, se você precisar fazer algo com a instância, faça o seguinte:

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

A vida foi muito mais fácil para mim quando decidi seguir esse caminho com JIFs Singleton.Altamente recomendado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top