Pass the execution of a particular method to Swingworker as argument

Asked

Viewed 498 times

3

I have a small application on swing, where I would like to display progress when certain actions are executed

As an example, I have the listener below that is run when a JComboBox is changed. It takes the selected item(which in this case is an object Setor with id and name), and passes the id pro CadastranteComboModel, which, in turn, searches the bank for the list of registrants of that past sector and displays in another JComboBox of registrants:

private void comboSetorItemStateChanged(java.awt.event.ItemEvent evt) {                                            
    if (evt.getStateChange() == ItemEvent.SELECTED) {
        final int setorId = ((Setor) evt.getItem()).getId();
        CadastranteComboModel cadComboModel = new CadastranteComboModel(setorId);
        comboUsuario.setModel(cadComboModel);

The problem is that this communication with the bank (which is in HSQL) takes a while, because the application is executed from a network location in Stand-alone mode. So I created a JDialog only to display a JProgressBar infinite, but do not know how to pass the line execution CadastranteComboModel cadComboModel = new CadastranteComboModel(setorId);, for example, for the SwingWorker in the doInBackground().

Trying to get around this problem, I downloaded this code inside the listener quoted:

        SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
            // esta é a janela que fiz a parte
            //com a JProgressBar infinita
            ProgressDialog progress;

             //esse método que ativa o progresso pelo publish()
            // e executa a linha a seguir em uma Thread separada
            @Override
            protected Void doInBackground() throws Exception {
                publish();
                CadastranteComboModel cadComboModel = new CadastranteComboModel(setorId);
                comboUsuario.setModel(cadComboModel);
                return null;

            }

            @Override
            protected void process(List<Void> chunks) {
                // getInstance() é o frame da tela como referencia
                //esse método é "decorativo"
                changeStatusComponent(getInstance(), false);
                //chama e exibe a JDialog com a JProgressBar
                progress = new ProgressDialog(getInstance(), true);
                progress.setLocationRelativeTo(getInstance());
                progress.setVisible(true);
            }

            @Override
            protected void done() {
                //quando termina a execução no doInBackground
                // fecho a tela de progresso
                progress.dispose();
                changeStatusComponent(getInstance(), true); 
            }
        };
        worker.execute();

It works perfectly for the case, only I’ll have to repeat the same block of code in other 7 or 8 methods (some even return values), which have some action that depends on query in the bank, like this one that excludes an office of the table and the bank:

private void btnExcluirOficioActionPerformed(java.awt.event.ActionEvent evt) {                                                 
    int indiceRowModel = this.tabela.getRowSorter().convertRowIndexToModel(this.tabela.getSelectedRow());
    int intOf = (int) this.tabela.getModel().getValueAt(indiceRowModel, 0);
    Date date = (Date) this.tabela.getModel().getValueAt(indiceRowModel, 3);
    String strAno = new SimpleDateFormat("yyyy").format(date);
    String strSetor = (String) this.tabela.getModel().getValueAt(indiceRowModel, 5);
    String strOficio = strSetor + " " + intOf + "-" + strAno;

    int confirma = JOptionPane.showConfirmDialog(getInstance(), "Excluir o oficio " + strOficio + "?",
            ListaDeOficiosUI.TITULO, JOptionPane.YES_NO_OPTION);
    if (confirma == JOptionPane.YES_OPTION) {
        try {
            //por causa desta chamada, vou ter que inserir aquele bloco
            // do swingworker
            this.tableModel.removeRow(indiceRowModel);
            PrintMessageUI.exibirMsg(this.getInstance(), "Oficio" + strOficio + " excluído.");
        } catch (ExcecaoPadrao ex) {
            PrintMessageUI.exibirError(this, ex.getMessage());
        }
    }
}

What I need to do is a class that inherits from swingworker and can receive these "problematic" methods as an argument, passing their execution to the doInBackground, but I don’t know how I can do it.

Is there any way to pass one method as argument to another, and its execution is not performed in the call, but within the method that received it as argument?

Note: the application (the jar, in this case) is in java7, I cannot do in java8 by IT restrictions(but java8 suggestions are welcome).

  • These methods you want to run on doInBackground() all have the same signature?

  • @ramaral unfortunately not :/, only if I bar directly in the controllers, because as can be seen in that question that I did a few days ago, they have in common the interface with exactly the same methods, in the end, practically all methods call some controller and these yes are standardized by interface. Problem is I don’t know if it’s good practice to "call GUI" in a class that has nothing to do with GUI, but if that’s the only solution...

1 answer

3


If the methods you want to run on doInBackground() had all the same signature the solution would be to declare an interface and pass it in the constructor of a class inherited from Swingworker.

public class Worker extends SwingWorker<Void, Void>{

    interface Operation{
        void execute(int valor); //Altere a assinatura de acordo com a sua necessidade
    }

    Operation operation;
    int valor;
    public Worker(Operation operation, int valor){

        this.operation = operation;
        this.valor = valor;
    }

    @Override
    protected Void doInBackground() throws Exception {

        operation.execute(valor);
    }

    @Override
    protected void process(List<Void> chunks) {

        -----
        -----
    }

    @Override
    protected void done() {

        -----
        -----
    }
}

Any class that implements the interface Operation can be passed in the constructor and its method executed in the doInBackground():

Worker worker = new Worker(myOperationClass, 10);
worker.execute();

As this does not happen, a possible solution will be, since what varies is only the code of doInBackground(), create an abstract class that inherits from Swingworker and implement the methods process() and done(), leaving the method doInBackground() by implementing.

public abstract class Worker extends SwingWorker<Void, Void>{

    //Implemente os métodos process e done

    @Override
    protected void process(List<Void> chunks) {

        -----
        -----
    }

    @Override
    protected void done() {

        -----
        -----
    }
}

When you need to execute one of tasks create an instance of this class and then implement the method doInBackground().

Worker worker = new Worker(){

    @Override
    protected Void doInBackground() throws Exception {

        //implemente de acordo com a situação.
    }
};
worker.execute();
  • Thanks for the examples, the first I could not implement because I did not understand kkk but the second seems that is the solution I needed! I will test tomorrow at the company(the code is on the pc there) and give a feedback.

  • 1

    It really worked, thank you :)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.