Arquivo para a categoria 'Programação'

06
Ago
09

“Cannot connect to VM”

Uma coisa estranha aconteceu hoje, e por isto estou fazendo uma pausa na preguiça de escrever algo.

Eclipse IDE

Eclipse IDE

Durante um dia normal de pesquisa, em uma reunião onde tentávamos entender o código de um projeto open source, o Eclipse Ganymede que ele utilizava no Linux estava com um problema para executar o Debug. Toda vez que tentava executá-lo, aparecia um dialog informando:

“Cannot connect to VM”.

Estranhamos. Olhando nas configurações de JRE utilizadas, estava tudo ok, e o problema apresentava-se somente no Debug, e não na compilação/execução de programas. Apresentava também, na área “Problems”, um problema com um getthisbyname(). Estranhei. Não estaria resolvendo o nome de que, se ao testarmos só estava tentando rodar um “Hello World”? A única máquina que estaria tentando alcançar seria ela mesma: localhost. Resolvemos olhar o arquivo /etc/hosts (que guarda algumas pré-configurações de hosts em UNIX):

#127.0.0.1   localhost
127.0.0.1   xxx-notebook
#outras configurações de hosts

Para os desavisados, em arquivos de configuração UNIX é comumente utilizado o # como símbolo para comentário de linha. Logo, aparentemente devido ao fato de estar comentado, o Eclipse (ou a função getthisbyname() de Java) não conseguia resolver o nome localhost para 127.0.0.1. Removido o comentário, o Debug do Ganymede passou a funcionar perfeitamente.

Interessante, não?

30
Mai
09

Adicionando evento em botão – ActionScript 3.0

Só pra colocar um pouco do que tenho feito ultimamente para projeto da faculdade: amostra de como inserir um evento a um botão em ActionScript 3.0 – assumindo “botao_mc” como o nome de uma instância de um botão.

botao_mc.addEventListener(MouseEvent.CLICK,fnOI);
function fnOI(event:MouseEvent):void{
       trace("oi");
}

Adiciona-se um evento ao botão, e, ao ser clicado, será chamada a função cadastrada (fnOI) – seguindo o padrão de projeto Publisher-subscriber, se não me engano. Clicando na instância, será impresso na saída a palavra “oi”. Boa parte da interface de flash funciona com isso agora – você adiciona um evento, e as funções cadastradas serão chamadas no momento certo, para qualquer objeto possível.

Mais em breve! =p

03
Abr
09

Curso gratuito de Ruby para Twitter

Agora no Portal RubyLearning: curso gratuito utilização de Twitter com Ruby.

Tweet

Tweet

Topicos:

  • What’s Twitter?
    • Some Twitter concepts
    • A brief look at REST
    • Twitter API
  • What’s cURL?
    • Downloading and Installing cURL
    • Using cURL
    • cURL and the Twitter API
  • Parsing Twitter XML
    • What’s Hpricot?
    • Net::HTTP
    • Examples and Exercises
  • Using Ruby for Twitter
    • Examples and Exercises

Parece legal. Vou tentar fazer, mesmo sem saber quase nada de Ruby. =D

20
Mar
09

I’m a basher

heckert_gnusmallEstava fazendo um script para a pesquisa esta semana. O propósito dele deveria ser rodar e escolher números aleatórios, para matarmos processos. Ao terminar o programa, que funcionava muito bem no Mac OS X, ficou parecendo o seguinte:

#!/bin/sh

contador=0
MAXIMO=15

while [ $contador -lt $MAXIMO ]
do
  echo $[ $[ $RANDOM % 30 ] + 10 ]
  contador=$[ $contador + 1 ]
done

Lindo. Imprimia uma lista de números aleatórios entre 10 e 39. Tudo o que eu queria.

O problema veio na hora de passar este pequeno script para o Ubuntu e rodar os testes necessários. Ao invés de funcionar perfeitamente, ele declarava erros incompreensíveis para mim. Informava que havia variáveis não encontradas, operações não entendidas, etc. Este é o momento em que você para e pensa: “WTF”?

Rodei novamente no Mac. Lindo. Digitei linha por linha no próprio shell do Ubuntu. Funcionou! Mas ao tentar copiar o resultado deste esforço para um documento .sh, ele se tornava em vão. Veio a dúvida: será que este shell do linux do laboratório está quebrado?

Fui verificar onde estava localizado. Após executar um file /bin/sh no Ubuntu, tive como resposta algo esclarecedor: Symbolic link to `dash‘. Lembrei de imediato que o Ubuntu não usa o Bash por questões de desempenho, e este Dash – Debian Almquist Shell possui diversas incompatibilidades com o Bash, já que utiliza um conjunto de funcionalidades mais restrito e original ao padrão POSIX.

Resultado: para corrigir o problema, alterei a linha de shebang para #!/bin/bash. Quanto às incompatibilidades, corrigirei-as depois. =)

10
Mar
09

Labirinto em Haskell – tail recursion

Enquanto estava estudando a linguagem de programação Lua, em um capítulo sobre elementos funcionais da linguagem, me deparei com uma explicação interessante para tail recursion. Nela, o autor do livro (Programming in Lua, 1ª Edição) falava como a linguagem implementa completamente tail recursion(que acho que fica bem traduzido como recursão de cauda). Até aí tudo legal, mas melhora.

Bem, pra demonstrar que implementa e também explicar o conceito, o autor se utiliza de um jogo-exemplo: um labirinto. O jogo constrói o labirinto através de funções que chamam umas às outras, porém utilizando-se de recursão de cauda para manter sempre o uso de memória como se só houvesse uma função. Explicação e o exemplo utilizado podem ser encontrados aqui.

Explicando melhor recursão de cauda: o princípio é que não precisamos que uma função fique esperando o retorno de um resultado de outra para terminar sua execução, como acontece normalmente. Se você faz uma função em C, ou um método em Java, que termina com um comando return outraFuncao;, a função original ficaria esperando o termino da chamada para poder terminar sua execução. Só que outraFuncao pode fazer chamadas a outras funções, e essas a mais outras, e assim por diante. Tal carga será deixada para a memória, que acabará por estourar(um stack overflow, ou estouro de pilha). Mas perceba que, no caso de uma instrução final de uma função, não há motivo para a espera de retorno da chamada. Pode-se simplesmente indicar que o retorno será o da função agora chamada, e limpar a memória utilizada pela execução da original. É isto que linguagens funcionais como Haskell e Scheme e linguagens com fortes influências, como Lua, implementam.

A novidade que gostaria de compartilhar aqui é uma implementação do mesmo código feito em Lua, para Haskell. O código pode dar origem a um jogo bastante complexo e infinitamente escalável, já que ao chamar uma nova função (entrar em um novo quarto) nenhuma informação é mantida da que chama, e sua execução é encerrada por completo. Código em Haskell abaixo:

import IO

main = do
         room1

room1 = do
          putStrLn "You're in room #1"
          text <- getLine
          if text=="south" then
            room3 -- movendo-se pro quarto 3
            else
              if text=="east" then
                room2 --movendo-se pro quarto 2
                else
                  putStrLn "Invalid move" >>
                  room1 --permanece no mesmo quarto

room2 = do
          putStrLn "You're in room #2"
          text <- getLine
          if text=="south" then
            room4
            else
              if text=="west" then
                room1
                else
                  putStrLn "Invalid move" >>
                  room2 

room3 = do
          putStrLn "You're in room #3"
          text <- getLine
          if text=="north" then
            room1
            else
              if text=="east" then
                room4
                else
                  putStrLn "Invalid move" >>
                  room3 

room4 = do
          putStrLn "You're in room #4! You won!"

O código é simples, elegante, e correto. É este mesmo comportamento que torna a recursão um ponto tão forte em Haskell: iteração não é necessária à linguagem pois recursividade não apresenta peso adicional algum ao código. Isto nos permite escrever funções recursivas muito mais poderosas do que podemos encontrar em uma linguagem como C ou Java, onde a pilha de execução não suporta tantas chamadas quanto uma tarefa mais complexa possa precisar(ex.: inserção em uma árvore AVL com 100 mil nós). Isso nos permite executar códigos como o clássico exemplo do fatorial:

fact x = if x < 0 then error"Fatoriais sao de numeros positivos!"
                       else fact2 x 1 where
                              fact2 0 acumulador = acumulador
                              fact2 x acumulador = fact2 (x-1) (acumulador*x)

Pode-se rodar este exemplo e calcular o fatorial de 100 mil, o que não é possível com recursão em C. Apesar do peso do alto nível de abstração, vemos aí parte do poder do paradigma funcional e da linguagem Haskell!

PS: Erro corrigido no quanto à recursividade do fatorial. Ah, e o exemplo do fatorial pode não dar Stack Overflow, mas dependendo da entrada você pode atingir picos de uso de CPU. =)

04
Jan
09

Movendo uma imagem usando Haskell e wxHaskell

Há pouco mais de um ano, quando eu estava cursando a cadeira de Linguagens de Programação Funcionais, tive o prazer de começar a utilizar interfaces gráficas em Haskell, linguagem utilizada pela disciplina. Dentre os vários toolkits gráficos disponíveis, o que nos foi apresentado foi o wxHaskell, na verdade um binding para o kit gráfico multi-plataforma/linguagem wxWidgets.

Tivemos vários problemas com o desenvolvimento:

  • o desenvolvimento gráfico para esse binding era exclusivamente textual, logo não há a possibilidade de modelar visualmente(pelo menos que nós conhecêssemos);
  • nossos prazos eram curtos, dado que a parte gráfica só foi nos ensinada no final da disciplina;
  • boa parte do que tentávamos fazer levava um bom tempo para ser estudado e descoberto como ser feito;
  • nossa equipe tinha poucas possibilidades de reunião, se resumindo a através de chat, geralmente;

Mas isso não é o foco deste post. No final das contas, o projeto foi feito.

wxHaskell

wxHaskell


Enquanto produzia, para prototipar o que eu poderia usar do toolkit, comecei a fazer brincadeiras. Uma delas seria fazer algo que poderia se tornar um jogo: movimentar uma imagem na tela. A imagem poderia ser um personagem, em um hipotético jogo. =)

Alguns passos fazem-se necessários. É necessário o GHC instalado, e o a biblioteca wxHaskell. Utilizei-nos no Windows, e tive inclusive que utilizar uma versão desatualizada do GHC para tornar possível a execução. Nunca mais o executei, e futuramente posso colocar uma descrição detalhada de como instalar tudo necessário. =)

Como foi feito? Explicando em alguns passos:
1) Importação dos módulos necessários:

import Graphics.UI.Wx
import Graphics.UI.Wxcore

2) Define-se um jogador, o qual encapsula a imagem a ser impressa e uma posição(um ponto na tela):

data Player = Player FilePath Point String

O tipo FilePath é um apelido para o tipo String, não se diferencia em nada de um pedaço de texto, representando um caminho nos arquivos para algo, que no nosso caso será a imagem. Point é um TAD que encapsula dois números – Integers, se não me engano – e faz parte da biblioteca do wx mesmo. A String final é apenas uma representação do nome do jogador. =)
3) Define-se a função principal, a que executará o programa através da interface gráfica. Aqui a chamaremos de gui:

gui = do

esta função é um Monad, ou seja, ela encapsula comportamento imperativo no paradigma funcional da linguagem. A partir da diretiva do o comportamento será similar a código imperativo, onde as chamadas a funções estarão separadas por quebras de linhas, de maneira ordenada. Claro, permanece a necessidade de organização de código através de indentação. Prosseguindo:

gui = do
	jog <- varCreate (Player "testFace.gif" (Point 0 0) "joao")
	j <- frameFixed [
		clientSize := Size 300 200,
		text := "teste jogo",
		picture :=	"face.ico",
		on paint := (\dc rect -> do
			x <- varGet jog
			printPlayer x dc
			return ()
			)
	]

Temos no código acima a criação de uma variável, jog, a qual representará um jogador(o tipo abstrato Player, mostrado acima). Passamos na criação a String “testFace.gif”, que é o nome do arquivo que coloquei na mesma pasta que o programa. O ponto passado como ponto inicial foi (Point 0 0), o ponto mínimo de exibição.

testeFace.gif!

testeFace.gif!


Na linha seguinte, definimos j, o qual será um Frame de tamanho fixo, com o uso da função frameFixed, onde passamos a lista de argumentos. Widgets em wxHaskell seguem geralmente esta forma, uma função relacionada que recebe uma lista de argumentos, onde outros podem ser configurados posteriormente. No caso, definimos o tamanho utilizável da janela em clientSize(com o TAD Size, que funciona recebendo dimensões de largura e altura), o texto da barra da janela em text, o ícone da janela em picture, a função que será chamada no momento da “pintura” do widget na tela, em on paint. A função, que declaramos on the fly através de uma expressão lambda, recebe um contexto de dispositivo(dc – device context), que neste caso é a janela, e um retângulo(rect), que especifica as coordenadas da área de visualização. Passaremos o dc como segundo argumento para a função de impressão, printPlayer. O primeiro argumento que passamos é o Player da variável jog, através da constante x, inicializada em:

x <- varGet jog 

A função printPlayer pode ser descrita no código como:

printPlayer :: Player->DC a->IO ()
printPlayer (Player a b c) dc = do
	im <- bitmapCreateFromFile a
	drawBitmap dc im b True []

ou seja, recebe o Player e o Device Context, e utiliza a função de criação de bitmap a partir de um caminho, bitmapCreateFromFile, e a função de desenho de bitmaps, drawBitmap, ambas últimas da própria API de WxHaskell. Temos a criação do bitmap im, que é impresso no dispositivo dc, nas cordenadas indicadas pelo ponto b, com o modo de transparência especificado(True). A lista vazia que está como último argumento são as propriedades, as quais não cheguei a utilizar(e descobrir utilidade).
Continuando no código da função gui, após a criação do FrameFixed j, configuramos alguns eventos para ele. Acredito que seja um padrão de codificação configurar os eventos fora da lista principal de atributos. Escolhi só deixar o on paint por ter caráter intrínsico ao frame, diferente dos que criaremos agora:

	set j [
		on downKey := (do
			varUpdate jog desce
			repaint j
			return ();
			),
		on upKey := (do
			varUpdate jog sobe
			repaint j
			return ();
			),
		on rightKey := (do
			varUpdate jog direita
			repaint j
			return ();
			),
		on leftKey := (do
			varUpdate jog esquerda
			repaint j
			return ();
			)
		]

os eventos configurados acima servem para movimentar a imagem a partir das setas do teclado. WxHaskell já utiliza eventos para as 4 teclas direcionais, listadas acima(ex: on rightKey, onde rightKey é o evento de apertar a seta para a direita). O que acontece a cada evento: é chamada a função varUpdate, da própria API de WxHaskell, a qual é uma função polimórfica. Se não me engano, sua assinatura é a seguinte:

varUpdate::a->(a->a)->IO ()

ou seja, recebe um argumento do tipo a, e uma função que também recebe um argumento deste tipo e retorna outro do tipo a, e finalmente retorna um IO (). Após a chamada de varUpdate, temos a chamada da função repaint, tomando como argumento o frameFixed j. O que esta função faz é disparar o evento de pintura(paint) do argumento, já descrito acima.
Mas o que as funções passadas como argumento para varUpdate – esquerda, direita, sobe e desce – fazem? Vejamos uma delas:

sobe :: Player->Player
sobe (Player a (Point x y) c) = if y==0 then (Player a (Point x y) c)
				else Player a (Point x (y-k)) c

sobe recebe um argumento do tipo Player e retorna o mesmo tipo. A lógica desta função consiste em checar se a posição do jogador já atingiu o topo da janela(quando y é igual a 0), e caso contrário retornar um Player com o valor de y reduzido em k, onde k é uma constante de movimentação, indicando quantos pixels serão saltados. O espaço percorrido por unidade de tempo – ou seja, por disparamento do evento – definirá a velocidade do personagem, sendo seus valores diretamente proporcionais. No meu caso, utilizei:

k::Int --Constante de movimentação
k = 10

As outras funções seguem lógica idêntica, sendo somente necessário checar por colisão do Player com as bordas de j, por isso não as colocarei por extenso aqui. Portanto, a partir de cada evento configurado (o pressionar das setas direcionais) temos uma atualização configurada para a variável jog, e portanto a imagem se comportará da maneira apropriada. Poderíamos brincar um pouco com isso também, fazendo alterações de imagens a partir de determinadas situações, que poderiam ser cláusulas if-then-else nas funções de atualização. Basta usar a criatividade.
Após isso, basta compilar o código e voilá!, você tem uma imagem se movimentando pela sua tela. =)

Comentários de aperfeiçoamentos e hacks a partir disto são bem-vindos! Breve, quem sabe, coloco aqui algo com GTK2Haskell!

20
Dez
08

Coisas divertidas em Python (2) – tocando sons

Como prometido aqui, colocando algo que eu estava vendo há algumas semanas atrás, bem interessante e, por enquanto, fácil de mexer: Manipulação de sons com Pygame.

Pygame

Pygame

Uma explicação antes: Pygame é uma biblioteca para produção de jogos em Python. Oferece suporte a sons, gráficos 2D e 3D, entre várias coisas necessárias à produção de jogos. Aqui eu estou mostrando só como utilizá-la para tocar e manipular sons.

Para começar, é necessário importar o módulo pygame e inicializá-lo.

import pygame
pygame.init()

Manipulação mais simples: usa-se a classe Sound.

from pygame.mixer import Sound
audio = pygame.mixer.Sound(caminhoArquivo)

onde caminhoArquivo é uma String contendo o caminho relativo até o arquivo de som, ou o caminho absoluto no sistema. Pygame por padrão suporta extensões .wav e .ogg, ao menos na versão testada(Linux). Chega a ser estupidamente fácil a maneira como você manda tocá-lo:

audio.play()

onde o método play também pode receber um argumento da quantidade de vezes que toca novamente, e outro do tempo destinado a tocar. No caso maior, a interface dele fica algo como play(numeroDeRepetições,duração). Pode-se fazer um som tocar uma quantidade infinita de vezes passando o argumento como -1.
Vários canais de som também estão disponíveis, e você pode tocar vários sons simultaneamente. Por exemplo:

musica = Sound(musica1)
som = Sound(som1)
v = True

musica.play(-1)
while(True):
    if v:
        som.play()
    v = not v

O exemplo é meio absurdo, já que eternamente ocorreria o laço e não haveria pausa alguma. Porém a idéia principal é que toda vez que v for verdadeiro, será tocado o som. Enquanto tudo acontece, a musica continuará tocando normalmente.

Manipulação aprimorada: usaremos agora o tipo sndarray.

import pygame.mixer.sndarray
from pygame.mixer.sndarray import *

arraySom = array(musica)

Agora você tem um array contendo todas as amostras de byte do som. Isso é um array BEM grande. Por exemplo, se o som tiver uma taxa de amostragem de 11000Hz, temos 11000 amostras por segundo. Logo, o tamanho do array é de 11000 * tamanho do som em segundos. Você pode testar isso manipulando este array, como no exemplo abaixo:

novoArray = arraySom[0:33000]

Considerando que temos um som com amostragem de 11000Hz, temos agora um novoArray com o equivalente a 3 segundos de amostragem(≈1/11000 segundo). Para tocar, podemos converter de volta para Sound.

novoSom = sndarray.make_sound(novoArray)
novoSom.play()

Pronto, agora você tocará aproximadamente 3 segundos do objeto musica original, do tipo Sound, uma representação do arquivo de som original passado como argumento.

Canais de reprodução
Há também maneiras para controlar os canais que são utilizados. O método play da classe Sound retorna um objeto de tipo Channel. Com ele, você pode controlar algumas coisas como volume de audio, inclusive para cada saída de som. Como funciona: a classe Channel possui um método setVolume, o qual recebe uma tupla numérica, onde os argumentos vão de 0 a 1(argumentos maiores que 1 funcionam como 1, até onde testei).

volume = 0.3, 0.7
canal = musica.play()
canal.setVolume(volume)

Você pode ouvir agora a saída da esquerda com som menor que a da direita, e nenhuma das duas com o volume máximo.
Canais de reprodução são alocados automaticamente pelo sistema, e possuem um numero limitado. Você pode aumentar a quantidade de canais, usando-se do método set…, e alocar explicitamente o canal que você deseja para o toque do som, utilizando-se do seguinte formato:

valor_desejado = 10
pygame.mixer.set_num_channels(valor_desejado) #você tem agora 10 canais disponíveis.

pygame.mixer.set_reserved(1) #você reservou um canal. Agora pygame não alocará automaticamente nada no canal 0.
canal = pygame.mixer.Channel(0) #atribuiu seu canal reservado à variável canal

canal.play(musica) #tocará o som musica no canal reservado.

Com tudo isso você pode editar seus sons, fazê-los tocar da maneira que deseja, simular sons vindos de diferentes posições(Stereo Panning, brincando com os volumes das caixas), ou seja, tem um arsenal pra manipulações sonoras bastante potente. Tudo graças a uma biblioteca de jogos. =)

Boa parte desse código foi testado em uma instalação do pygame, usando de Python versão 2.6. Talvez não haja disponível versão para a nova versão 3.0. Talvez haja algum erro, mas prometo revisar isso depois. =)

06
Dez
08

Novo livro sobre Haskell

Capa do livro Real World Haskell

Real World Haskell

Há um novo livro disponível sobre Haskell: a O’Reilly acabou de lançar, em novembro, o livro Real World Haskell. Para melhorar, o conteúdo está disponível livremente para leitura!

Até onde olhei (pouco mais do que o índice) parece um livro bom. Em geral acho os livros da O’Reilly muito bons, e tenho alguns deles. Este, como o título indica, tem um aspecto bastante prático, e é interessante como lida com vários pontos da linguagem comumente não vistos ao se explicar o paradigma: programação para banco de dados, redes, GUIs, paralelismo e concorrência(algo que aparentemente está em alta para programação funcional atualmente).

No mais, parece bem interessante para ser lido para iniciantes ou para quem deseje melhorar seus conhecimentos práticos sobre Haskell. Mais um livro para o recesso Dezembro – Janeiro!

Página do livro: http://book.realworldhaskell.org/
Encontrado na página inicial de Haskell.

08
Out
08

Coisas divertidas(?) em Python

Python powered

Python powered


Algumas coisas divertidas de se fazer em Python:

  • Abrir uma página web em um browser
    Para se fazer isso, pode ser usado, diretamente da biblioteca padrão, o módulo webbrowser:

    import webbrowser
    
    webbrowser.open("http://frsoares.wordpress.com")
    

    O módulo suporta vários browsers no Unix e no Windows utiliza o padrão.

  • Listar um diretório e mudar um diretório, entre outros
    O módulo os oferece dezenas de funções para manipular o sistema operacional, de maneira independente de sistema.

    import os
    
    os.listdir(".") #lista o diretorio atual
    
    os.chdir("..") #muda de diretório para o abaixo na árvore do sistema
    
    #entre outros
    
  • Serializar objetos com o cPickle
    Qualquer coisa em Python pode ser transformada para texto ou mandada de volta usando o módulo pickle ou cPickle. Ambos são equivalentes.

    import cPickle
    
    dic = {'oi':12, 'tchau':13}
    arq = open('arquivo.txt','w')
    
    #insere-se itens
    cPickle.dump(dic,arq)
    cPickle.dump('algo',arq)
    arq.close()
    
    #recupera-se itens
    arq2 = open('arquivo.txt','r')
    print cPickle.load(arq2)
    print cPickle.load(arq2)
    arq2.close()

updates a serem adicionados (quando eu lembrar de algo)….

03
Mai
08

Um aplicativo trivial em Java

Com meu tempo atribulado, hoje tive uma iluminação:

Preciso de algo para gerenciar melhor meu tempo durante o dia… já sei, vou fazer um temporizador!

Isso, e pelo fato da água da chaleira ferver demais e eu ter que re-enxê-la para fazer café. Muito chato isso – mesmo. Fui até o Eclipse, e comecei a digitar.

Quero algo em formato de pop-ups, que aparecem na tela e me diga: “Ei, hora disso.”

Pop-ups.. hum… Poderiam ser Dialogs? Surgiu uma idéia simples:

Começando com uma classe simples, chamemo-a Main.

public class Main{
}

Para podermos chamar fácil Dialogs de opções a partir dela, podemos acrescentar algo: herdando de JFrame, fica fácil de usá-la como componente pai de um Dialog de JOptionPane. Começamos a fazer sua classe principal também:

public class Main extends JFrame{
    public static void main(String[] args){
       Main m = new Main();
       m.setVisible(false);
   }
}

Ok, agora já temos um JFrame invisível. A partir deles vamos abrir pop-ups. Podemos ter um para saber quantos minutos você quer esperar, e outro para saber que mensagem ele deve retornar para lhe lembrar do que era para ser feito. Finalmente teremos um que indicará que passou o tempo.

public class Main extends JFrame{
   public static void main(String[] args){
      Main m = new Main();
      m.setVisible(false);

      String tempo = JOptionPane.showInputDialog(m,"Digite o tempo de espera");
      if(tempo==null){
      //caso da janela ser cancelada ou fechada.
        System.exit(0);
      }

      tempo=tempo.trim();
      int minutos = Integer.parseInt(tempo);

      String mensagem = JOptionPane.showInputDialog(m,
                                     "Digite a mensagem de alerta!");

      Thread.sleep(minutos*60*1000);

      JOptionPane.showMessageDialog(m,mensagem);
      m.dispose();
      System.exit(0);
      }
   }
}

O programa todo é mais ou menos isso. Na chamada de Thread.sleep, a multiplicação é feita para passar de minutos para milissegundos, medida de tempo que ele usa. Claro, algumas exceções devem ser verificadas: NumberFormatException e InterruptedException, para o parseInt e o sleep, respectivamente. Podemos florear também o retorno um pouco. O código final fica assim:

public class Main extends JFrame{
  public static void main(String[] args){
    Main m = new Main();
    m.setVisible(false);

    try{
      String tempo = JOptionPane.showInputDialog(m,"Digite o tempo de espera");
      if(tempo==null){
      //caso da janela ser cancelada ou fechada.
        System.exit(0);
      }

      tempo=tempo.trim();
      int minutos = Integer.parseInt(tempo);

      String mensagem = JOptionPane.showInputDialog(m,
                                      "Digite a mensagem de alerta!");

      Thread.sleep(minutos*60*1000);

      JOptionPane.showMessageDialog(m,mensagem,"Passados "+tempo+" minutos!!!",
                        JOptionPane.WARNING_MESSAGE);
      } catch(NumberFormatException e){
         JOptionPane.showMessageDialog(m, "Use somente "+
                 " números inteiros para o tempo!!!");
      } catch(InterruptedException e){
         JOptionPane.showMessageDialog(m, e.getMessage());
      } finally{
         m.dispose();
         System.exit(0);
      }
    }
  }
}

Quanto à dependências dos pacotes, só precisa do JFrame e do JOptionPane – nada que um Ctrl+Shift+O não resolva.

Isso, em uma classe só, é um aplicativo trivial e funcional o suficiente para eu ter me viciado nele. Já virei escravo dele para tudo que preciso. E não me preocupo mais que a água da chaleira evapore toda.

Entrada do tempo do temporizadorEntrada de mensagemRetorno do temporizador




X-Files

 

Novembro 2009
S T Q Q S S D
« Out    
 1
2345678
9101112131415
16171819202122
23242526272829
30  

Estatísticas:

  • 3,558 erros de pesquisa

Tweet! :>

last.fm

Join the Free Software Foundation!

Support freedom