Criando compoment proprio - DBNavigator, como tratar evento

Boa tarde.

Este eh meu primeiro post.
Estou aprendendo java (novamente, parei a uns 6 ou 8 anos atras no basico) e me interessei de novo.
Ja leio o forum a algum tempo para pegar dicas e acho-o muito util.

Estou aprendendo, entao comecei uma aplicação basicamente “refazendo” uma aplicacao que desenvolvi em Delphi a uns anos atras, so que agora em Java.

Pesquisei muito no google e outros foruns, e em nenhum lugar achei uma resposta que funcionasse para uma duvida que tenho, então vamos ver se aqui consigo me esclarecer melhor.

Meu problema eh o seguinte. Eu gosto de colocar em formulario de cadastro uma ferramenta semelhante ao DBNavigator do Delphi. Para quem não sabe o que eh um DBnavigator. Eh basicamente uma barra de botoes que permite navegar pelo ponteiro (indicador de registro atual) de um banco de dados.
Desta forma, posso ir para o primeiro, ultimo, proximo registro ou anterior ao atual rapidamente.

A forma que eu encontrei para que isso fosse possível, foi criar um objeto DBNavigator em java que extende JPanel. Neste objeto eh feita a formatação da tela do componente (adicionando outros paineis, botoes, etc).

O problema eh. Dentro do componente, eu preciso tratar ActionEvents (clique do botao).
Até ai, tudo muito bom. Por exemplo. Se eu clicar no botao “primeiro”, eu movo o ponteiro para o primeiro registro do Banco de Dados simplesmente chamando uma classe de negocios (control) que sabe como se comportar quando voce chama algo do tipo dbObject.first().

Para eu poder chamar esta classe de negocios, eu passo para meu DBNavigator, no construtor ou via um metodo setDatabaseObject(databaseObject) que recebe minha classe de negocios (DAO) como parametro.
Ou seja. Movimentar e manipular o banco de dados em si nao eh problema. Porem como eu trato o evento de “clique” dentro da classe. E essa classe tem por objetivo funcionar com qualquer modelo de DAO em qualquer formulario, eu não posso por exemplo fazer “txNomeEmpresa.setText(String text)” em um JTextField do formulario que estou trabalhando. Pois nao sei que formulario eh esse.

Para poder usar qualquer classe de controle de banco de dados que eu crie, eu criei uma classe Abstract que usa Generics para manipular o Banco.

Agora vamos la ao problema real. Eu preciso, quando o botao “Primeiro” por exemplo for clicado, saber no meu formulario (JDialog) que houve este clique. Para trata-lo. O tratamento seria pegar os dados do banco de dados, atravez do metodo DAO.getCurrent() que retorna um objeto (definido como modelo, exemplo Estados ou Cliente) e gravar nos capos de texto, combo, etc.

Resumindo.
Eu insiro meu objeto DBNavigator em um painel num JDialog. E quero saber se qualquer botao do meu DbNavigator foi clicado e resgatar qual botão foi este. E assim poder tratar o evento visualmente.
Como eu faria para saber que meu “objeto” que extende JPanel recebeu um clique em “qualquer” botao dento dele? Qual Listener eu poderia usar?

Nao sei se consegui explicar bem minha duvida e se estou fazendo certo. Eh uma grande duvida minha como "passar adiante " um evento que ocorre internamente em uma classe e trata-lo fora dela.

Vamos ao codigo, postarei apenas o que acho pertinente, nao vou ficar postando formatacao de formularios, layouts etc pois acho que so tornaria o topico maior. Se alguma identacao ficou ruim desculpem, copiei e colei dentro da tag CODE.

Classe generica abstrata para manipular banco de dados.


package model;

import java.sql.Connection;
import java.sql.SQLException;

/**
 *
 * @author Alex
 * @param <T>
 */
public abstract class GenericDAO <T> {
    
    //conexao ao BD
    /**
     * Retorna conexao
     * @return
     * @throws SQLException 
     */
    abstract public Connection getConnection() throws SQLException;
    /**
     * Inicia conexoes 
     * @throws SQLException 
     */
    abstract public void startConnection() throws SQLException;
    /**
     * inicia o dataset rolavel
     * @throws SQLException 
     */
    abstract public void startDataSet() throws SQLException;
    //Operacoes basicas
    /**
     * Cria novo registro
     * @param newRecord
     * @throws SQLException 
     */
    abstract public void novo(T newRecord) throws SQLException;
    /**
     * Altera registro atual
     * @param changedRecord
     * @throws SQLException 
     */
    abstract public void altera(T changedRecord) throws SQLException;
    
    /**
     * Exclui registro atual
     * @throws SQLException 
     */
    abstract public void exclui() throws SQLException;
    //movimentacao de cursor etc
    /**3
     * Retorna numero da linha atual do BD
     * @return
     * @throws SQLException 
     */
    abstract public int getRow() throws SQLException;
    /**
     * Move ponteiro para linha desejada
     * @param row
     * @return
     * @throws SQLException 
     */
    abstract public int goToRow(int row) throws SQLException;
    /**
     * Move ponteiro para primeiro registro
     * @throws SQLException 
     */
    abstract public void first() throws SQLException;
    /**
     * Move ponteiro para ultimo registro
     * @throws SQLException 
     */
    abstract public void last() throws SQLException;
    /**
     * move ponteiro para registro anterior
     * @throws SQLException 
     */
    abstract public void previous() throws SQLException;
    /**
     * Move ponteiro para proximo registro
     * @throws SQLException 
     */
    abstract public void next() throws SQLException;
    /**
     * Retorna objeto contendo dados do registro atual.
     * @return
     * @throws SQLException 
     */
    abstract public T getCurrent() throws SQLException;
    /**
     * Fecha todas as conexoes ao BD
     * @throws SQLException 
     */
    abstract public void closeAll() throws SQLException;
    

}

Classe modelo de “País”. No caso países do mundo. implementa os metodos de GenericDAO.
A classe eh responsável pela conexão e navegação no BD.


package control;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import model.GenericDAO;
import model.Pais;


public class PaisDAO extends GenericDAO<Pais> {

    private Connection conn;
    private PreparedStatement ps;
    private ResultSet rollRs;
            
    private final String CONNECTION_TYPE="jdbc:mySql";
    private final String CONNECTION_HOST="localhost:3306";
    private final String CONNECTION_SCHEMA="nomeschema";
    private final String CONNECTION_USER="root";
    private final String CONNECTION_PASSWORD="password";
    private final String SELECT_QUERY="select * from paises";

    public PaisDAO() {
    }
    
    /**
     * Cria a conexao e retorna a mesma.
     * @return
     * @throws SQLException 
     */
    @Override
    public Connection getConnection() throws SQLException {
        Connection        connection=DriverManager.getConnection(CONNECTION_TYPE+"://"+CONNECTION_HOST+"/"+CONNECTION_SCHEMA,
                CONNECTION_USER,CONNECTION_PASSWORD);
        return connection;
    }
    
    /**
     * Inicia a conexao. Para retornar referencia a conexao use getConnection().
     * @throws java.sql.SQLException 
     */
    @Override
    public void startConnection() throws SQLException {
        try {
            conn=getConnection();
        } catch (SQLException e){
            throw new SQLException(e.getMessage());
        }
    } //startConnection
    
    /**
     * Cria o prepard Statement com SQL e o Result Set rollavel e com update.
     * @throws SQLException 
     */
    @Override
    public void startDataSet() throws SQLException{
        ps=conn.prepareStatement(SELECT_QUERY, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
        rollRs=ps.executeQuery();
    }
    
    @Override
    public void novo(Pais p) throws SQLException{
        
        try {
            rollRs.moveToInsertRow(); //nova linha
            rollRs.updateInt("pais", p.getPais());
            rollRs.updateString("abreviado", p.getAbreviado());
            rollRs.updateString("descricao",p.getDescricao());
            rollRs.updateString("icone",p.getIcone());
            rollRs.insertRow(); //Salva as alteracoes.
            rollRs.moveToCurrentRow();
            
            
        } catch (SQLException e) {
            throw new SQLException(e.getMessage());
        }
        
    } //fim novo pais
    
    @Override
    public void altera(Pais p) throws SQLException{
        try {
            
            rollRs.updateInt("pais", p.getPais());
            rollRs.updateString("abreviado", p.getAbreviado());
            rollRs.updateString("descricao",p.getDescricao());
            rollRs.updateString("icone",p.getIcone());
            rollRs.updateRow();
            rollRs.moveToCurrentRow();
        } catch (SQLException e) {
            throw new SQLException(e.getMessage());
        }
        
    }
    
    @Override
    public void exclui() throws SQLException{
        rollRs.deleteRow();
        rollRs.moveToCurrentRow();
    }
            
    /**
     *
     * @return
     * @throws SQLException
     */
    @Override
    public int getRow() throws SQLException{
        return rollRs.getRow();
    }
    /**
     * 
     * @param row
     * @return
     * @throws SQLException 
     */
    @Override
    public int goToRow(int row) throws SQLException{
        int oldRow=getRow();
        rollRs.absolute(row);
        return oldRow;
    }
    /**
     * 
     * @throws SQLException 
     */
    @Override
    public void first() throws SQLException{
        rollRs.first();
    }
    /**
     * 
     * @throws SQLException 
     */
    @Override
    public void last() throws SQLException {
        rollRs.last();
    }
    
    @Override
    public void previous() throws SQLException{
        if (rollRs.isBeforeFirst()){
            rollRs.first();
        } else {
            rollRs.previous();
        }
    }
    /**
     * 
     * @throws SQLException 
     */
    @Override
    public void next() throws SQLException{
        if (rollRs.isAfterLast()){
            rollRs.last();
        } else {
            rollRs.next();
        }
    }
    
    /**
     * Retorna objeto no registro atual
     * @return 
     * @throws java.sql.SQLException 
     */
    @Override
    public Pais getCurrent() throws SQLException {
        Pais p=new Pais();
        
        p.setPais(rollRs.getInt("Pais"));
        p.setDescricao(rollRs.getString("Descricao"));
        p.setAbreviado(rollRs.getString("Abreviado"));
        p.setIcone(rollRs.getString("Icone"));
        return p;
    }
   
    /**
     * Fecha todas as conexoes e datasets
     * @throws SQLException 
     */    
    @Override
    public void closeAll() throws SQLException {
        try {
            conn.close();
            ps.close();
            rollRs.close();
        } catch (SQLException e) {
            throw new SQLException(e.getMessage());
            
        }
        
    } //fim closeAll
    
    
}

Classe DBnavigator:
Reparem que o clique do botao First já movimentaria o Banco de dados. Porem fiquei preso em como fazer para depois saber que o DBNavigator foi clicado para poder pegar os dados atuais do BD.

package view;

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.SQLException;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import model.GenericDAO;

/**
 *
 * @author X8
 */
public class DBNavigator extends JPanel {
    
    private JButton btNovo;
    private JButton btAlterar;
    private JButton btExcluir;
    private JButton btFirst;
    private JButton btPrevious;
    private JButton btNext;
    private JButton btLast;
    private JTextField txRecord;
    private JPanel pnBasicOp;
    private JPanel pnNavigate;
    private GenericDAO dbObject; //O objeto database

   
    
    
    public DBNavigator(GenericDAO db) {
        this();
        dbObject=db;
            
    }
    
    public DBNavigator() {
        
        this.setLayout(new GridLayout(1,2)); //Uma linha 2 colunas para os paineis
        iniciaVars();
        //inserir botoes basicos
        criaInterface();
        
    }

    
     public void setDbObject(GenericDAO dbObject) {
        this.dbObject = dbObject;
    }
    
    private void criaInterface(){
        
        
        pnBasicOp.setLayout(new GridLayout(1,3));
        pnBasicOp.add(btNovo);
        pnBasicOp.add(btAlterar);
        pnBasicOp.add(btExcluir);
        this.add(pnBasicOp); 

        pnNavigate.setLayout(new GridLayout(1,5));
        pnNavigate.add(btFirst);
        pnNavigate.add(btPrevious);
 
        txRecord.setEditable(false);
        txRecord.setHorizontalAlignment(JTextField.CENTER);
        pnNavigate.add(txRecord);
        
        pnNavigate.add(btNext);
        pnNavigate.add(btLast);
        this.add(pnNavigate);
        
        //Adiciona listeners de eventos
        btFirst.addActionListener((ActionEvent evt) -> {
            btFirstActionPerformed(evt);
        });
    }
    
    
    
    private void iniciaVars(){
         btNovo=new JButton("Novo");
         btAlterar=new JButton("Alterar");
         btExcluir=new JButton("Excluir");
         btFirst=new JButton("<<");
         btPrevious=new JButton("<");
         btNext=new JButton(">");
         btLast=new JButton(">>");
         pnBasicOp=new JPanel();
         pnNavigate=new JPanel();
         txRecord=new JTextField("0");
    }
    
    


    private void btFirstActionPerformed(ActionEvent evt) {
        try {
            dbObject.first();
        } catch (SQLException e) {
            showMessage("<html>Erro no acesso ao BD:<br><br> "+e.getMessage());
        }
    }
    
    private void showMessage(String msg)  {
        JOptionPane.showMessageDialog(null, msg);
    }
    
}

Classe Pais

package model;

/**
 * Classe modelo de País.
 * @author Alex
 */
public class Pais {
    
    private int pais;
    private String descricao;
    private String abreviado;
    private String icone;

    
    /**
     * Construtor para estado inicial.
     */
    public Pais() {
        this.pais = 0;
        this.descricao = "";
        this.abreviado = "";
        this.icone = "";
    }

    /**
     * Define o codigo internacional do pais
     * @param pais 
     */
    public void setPais(int pais) {
        this.pais = pais;
    }

    /**
     * Define a descricao do pais (nome)
     * @param descricao 
     */
    public void setDescricao(String descricao) {
        this.descricao = descricao;
    }

    /**
     * Define abreviacao do pais
     * @param abreviado 
     */
    public void setAbreviado(String abreviado) {
        this.abreviado = abreviado;
    }

    /**
     * Define caminho do icone
     * @param icone 
     */
    public void setIcone(String icone) {
        this.icone = icone;
    }

    /**
     * retorna codigo do pais
     * @return 
     */
    public int getPais() {
        return pais;
    }
    /**
     * retorna a descricao
     * @return 
     */
    public String getDescricao() {
        return descricao;
    }
    /**
     * Retorna abreviacao
     * @return 
     */
    public String getAbreviado() {
        return abreviado;
    }

    /**
     * Retorna caminho do icone
     * @return 
     */
    public String getIcone() {
        return icone;
    }

    /**
     * Representacao String
     * @return 
     */
    @Override
    public String toString() {
        return Integer.toString(getPais()) + getDescricao() +getAbreviado() + getIcone();
    }
    
}

Obrigado pela ajuda de todos. Já raciocinei uma solução, mais simples do que imaginava.

Apenas faltam alguns ajustes na implementação.

Abraços.

Qual foi a solução encontrada?