Larback - Retornando conhecimento

Google.

Criando aplicações MDI em java

Parte 1 - Criando o JFrame Uma aplicação pode ser dividida em duas categorias: MDI e SDI. Aplicações SDI são compostas de várias telas diferentes, ou seja, cada opção do sistema abre em uma janela diferente. Já as aplicações MDI abrem todas as telas do sistema dentro de uma única janela, tornando a aplicação mais organizada. Para isso utilizaremos, além do JFrame, o JDesktopPane e o JInternalFrame. Para criarmos uma aplicação MDI temos que criar um JFrame primeiramente. Ele será a janela em que os demais serão abertos. Vamos criar a classe pública Menu do tipo JFrame e implementar ActionListener para que possamos capturar eventos na barra de menus, que abrirá as janelas de cada módulo da aplicação:
import java.awt.event.*;
import javax.swing.*;

public class Menu extends JFrame implements ActionListener {

   //cria barra de menu                            
   private JMenuBar     jmPrincipal     = new JMenuBar();

   //cria menu "cadastro" na barra de menu
   private JMenu        jmCadastro      = new JMenu("Cadastros");

   //cria item "cliente" dentro do menu "cadastro"
   private JMenuItem    jmCadCliente    = new JMenuItem("Cliente");
   private JMenuItem    jmCadFornecedor = new JMenuItem("Fornecedor");

   //cria objeto jdPane, do tipo JDesktopPane. Ele vai dentro d JFrame
   public  JDesktopPane jdPane          = new JDesktopPane();

   Tela telaCadCliente, telaCadFornecedor, telaCadProduto;

   //método main instancia o objeto menu A inicialização fica com o construtor da classe
   public static void main(String args[]) {
      Menu menu = new Menu();
   }
O código acima cria uma classe pública chamada Menu, onde colocamos uma barra de menu com a opção "cadastro" (JMenu) e com as opções "cliente" e "fornecedor" (JMenuItem). Criamos também uma variável jdPane do tipo JDesktopPane e 3 variáveis: telaCadCliente, telaCadFornecedor e telaCadProduto. A variável jdPane será nosso JDesktopPane e as demais serão JInternalFrame. O JDesktopPane será colocado "dentro" do JFrame. Dentro dele serão colocados todos os JInternalFrame que criarmos. As variáveis telaCadCliente, telaCadFornecedor e telaCadProduto serão do tipo JInternalFrame e serão colocadas dentro do JDesktopPane, fazendo com que elas sejam abertas dentro da janela principal da aplicação. Nossos JInternalFrame são do tipo Tela. Esse é o nome da classe que usaremos para instanciá-los, ou seja, criaremos uma classe do tipo JInternalFrame e instanciaremos quantas telas quisermos. Esse é o lado bom da orientação a objetos. Abaixo temos o construtor da classe Menu que, entre outras tarefas, coloca o JDesktopPane dentro do JFrame:
//método construtor da aplicação
public Menu() {
   //"pegue o conteúdo do painel" - adiciona o jDesktopPane ao JFrame (janela principal
   getContentPane().add(jdPane);

   //adiciona o menu cadastro à barra de menus (jmPrincipal)
   jmPrincipal.add(jmCadastro);

   //adiciona o item cliente ao menu cadastro
   jmCadastro.add(jmCadCliente);

   //adiciona o item fornecedor ao menu cadastro
   jmCadastro.add(jmCadFornecedor);

   //"ajusta" a barra de menu dentro da janela principal
   setJMenuBar(jmPrincipal);

   //adiciona actionlistener ao item "cliente" do menu,
   //para que os eventos sejam tratados
   jmCadCliente.addActionListener(this);

   //adiciona o actionlistener ao item "fornecedor do menu
   jmCadFornecedor.addActionListener(this);

   setSize(800,600);
   setVisible(true);
}
Parte 2 - Eventos do Menu É aqui que está o "pulo do gato". O menu de nosso JFrame apenas irá chamar nossos JInternalFrames para que sejam abertos dentro do JDesktopPane. Uma tarefa simples, porém nos deparamos com a seguinte situação: O usuário abre a tela de cadastro de clientes. Em seguida abre a janela de cadastro de fornecedores, que fica a frente da anterior. Logo depois ele deseja abrir a janela de cadastro de clientes novamente e se esquece de que ela já está aberta, então, uma segunda janela de cadastro de cliente é aberta. Isso faz com que o sistema fique desorganizado, ocupando espaço desnecessário de memória etc. Para tratarmos esse tipo de evento vamos usar a seguinte lógica: Se a tela já estiver aberta, apenas mova-a para frente das outras janelas, mas se a janela não existir, então crie uma. Para isso utilizaremos o código abaixo:
//tratamento dos eventos de menu
public void actionPerformed(ActionEvent evt) {

   //se o evento capturado for uma chamada vinda do item cliente do menu...
   if (evt.getSource() == jmCadCliente) {
      //se não for null, a tela já está visível, tendo apenas que ser "levada pra frente"
      if (telaCadCliente == null)
         //instancia a tela de cadastro de clientes
         telaCadCliente = new Tela("Cadastro de Cliente", this);

      //independente da tela estar visível ou não, a tela é movida para frente
      jdPane.moveToFront(telaCadCliente);
   }

   // mesmo anterior, porém, ocorre quando o evento vêm do item fornecedor do menu...
   if (evt.getSource() == jmCadFornecedor) {
      if (telaCadFornecedor == null)
         telaCadFornecedor = new Tela("Cadastro de Fornecedor", this);

      jdPane.moveToFront(telaCadFornecedor);
   }
}
Um simples teste if colocado dentro do evento realiza um teste lógico e descobre se a tela ainda não foi criada (se seu valor for null, ela ainda não existe). Caso a tela não exista, ela é criada através da instanciação de um objeto, mas se a tela já existir, ela é apenas movida para frente, com o uso da função jdPane.moveToFront(). O título da janela é passado como parâmetro na instanciação de cada JInternalFrame. O parâmetro this indica a tela principal para o JInternalFrame. Parte 3 - A classe Tela Essa é a classe do tipo JInternalFrame que usaremos para instanciar as demais. Dois parâmetros são passados durante a instanciação. O primeiro é o título da janela. O segundo indica a classe pai dos objetos que serão instanciadas por essa classe. Vejamos o código da classe Tela:
class Tela extends JInternalFrame {

   //classe pai dos objetos que serão instanciadas por essa classe
   private Menu telaPrincipal;

   //método construtor da tela
   public Tela(String titulo, Menu telaPrincipal) {

      //reescreve o método construtor da classe pai, ajustando o título da janela (neste caso)
      super(titulo,true,true,true,true);

      setSize(300,200);
      setVisible(true);

      this.telaPrincipal = telaPrincipal;

      telaPrincipal.jdPane.add(this);
   }

}

O título é usado no construtor pelo método super(), que sobrescreve o construtor da classe pai, alterando assim o título da página. Os quatro "true" ativam os botões minimizar/maximizar, restaurar e fechar de cada JInternalFrame. Abaixo está o código completo e sem os comentários:
mport java.awt.event.*;
import javax.swing.*;

public class Menu extends JFrame implements ActionListener {

   private JMenuBar jmPrincipal = new JMenuBar();
   private JMenu jmCadastro = new JMenu("Cadastros");
   private JMenuItem jmCadCliente = new JMenuItem("Cliente");
   private JMenuItem jmCadFornecedor = new JMenuItem("Fornecedor");

   public JDesktopPane jdPane = new JDesktopPane();

   Tela telaCadCliente, telaCadFornecedor, telaCadProduto;

   public static void main(String args[]) {
      Menu menu = new Menu();
   }

   public Menu() {
      getContentPane().add(jdPane);
      jmPrincipal.add(jmCadastro);
      jmCadastro.add(jmCadCliente);
      jmCadastro.add(jmCadFornecedor);
      setJMenuBar(jmPrincipal);
      jmCadCliente.addActionListener(this);
      jmCadFornecedor.addActionListener(this);
      setSize(800,600);
      setVisible(true);
   }

   public void actionPerformed(ActionEvent evt) {

      if (evt.getSource() == jmCadCliente) {
         if (telaCadCliente == null)
            telaCadCliente = new Tela("Cadastro de Cliente", this);

         jdPane.moveToFront(telaCadCliente);
      }

      if (evt.getSource() == jmCadFornecedor) {
         if (telaCadFornecedor == null)
            telaCadFornecedor = new Tela("Cadastro de Fornecedor", this);

         jdPane.moveToFront(telaCadFornecedor);
      }
   }
}

class Tela extends JInternalFrame {

   private Menu telaPrincipal;

   public Tela(String titulo, Menu telaPrincipal) {
      super(titulo);
      setSize(300,200);
      setVisible(true);

      this.telaPrincipal = telaPrincipal;
      telaPrincipal.jdPane.add(this);
   }
}
Retirado de http://www.htmlstaff.org/ver.php?id=22602 (acesso em 28/11/10)