Desenvolvimento - Java

ComboBoxModel em Java

Veja nesse artigo como implementar um ComboBoxModel em Java e tire de uma vez por todas as dúvidas que existem sobre esse assunto.

por André Pereira



Ao decorrer do tempo, percebi que muita gente tem duvidas sobre implementação do ComboBoxModel, e para piorar tudo, na internet não tem nada muito claro que possa realmente ajudar. Foi pensando nisso que resolvi criar esse tutorial com um exemplo fácil, simples e bem resumido, não tratei erros como, por exemplo, não remover um item do JComboBox quando a lista já estiver vazia, por que esse não é intuito do tutorial, e até por que cada projeto terá sua maneira de tratar erros. E é claro peço desculpas por possíveis erros, ou falta de esclarecimento, pois como grande maioria também sou um eterno aprendiz.

Fiz um exemplo bem básico, mas bem proveitoso, vamos começar pela classe modelo, que é a classe que representa seu objeto, geralmente são os dados que serão persistidos. [b]OBS: Tomem cuidado com packages. [/b]

Classe Estado (Modelo)

package br.com.combox.modelo;

public class Estados {
	private String pais;
	private String estado;
	private String cidade;
	private String bairro;
	
	public String getPais() {
		return pais;
	}
	public void setPais(String pais) {
		this.pais = pais;
	}
	public String getEstado() {
		return estado;
	}
	public void setEstado(String estado) {
		this.estado = estado;
	}
	public String getCidade() {
		return cidade;
	}
	public void setCidade(String cidade) {
		this.cidade = cidade;
	}
	public String getBairro() {
		return bairro;
	}
	public void setBairro(String bairro) {
		this.bairro = bairro;
	}
}

Acabamos de criar a classe que será representada no nosso JComboBox, nada além do que não conhecemos, uma classe com atributos e seus getters e setters. Para não deixar nenhum código muito confuso ou com muitas obrigações, criei uma classe apenas para nos auxiliar na criação e preenchimento de um List, sendo assim vamos criar uma classe chamada ControlEstados.

Classe ControlEstados (Auxiliar)

package br.com.combox.control;

import java.util.ArrayList;
import java.util.List;

import br.com.combox.modelo.Estados;

public class ControlEstados {
	List<Estados> listEstados;
	Estados estado;
	
	public ControlEstados() {
		listEstados = new ArrayList<Estados>();
	}	
	
	public List<Estados> criaListEstados() {		
		estado = new Estados();
		estado.setPais("Brasil");
		estado.setEstado("São Paulo");
		estado.setCidade("Suzano");
		estado.setBairro("Jardim Graziela");
		listEstados.add(estado);
		
		estado = new Estados();
		estado.setPais("Brasil");
		estado.setEstado("Rio de Janeiro");
		estado.setCidade("Grande Tijuca");
		estado.setBairro("Grajaú");
		listEstados.add(estado);
		
		estado = new Estados();
		estado.setPais("Brasil");
		estado.setEstado("Minas Gerais");
		estado.setCidade("Contagem");
		estado.setBairro("Petrolandia");
		listEstados.add(estado);
		
		return listEstados;		
	}
}

Esta classe apenas tem um construtor sem parâmetros que instancia o nosso List, e um método que configura este List com vários estados.

Agora vem a parte que mais nos interessa, o nosso ComboModel. O que precisamos saber é que teremos que implementar (implements) a interface ComboBoxModel que por sua vez estende (extends) a também interface ListModel<E>. Antes de começarmos irei explicar um pouco dessas duas (2) interfaces.

Na interface ComboBoxModel existem apenas dois (2) métodos a serem implementados:

public void setSelectedItem(Object anItem);

Este método é usado pelo próprio componente JComboBox para setar (configurar) o objeto que está selecionado.

public Object getSelectedItem();
 

Este método é usado pelo próprio componente JComboBox para getar (retornar) o objeto que está selecionado.

Já na interface ListModel (que é estendida pela interface ComboBoxModel) existem quatro (4) métodos, dos quais teremos que implementar apenas dois (2), um deles é o método:

public Object getElementAt(int index);

Este método recebe um int como parâmetro que será usado como índice para retornar o objeto da lista.

public int getSize();

Já este método retorna um int que é total de itens no nosso JComboBox.

Estes são os métodos que teremos que implementar e os principais para que nosso ComboBoxModel funcione da maneira que queremos.

Além de implementar a interface que citei acima devemos estender (extends) a classe abstrata AbstractListModel<E> que também implementa a interface ListModel. Lembram daqueles dois (2) métodos que disse que não precisaríamos implementar, pois é, não precisamos por que estendemos esta classe que já os implementam.

Precisamos estender essa classe por que precisamos de três métodos dessa classe, são eles:

protected void fireContentsChanged(Object source, int index0, int index1)

Responsável por atualizar por inteiro o conteúdo do JComboBox.

protected void fireIntervalAdded(Object source, int index0, int index1)

Responsável por atualizar o intervalo de dados que foram inseridos no JComboBox.

protected void fireIntervalRemoved(Object source, int index0, int index1)

Responsável por atualizar o intervalo de dados que foram removidos no JComboBox.

Esses métodos não precisamos implementar, pois eles já estão prontos para serem usados, iremos apenas chama-los quando atualizamos os dados do JComboBox, seja atualizar, remover ou inserir.

Vamos para os detalhes da classe que será nosso ComboBoxModel.

private List<Estados> listEstados;
private Estados selectedEstado;
private final static int FIRSTINDEX = 0;

Começamos declarando os atributos composto por um List que será nossa lista de estados, e também um atributo selectedEstado do tipo Estados para que seja guardado o objeto que esta selecionado no componente JComboBox. Criei também uma constante para representar o primeiro item da lista, somente para não parecer números “fantasmas” no nosso código.

public EstadosComboModel() {
	this.listEstados = new ArrayList<Estados>();
}
	
public EstadosComboModel(List<Estados> listEstados) {
	this();
	this.listEstados.addAll(listEstados);
	if (getSize() > 0) { 
		setSelectedItem(this.listEstados.get(FIRSTINDEX));
	}
}

Criaremos dois (2) construtores, um sem parâmetros do qual instanciamos a nossa lista, e outro que recebe um List que adicionamos na lista principal. Reparem que chamamos o método “setSelectedItem” para selecionar o primeiro objeto da lista.

public Object getElementAt(int index) {
	return listEstados.get(index);
}

Este método usaremos para retornar um objeto da lista conforme índice que foi passado pelo parâmetro.

public int getSize() {
	return listEstados.size();
}

Neste método apenas retornamos o tamanho da lista.

public Object getSelectedItem() {
	return selectedEstado;
}

Retornamos o atributo “selectedEstado” que é o responsável por guardar o objeto selecionado no componente JComboBox.

public void setSelectedItem(Object anItem) {
	selectedEstado = (Estados) anItem;
}

Setamos o atributo “selectedEstado” que é o responsável por guardar o objeto selecionado no componente JComboBox.

Estes métodos visto até aqui são os que devemos implementar, agora veremos alguns métodos que foram incluídos para que possamos incluir um ou mais objeto, remover e atualizar um ou mais objeto também.

public void addEstado(Estados estado) {
	listEstados.add(estado);
	fireIntervalAdded(this, getSize() - 1, getSize() - 1);
	setSelectedItem(listEstados.get(getSize() - 1));
}

Método para adicionarmos um item na lista, reparem que a partir deste precisamos chamar os métodos da classe AbstractListModel para atualizar a lista do componente, neste caso como estamos adicionando usamos o [b]fireIntervalAdded[/b].

public void addListEstado(List<Estados> estados) {
	int primeiraLinha = getSize();
	listEstados.addAll(estados);
	fireIntervalAdded(this, primeiraLinha, primeiraLinha  + estados.size());
	setSelectedItem(listEstados.get(getSize() - 1));
}

Outro para adicionar Estados, porém este adiciona uma lista.

public void removeEstado() {
	listEstados.remove(getSelectedItem());
	fireIntervalRemoved(this, FIRSTINDEX, getSize() - 1);
	setSelectedItem(listEstados.get(FIRSTINDEX));
}

Método que remove objeto selecionado da lista.

public void clear() {
	listEstados.clear();
	fireContentsChanged(this, FIRSTINDEX, getSize() - 1);
}

E por ultimo um que limpa todos os objetos da lista.

Vamos para o código da classe, como ficou no final.

Classe EstadosComboModel (ComboBoxModel)

package br.com.combox.model;

import java.util.ArrayList;
import java.util.List;

import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;

import br.com.combox.modelo.Estados;

public class EstadosComboModel extends AbstractListModel<Object> implements ComboBoxModel<Object> {

	private List<Estados> listEstados;
	private Estados selectedEstado;
	private final static int FIRSTINDEX = 0;

	public EstadosComboModel() {
		this.listEstados = new ArrayList<Estados>();
	}
	
	public EstadosComboModel(List<Estados> listEstados) {
		this();
		this.listEstados.addAll(listEstados);
		if (getSize() > 0) { 
			setSelectedItem(this.listEstados.get(FIRSTINDEX));
		}
	}
	
	@Override
	public Object getElementAt(int index) {
		return listEstados.get(index);
	}

	@Override
	public int getSize() {
		return listEstados.size();
	}

	@Override
	public Object getSelectedItem() {
		return selectedEstado;
	}

	@Override
	public void setSelectedItem(Object anItem) {
		selectedEstado = (Estados) anItem;
	}
	
	public void addEstado(Estados estado) {
		listEstados.add(estado);
		fireIntervalAdded(this, getSize() - 1, getSize() - 1);
		setSelectedItem(listEstados.get(getSize() - 1));
	}
	
	public void addListEstado(List<Estados> estados) {
		int primeiraLinha = getSize();
		listEstados.addAll(estados);
		fireIntervalAdded(this, primeiraLinha, primeiraLinha  + estados.size());
		setSelectedItem(listEstados.get(getSize() - 1));
	}
	
	public void removeEstado() {
		listEstados.remove(getSelectedItem());
		fireIntervalRemoved(this, FIRSTINDEX, getSize() - 1);
		setSelectedItem(listEstados.get(FIRSTINDEX));
	}
	
	public void clear() {
		listEstados.clear();
		fireContentsChanged(this, FIRSTINDEX, getSize() - 1);
	}
}

Antes de continuarmos precisamos informar para o componente JComboBox como ele deverá exibir nosso objeto em sua lista, algumas pessoas sobrescrevem o método “toString” na classe modelo, para indicar de forma textual como exibir o objeto. Mas a melhor forma sem duvida é renderizar o objeto, como mostro no exemplo abaixo:

package br.com.combox.renderer;

import java.awt.Component;

import javax.swing.DefaultListCellRenderer;
import javax.swing.JList;

import br.com.combox.modelo.Estados;

public class EstadosCellRenderer extends DefaultListCellRenderer {

	@Override
	public Component getListCellRendererComponent(JList<? extends Object> list,
			Object value, int index, boolean isSelected, boolean cellHasFocus) {
		super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
		
		if (value instanceof Estados) {
			Estados estado = (Estados) value;
			setText(estado.getEstado());
		}
		return this;
	}
}

Agora é só passar esse render para o componente JComboBox dessa maneira. (Veremos na classe com o frame.

comboBox.setRenderer(new EstadosCellRenderer());

Agora veremos a classe responsável pela interface gráfica com o JFrame, não irei entrar em detalhes nesta classe, postarei para que possa ser testado e estudado por todos que se interessarem pelo tutorial.

package br.com.combox.frame;

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

import br.com.combox.control.ControlEstados;
import br.com.combox.model.EstadosComboModel;
import br.com.combox.modelo.Estados;

public class FrameComboBox extends JFrame {

	private static final long serialVersionUID = 1L;
	private JPanel contentPane;
	JComboBox<Object> comboBox;
	JButton btnConsultar;
	private JButton btnRemove;
	private JButton btnLimpar;
	private JButton btnAddListEstados;
	
	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		FrameComboBox frame = new FrameComboBox();
		frame.setVisible(true);
	}

	/**
	 * Create the frame.
	 */
	public FrameComboBox() {
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 400, 250);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);
		
		List<Estados> listEstados = new ControlEstados().criaListEstados();		
		EstadosComboModel modelEstados = new EstadosComboModel(listEstados);
		
		comboBox = new JComboBox<Object>();
		comboBox.setModel(modelEstados);
		comboBox.setRenderer(new EstadosCellRenderer());
		
		btnConsultar = new JButton("Consultar");
		btnConsultar.addActionListener(new ConsultaEstadoListener());
		
		JButton btnAddEstado = new JButton("Add Estado");
		btnAddEstado.addActionListener(new AddEstadoListener());
		
		contentPane.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
		contentPane.add(comboBox);
		contentPane.add(btnConsultar);
		contentPane.add(btnAddEstado);
		
		btnRemove = new JButton("Remove");
		btnRemove.addActionListener(new RemoveEstadoListener());
		contentPane.add(btnRemove);
		
		btnLimpar = new JButton("Limpar");
		btnLimpar.addActionListener(new ClearEstadoListener());
		contentPane.add(btnLimpar);
		
		btnAddListEstados = new JButton("Add List Estados");
		btnAddListEstados.addActionListener(new AddListEstadoListener());
		contentPane.add(btnAddListEstados);
	}
	
	private class ConsultaEstadoListener implements ActionListener {
		
		public void actionPerformed(ActionEvent ae) {
			Estados estado = (Estados) comboBox.getModel().getSelectedItem();
			String dados = "Pais: " + estado.getPais();
			dados += "\nEstado: " + estado.getEstado();
			dados += "\nCidade: " + estado.getCidade();
			dados += "\nBairro: " + estado.getBairro();
			
			JOptionPane.showMessageDialog(null, dados);
		}
	}
	
	private class AddEstadoListener implements ActionListener {
		
		public void actionPerformed(ActionEvent e) {
			Estados estado = new Estados();
			estado.setPais(JOptionPane.showInputDialog("Digite o nome do Pais:"));
			estado.setEstado(JOptionPane.showInputDialog("Digite o nome do Estado:"));
			estado.setCidade(JOptionPane.showInputDialog("Digite o nome da Cidade:"));
			estado.setBairro(JOptionPane.showInputDialog("Digite o nome do Bairro:"));
			
			EstadosComboModel modelCombo = (EstadosComboModel) comboBox.getModel();
			modelCombo.addEstado(estado);
		}
	}
	
	private class RemoveEstadoListener implements ActionListener {
		
		public void actionPerformed(ActionEvent e) {
			EstadosComboModel modelCombo = (EstadosComboModel) comboBox.getModel();
			modelCombo.removeEstado();
		}
	}
	
	private class ClearEstadoListener implements ActionListener {
	
		public void actionPerformed(ActionEvent e) {
			EstadosComboModel modelCombo = (EstadosComboModel) comboBox.getModel();
			modelCombo.clear();
		}
	}
	
	private class AddListEstadoListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			List<Estados> listEstados = new ArrayList<Estados>();
			Estados estado;
			
			for (int i = 0; i < 3; i++) {
				estado = new Estados();
				estado.setPais(JOptionPane.showInputDialog("Digite o nome do Pais:"));
				estado.setEstado(JOptionPane.showInputDialog("Digite o nome do Estado:"));
				estado.setCidade(JOptionPane.showInputDialog("Digite o nome da Cidade:"));
				estado.setBairro(JOptionPane.showInputDialog("Digite o nome do Bairro:"));
				listEstados.add(estado);
			}
			
			EstadosComboModel modelCombo = (EstadosComboModel) comboBox.getModel();
			modelCombo.addListEstado(listEstados);
		}
	}
}

Só um detalhe, reparem que criei meus próprios Listeners para cada evento dos botões que usamos, as classes internas são as melhores opções para este tipo de ação.

Bem, fico por aqui e espero realmente que todos gostem, e ajudem mais ainda no estudo individual, e claro, que acabe com as duvidas sobre ComboBoxModel.

André Pereira

André Pereira - Programador há mais de 2 anos, atualmente trabalhando com VB6. Atualmente além de continuar estudando Java, também estuda PHP.