Com instal·lar Node.js a màquines Debian.

Trobat a https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager

Com instal·lar Node.js a màquines Debian.

Build from source

sudo apt-get install python g++ make checkinstall
mkdir ~/src && cd $_
wget -N http://nodejs.org/dist/node-latest.tar.gz
tar xzvf node-latest.tar.gz && cd node-v*
./configure
sudo checkinstall -y --install=no --pkgversion 0.10.24  # Replace with current version number.
# optionally append " -- make -jx install" to the previous line and replace x with number of cores.
sudo dpkg -i node_*

Uninstall

sudo dpkg -r node

Com fer servir jProgressBar i SwingWorker

Introducció
Quan a una aplicació gràfica hi ha una tasca de llarga duració i que fa que l’usuari hagi d’esperar a que es completi cal informar a l’usuari d’aquesta circumstància, i una forma de fer-ho és mitjançant barres de progrés.

A Java Swing es fa servir el component jProgressBar. A l’apunt d’avui explicaré com fer servir jProgressBar per a informar sobre l’evolució d’una tasca que triga un temps a completar-se.

Plantejament de la solució
La construcció d’una barra de progrés que informi dels avenços d’una tasca requereix la col·laboració de diversos objectes. No és tan senzill com actualitzar l’estat de la barra. En general, si es realitza una tasca pesada al fil d’execució principal, no hi ha temps per a executar altres tasques de menor prioritat, com per exemple el repintat de finestres. La solució a aquest problema consisteix en crear fils d’execució encarregats d’aquestes actualitzacions. Es tracta d’un problema comú als entorns gràfics i la tècnica que acabo de mencionar és la forma comú de resoldre’l.

Amb Java, una aproximació genèrica faria servir la classe Thread, però a Swing hi ha disponible la classe SwingWorker que simplifica l’esquema.

Documentació
A la documentació oficial d’Oracle es pot trobar aquest tutorial “How to use a progress bar“.

Com a referència, l’enllaç al javadoc de la classe SwingWorker.

Com es fa amb java
L’esquema d’una progress bar és el següent:

1. La classe amb el fil principal d’execució ha d’implementar la interface PropertyChangeListener. Això vol dir que ha de tenir un mètode void propertyChange(PropertyChangeEvent evt). Aquest mètode s’activarà cada cop que es produeixi un canvi a les propietats progress o state de la classe que implementi la tasca en progrés. El mètode propertyChange serà l’encarregat d’actualitzar l’estat de la barra de progrés.

2. La tasca s’executarà dins d’una classe que derivarà de extends SwingWorker<Void, Void>. Això vol dir que, com a mínim, caldrà escriure doInBackground() i, si és necessari, també es pot sobreescriure done(). Al mètode doInBackground és on executarem la tasca pesada. Dins d’aquest mètode, també cal fer que el progrés de la tasca es reflexi en la propietat progress de SwingWorker mitjançant el mètode setProgress().
La propietat progress de SwingWorker només accepta valors enters entre 0 i 100. Provar d’establir altres valors amb setProgress() tornarà error.

3. Els canvis en la propietat de progrés de la classe derivada de SwingWorker seran els que caldrà capturar al mètode propertyChange de la classe de fil principal. Per aconseguir això, des de la classe principal es llençarà l’execució de la tasca.
3.1. Es crearà una instància de la tasca.
3.2. La instància de classe amb el fil de control principal es registrarà com a PropertyChangeListener de la instància de classe de la tasca.
3.3. S’executarà la tasca. El progrés de la tasca es reflexarà en la propietat progress. Els canvis en les propietats dispararan els events PropertyChange que activaran el mètode listener propertyChange dins del qual, si és el cas, s’actualitzarà la progress bar. En aquest mètode recollirem el valor de progress amb el mètode getNewValue() de l’objecte event rebut com a paràmetre i el farem servir per actualitzar la progressbar.

Un exemple
Tenint en compta l’esquema acabat de descriure, a continuació en presento un exemple: Es tracta d’una aplicació Java que presenta un formulari amb un botó. En fer click al botó es crea un fitxer de 1.000.000 de línies. Al llençar la creació del fitxer s’obre un formulari amb una progress bar que s’actualitza a mida que es creen les línies del fitxer.

El codi es pot descarregar del meu github (https://github.com/abaranguer/progressbar). El codi pujat correspon al projecte NetBeans.

El projecte té la següent estructura:

projecte

És dir, una classe per al formulari “principal”,FrameMainProvaProgressBar; una per al formulari amb la progress barFrameProgressBar; més una classe inicial ProvaProgressBar; un Controller i una classe Task.
He fet que l’aplicació seguís el patró MVC i he separat les funcionalitats seguint aquest criteri.

La classe amb el main executa el controlador.

package prova.progressbar;

import prova.progressbar.controller.Controller;

public class ProvaProgressBar {
    static Controller controller;
    
    public static void main(String[] args) {
        controller = new Controller();
        controller.initGUI();
    }
}

El constructor mostra el formulari principal i amaga el del progress bar.
El controlador té un mètode per respondre al click al botó. Quan es fa click al botó instancia una nova Task. Registra el Controller com a listener dels canvis de les propietats; mostra el formulari de la progress bar i canvia el cursor gràfic pel de “en espera”; Finalment, llença l’execució tasca en un nou fil.

El controlador implementa PropertyChangeListener. Per tant, cal sobreescriure public void propertyChange(PropertyChangeEvent evt). En aquest mètode intercepto els events corresponents als canvis de progress, en prenc el valor i actualitzo la progress bar.

El mètode done s’activa quan la tasca s’ha completat. Restaura el cursor i oculta el formulari de la progress bar

package prova.progressbar.controller;

import java.awt.Cursor;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import prova.progressbar.gui.*;

public class Controller implements PropertyChangeListener {
    FrameMainProvaProgressBar frameMainProvaProgressBar = null;
    FrameProgressBar frameProgressBar = null;

    public void initGUI() {
        frameMainProvaProgressBar = new FrameMainProvaProgressBar(this);
        frameMainProvaProgressBar.setVisible(true);
        frameProgressBar = new FrameProgressBar();
        frameProgressBar.setVisible(false);
    }
            
    public void loadProva() {
        frameProgressBar.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        frameProgressBar.setVisible(true);
        Task task = new Task(this);
        task.addPropertyChangeListener(this);
        task.execute();
    }

    public void propertyChange(PropertyChangeEvent evt) {
        System.out.println("Evt: " + evt.getPropertyName() + "; value: " + evt.getNewValue());
        if ("progress" == evt.getPropertyName()) {         
            int progress = (Integer) evt.getNewValue();
            frameProgressBar.setProgresBarValue(progress);
        } 
    }   
    
    public void done() {
        frameProgressBar.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        frameProgressBar.setVisible(false);
        System.out.println("Task done");
    }
}

La tasca java, que estén SwingWorker és on es fa tota la tasca de crear el fitxer.
Task ha de sobreescriure (@override) els mètodes doInBackground i done
La propietat progress de SwingWorker s’actualitza amb setProgress a mida que es va generant el fitxer. Cal recordar que progress només pren valors entre 0 i 100. Per això es divideix el nombre de fila (variable i) per 10000.

Quan la tasca es completa, s’activa el mètode done, que al seu temps invoca el done del Controller.

package prova.progressbar.controller;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import javax.swing.SwingWorker;

public class Task extends SwingWorker {
    Controller controller;
        
    public Task(Controller controller) {
        this.controller = controller;
    }
    
    @Override
    protected Void  doInBackground() throws Exception {    
        try {
            System.out.println("Entra");
            File file = new File("/home/albert/NetBeansProjects/prova-progressbar/file/test.txt");
            
            FileWriter fw = new FileWriter(file.getAbsoluteFile());
	    BufferedWriter bw = new BufferedWriter(fw);
            
            for(int i=0; i<1000000; i++) {
                setProgress(i/10000);
                bw.write("id: " + i +"; name: nom_" + i + "; value: valor_" + i+ "\n");
            }
	    
            bw.close();
            System.out.println("Surt");
	} catch (Exception e) {
	    e.printStackTrace();
	}

        return null;
    }
    
    @Override
    protected void done() {
        controller.done();
    }    
}

Les classes dels formularis no tenen molta cosa a comentar. Només dir que a les propietats del component progressBar cal establir que el valor màxim és 100 i el mínim 0. El motiu és que estic fent servir directament progress i, per tant, imposa aquesta límit.

En aquest vídeo, podeu veure l’execució de l’aplicació des de NetBeans.