Não atualiza o valor do JLabel depois de um evento

Pessoal boa tarde,

Estou a alguns dias tentando criar uma animação utilizando eventos e swing. A minha idéia é a seguinte: criar um taxímetro. Eu tenho um JFrame que é onde eu monto minha GUI, onde tenho um JLabel que informa o preço, um JComboBox que possui uma lista de cidades e dois botões, sendo um que inicia o taxímetro e o outro que para o mesmo.

O meu problema é que, quando eu clico no botão "Iniciar", parece que o JFrame congela enquanto o processamento continua, porém não existe o resultado no JLabel de preço.

Abaixo seguem minhas classes.

//Classe Cidade que possui os métodos de captura dos valores de cada modalidade
package Taximetro;

public abstract class Cidade {
	
	public double valorPorKmRodado;
	public double valorPorMinutoParado;
	public double valorFixo;
	public String cidade;	
	
	public double getValorPorKmRodado(){
		return this.valorPorKmRodado;
	}
		
	public double getValorPorMinutoParado(){
		return this.valorPorMinutoParado;
	}
	
	public double getValorFixo(){
		return this.valorFixo;
	}
	
	public String getCidade(){
		return this.cidade;
	}
}
//Classe que efetivamente faz os cálculos do valor da corrida, com base na cidade (pois cada uma tem uma taxa diferente)
package Taximetro;

public class TaxiDroid {
	public double valorPor100Metros;
	public double distanciaPercorrida;
	public double valorTotal;
	public Cidade cidade;
	public boolean usando;
	
	public void getDadosDaCidade(Cidade c){
		if(c != null){
			this.cidade = c;
			valorPor100Metros = c.getValorPorKmRodado() / 10;			
		} else {
			System.out.println("Erro");
		}
	}
	
	public void calcularUso(){
		boolean usando = true;

		try{
			while(usando){
				//Acredito que aqui seja o problema, mas não sei como corrigir
				Thread.sleep(1000);
				distanciaPercorrida = distanciaPercorrida + 0.1;
				if(distanciaPercorrida >= 10){
					usando = false;
					break;
				}
				valorTotal = valorTotal + valorPor100Metros;			
			}		
			valorTotal = valorTotal + cidade.getValorFixo();
		}catch(Exception e){

		}		
	}
}
//Classe onde eu construo a gui e onde ocorrem os eventos
package Taximetro;

import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Font;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;

import java.awt.event.*;

public class TaxiInterface{
	JFrame frame;
	JLabel preco;
	JLabel lblCidade;
	JList listCidades;
	JButton btnComecar;
	JButton btnParar;
	Thread comecar;
	TaxiDroid taxi = new TaxiDroid();
	
	public void criarInterfaceTaximetro(){
		Cidade c = new SaoPaulo();
		taxi.getDadosDaCidade(c);
		
		FlowLayout flow = new FlowLayout();
		
		frame = new JFrame("Android Taxímetro");
		frame.setLayout(flow);
		frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
		frame.setResizable(false);
		frame.setSize(300, 180);
		
		Font bigFont = new Font("verdana", 4, 55);
		preco = new JLabel("R$ 0,00");
		preco.setFont(bigFont);
		
		String [] cidades = new String[]{"São Paulo", "Brasília"};
		lblCidade = new JLabel("Selecione a cidade: ");		
		JComboBox comboCidades = new JComboBox(cidades);		
		
		btnComecar = new JButton("Iniciar");
		btnComecar.addActionListener(new BotaoComecarListener());
		
		btnParar = new JButton("Parar");
		btnParar.addActionListener(new BotaoPararListener());
		
		frame.add(preco);
		frame.add(lblCidade);
		frame.add(comboCidades);
		frame.add(btnComecar);
		frame.add(btnParar);
		frame.setVisible(true);	
	}
	
	public TaxiInterface(){
		criarInterfaceTaximetro();
	}
	
	class BotaoComecarListener implements ActionListener{
		public void actionPerformed(ActionEvent ae){
			comecar = new Thread(new ThreadContador(), "Contando");
			comecar.start();
		}
	}
	
	class BotaoPararListener implements ActionListener{
		public void actionPerformed(ActionEvent ae){
			taxi.usando = false;
		}
	}
	
	class ThreadContador implements Runnable{
		public void run(){
			try{
				EventQueue.invokeLater(new Runnable(){
					public void run(){
						taxi.calcularUso();
						preco.setText("R$ " + taxi.valorTotal);
					}
				});
			} catch (Exception e){
				e.printStackTrace();
			}
		}		
	}
	
	public static void main(String[] args) {
		new TaxiInterface();
	}
}

O problema que acontece é que a minha interface simplesmente congela, não permitindo que o valor seja atualizado conforme deveria ser pelo método calcularUso().

Alguém sabe onde pode ser o problema, e também como seria a melhor maneira de criar animação utilizando eventos… Valeu

O que o EventQueue faz é justamente colocar o que está dentro daquele runnable para rodar na thread do Swing.
Portanto, não adianta nada você disparar uma thread secundária, se dentro dela você empilha um comando para que o cálculo inteiro seja realizado na thread do Swing. Isso vai travar a GUI do mesmo jeito.

Faça o cálculo na thread separada e use o EventQueue.invokeLater apenas para empilhar comandos que alterem o status das labels ou de outros componentes.

Provavelmente a correção será fazer:

 class ThreadContador implements Runnable{  
        public void run(){  
            try{  
                taxi.calcularUso(); //O método pesado fica fora da thread do Swing
                EventQueue.invokeLater(new Runnable(){  
                    public void run(){  
                        preco.setText("R$ " + taxi.valorTotal);  //E a atualização do label na thread do Swing.
                    }  
                });  
            } catch (Exception e){  
                e.printStackTrace();  
            }  
        }         
    }  

Tópico movido para o fórum de interface gráfica. Por favor, leia com atenção a descrição dos fóruns antes de postar.