41bb726c

Dia 12

Dirigir eventos simples e interatividade

Laura Lemay


CONTEÚDOS

Os eventos de Java são parte de Java awt (Caixa de ferramentas de Windowing Abstrata) pacote. Um evento é o modo que o awt se comunica para você, como o programador, e a outro Java awt componentes que algo aconteceu. Que algo possa introduzir-se do usuário (movimentos de rato ou cliques, keypresses), modificações no ambiente de sistema (uma abertura de janela ou encerramento, a janela que se enrola acima ou abaixo), ou um anfitrião de outras coisas que, de algum modo, poderiam afetar a operação do programa.

Em outras palavras, sempre que quase algo aconteça a Java awt o componente, inclusive um applet, um evento gera-se. Alguns eventos tratam-se pelo awt ou pelo ambiente que o seu applet dirige em (o browser) sem você precisando de fazer algo. os métodos de paint(), por exemplo, geram-se e tratam-se pelo ambiente - tudo que tem de fazer é dizem o awt o que quer pintado quando vem à sua parte da janela. Contudo, precisaria de saber sobre alguns eventos, como um clique de rato dentro dos limites do seu applet. Escrevendo os seus programas Java tratar estas espécies de eventos, pode introduzir-se do usuário e ter a sua modificação de applet o seu comportamento baseado naquela entrada.

Hoje aprenderá sobre a direção de eventos simples, inclusive os seguintes fundamentos:

Também aprenderá sobre o método de handleEvent(), que é a base de reunião, manejo e transmissão dos eventos de todas as espécies do seu applet a outros componentes da janela ou do seu próprio applet. Amanhã aprenderá como combinar eventos com outros componentes awt para criar uma interface completa do seu applet.

Cliques de rato

Vamos começar com o evento mais comum no qual poderia interessar-se: cliques de rato. Os eventos de clique do rato ocorrem quando o seu usuário clica no rato em algum lugar no corpo do seu applet. Pode interceptar cliques de rato para fazer coisas por exemplo muito simples, ao pino de madeira o som em e de no seu applet, mover-se para o seguinte escorregão em uma apresentação ou compensar a tela e partida sobreou pode usar cliques de rato em conjunto com movimentos de rato para executar movimentos mais complexos dentro do seu applet.

Rato abaixo e rato eventos

Quando clica no rato uma vez, o awt gera dois eventos: um rato abaixo evento quando o botão de rato se aperta e um rato evento quando o botão se lança. Porque dois eventos individuais de uma ação de rato única? Como pode querer fazer coisas diferentes para "o abaixo" e "o". Por exemplo, olhe para um menu descendente. O rato abaixo estende o cardápio, e o rato seleciona um item (com arrastos de rato entre - mas aprenderá sobre aquele um depois). Se tiver só um evento de ambas as ações (rato e rato abaixo), não pode implementar aquele tipo da interação de usuário.

O manejo de eventos de rato no seu applet é fácil - tudo que tem de fazer é ignoram a definição de método direita no seu applet. Aquele método vai se chamar quando aquele determinado evento ocorrer. Aqui está um exemplo da assinatura de método de um rato abaixo evento:

public boolean mouseDown(Event evt, int x, int y) {
...
}

O método de mouseDown() (e o método de mouseUp() também) tomam três parâmetros: o próprio evento e o x e y coordenam onde o rato abaixo ou o rato evento ocorreram.

O argumento de evt é um exemplo da classe Event. Todos os eventos de sistema geram um exemplo da classe de Event, que contém a informação sobre onde e quando o evento se realizou, a espécie do evento é, e outra informação que poderia querer saber sobre este evento. Às vezes tendo uma maçaneta a que o objeto de Event é útil, como descobrirá depois nesta seção.

O x e as coordenadas y do evento, como passado em pelo x e argumentos de y ao método de mouseDown(), são especialmente bonitos saber porque pode usá-los para determinar precisamente onde o clique de rato se realizou. Deste modo, por exemplo, se o rato abaixo o evento foi sobre um botão gráfico, pode ativar aquele botão.

Por exemplo, aqui está um método simples que imprime a informação sobre um rato abaixo quando ocorre:

public boolean mouseDown(Event evt, int x, int y) {
    System.out.println("Mouse down at " + x + "," + y);
    return true;

Pela inclusão deste método no seu applet, cada vez quando o seu usuário clica no rato dentro do seu applet, esta mensagem vai se imprimir. As chamadas de sistema awt cada um destes métodos quando o evento real se realiza.

Observar
Diferentemente de com aplicações de Java, onde produções de System.out.println() à tela, a produção que aparece em applets varia de sistema ao sistema e browser ao browser. O Netscape tem uma janela especial chamada o consolo de Java que deve ser visível para você para ver a produção. O Internet Explorer registra em log a produção de Java a um arquivo separado. Confira com o seu ambiente para ver onde a produção de Java de applets se envia.

Observe que este método, diferentemente de outros métodos de sistema estudou isto longe, devolve um valor booleano em vez de não devolver nada (void). Isto ficará importante amanhã quando criar interfaces de usuário e logo dirigir a entrada a estas interfaces; ter um método de manipulador de eventos devolve true ou false determina se um componente dado pode interceptar um evento ou se tem de transmiti-lo ao componente de cerrado. A regra geral consiste em que se o seu método interceptar e fizer algo com o evento, deve devolver true. Se por alguma razão o método não fizer nada com aquele evento, deve devolver false para que outros componentes no sistema possam ter uma possibilidade de ver aquele evento. Na maioria dos exemplos na lição de hoje, estará interceptando eventos simples, portanto a maioria dos métodos aqui devolverão true. Amanhã aprenderá sobre componentes de aninhamento e eventos passantes a hierarquia componente.

A segunda metade do clique de rato é o método de mouseUp(), que se chama quando o botão de rato se lança. Para tratar um rato evento, acrescente o método de mouseUp() ao seu applet: mouseUp() olha como mouseDown():

public boolean mouseUp(Event evt, int x, int y) {
    ....
}

Um exemplo: lugares

Nesta seção criará um exemplo de um applet que usa o rato dos eventos de rato abaixo eventos especialmente. Os Lugares applet começam com uma tela em branco e logo sentam-se e esperam. Quando clica no rato naquela tela, um ponto azul desenha-se. Pode colocar até 10 pontos na tela. A figura 12.1 mostra os Lugares applet.

A figura 12.1: Os Lugares applet.

Vamos começar do começo e construir este applet, que começa da definição de classe inicial:

import java.awt.Graphics;
import java.awt.Color;
import java.awt.Event;

public class Spots extends java.applet.Applet {

    final int MAXSPOTS = 10;
    int xspots[] = new int[MAXSPOTS];
    int yspots[] = new int[MAXSPOTS];
    int currspots = 0;

}

Esta classe usa três outras classes awt: Graphics, Color e Event. Aquela classe última, Event, tem de importar-se em qualquer applets aquele uso eventos. A classe tem quatro variáveis de exemplo: uma constante para determinar o número máximo de lugares que podem desenhar-se, duas tabelas para guardar o x e coordenadas y dos lugares que já se desenharam, e um número inteiro para guardar a pista do número do lugar atual.

Observar
Esta classe não inclui as palavras de implements Runnable na sua definição. Como verá depois como constrói este applet, também não tem um método de run(). Porque não? Como não faz de fato nada no seu próprio - tudo que faz é esperam pela entrada e logo enchem quando introduzido acontece. Não há necessidade de fios se o seu applet não estiver fazendo ativamente algo todo o tempo.

Vamos começar acrescentando o método de init(), que faz só uma coisa: escolha a cor de fundo a white:

public void init() {
    setBackground(Color.white);
}

Estabelecemos o contexto aqui em init() em vez de em paint() como tem em exemplos passados porque tem de estabelecer o contexto só uma vez. Como paint() se chama repetidamente cada vez quando um novo lugar acrescenta-se, estabelecer o contexto no método de paint() desnecessariamente diminui aquele método. A colocação dele aqui está uma ideia muito melhor.

A ação principal deste applet ocorre com o método de mouseDown(), então vamos acrescentar que um agora:

public boolean mouseDown(Event evt, int x, int y) {
    if (currspots < MAXSPOTS) {
        addspot(x,y);
        return true;
    }
    else {
       System.out.println("Too many spots.");
       return false;
    }
}

Quando o clique de rato ocorre, os testes de método de mouseDown() para ver se há menos de 10 lugares. Nesse caso chama o método de addspot() (que escreverá logo) e devolve true (o rato abaixo o evento interceptou-se e tratou-se). Se não, somente imprime uma mensagem de erro e devolve false.

O que addspot() faz? Acrescenta as coordenadas do lugar às tabelas que guardam as coordenadas, incrementa a variável de currspots, e logo chama repaint():

void addspot(int x, int y) {
    xspots[currspots] = x;
    yspots[currspots] = y;
    currspots++;
    repaint();
}

Pode estar admirando-se porque tem de guardar a pista de todos os lugares passados além do lugar atual. É por causa de repaint(): Cada vez quando pinta a tela, tem de pintar todos os velhos lugares além do lugar mais novo. De outra maneira, cada vez quando pintou um novo lugar, os mais velhos lugares iriam se apagar. Agora, no método de paint():

public void paint(Graphics g) {
    g.setColor(Color.blue);
    for (int i = 0; i < currspots; i++) {
        g.fillOval(xspots[i] -10, yspots[i] - 10, 20, 20);
    }
}

Dentro de paint(), somente faz um laço pelos lugares que guardou no xspots e tabelas de yspots, pintando cada um (de fato, pintando-os um pouco à direita e para cima para que o lugar se pinte em volta do ponteiro de rato em vez de abaixo e à direita).

É isso! Isto é tudo que tem de criar um applet que trata cliques de rato. Todo o resto trata-se para você. Tem de acrescentar o comportamento apropriado a mouseDown() ou mouseUp() para interceptar e tratar aquele evento. A listagem 12.1 mostra o texto cheio dos Lugares applet.


A listagem 12.1. Os Lugares applet.
 1: import java.awt.Graphics;
 2: import java.awt.Color;
 3: import java.awt.Event;
 4:
 5: public class Spots extends java.applet.Applet {
 6:
 7:     final int MAXSPOTS = 10;
 8:     int xspots[] = new int[MAXSPOTS];
 9:     int yspots[] = new int[MAXSPOTS];
10:     int currspots = 0;
11:
12:     public void init() {
13:         setBackground(Color.white);
14:     }
15:
16:     public boolean mouseDown(Event evt, int x, int y) {
17:         if (currspots < MAXSPOTS) {
18:             addspot(x,y);
19:             return true;
20:         }
21:         else {
22:            System.out.println("Too many spots.");
23:            return false;
24:         }
25:     }
26:
27:     void addspot(int x,int y) {
28:          xspots[currspots] = x;
29:          yspots[currspots] = y;
30:          currspots++;
31:          repaint();
32:     }
33:
34:     public void paint(Graphics g) {
35:         g.setColor(Color.blue);
36:         for (int i = 0; i < currspots; i++) {
37:               g.fillOval(xspots[i] - 10, yspots[i] - 10, 20, 20);
38:        }
39:     }
40: }

Clica duas vezes

E se o evento de rato em que se interessa for mais que um clique de rato único - e se quiser seguir a pista duplo - ou cliques triplos? Java classe de Event fornece uma variável para seguir a pista desta informação, chamada clickCount. clickCount é um número inteiro que representa o número de cliques de rato consecutivos que ocorreram (onde "consecutivo" determina-se normalmente pelo sistema operacional ou o hardware de rato). Se se interessar em múltiplos cliques de rato no seu applets, pode testar este valor no corpo do seu método de mouseDown(), como isto:

public boolean mouseDown(Event evt, int x, int y) {
    switch (evt.clickCount) {
      case 1:  // single-click
      case 2:  // double-click
      case 3:  // triple-click
      ....
    }
}

Movimentos de rato

Cada vez quando o rato move-se um pixel único em qualquer direção, um evento de movimento de rato gera-se. Há dois eventos de movimento de rato: os arrastos de rato, onde o movimento ocorre com o botão de rato movimentos de rato premidos, e claros, onde o botão de rato não se aperta.

Para dirigir eventos de movimento de rato, use métodos de mouseMove() e o mouseDrag().

Arrasto de rato e eventos de movimento de rato

O mouseDrag() e métodos de mouseMove(), quando incluído no seu código de applet, intercepção e eventos de movimento de rato de maçaneta. O movimento de rato e os eventos de arrasto de movimento geram-se para cada modificação de pixel os movimentos de rato, portanto um movimento de rato de um lado do applet ao outro pode gerar centenas de eventos. O método de mouseMove(), para movimentos de ponteiro de rato claros sem o botão de rato apertado, parece muito os métodos de clique do rato:

public boolean mouseMove(Event evt, int x, int y) {
    ...
}

O método de mouseDrag() trata movimentos de rato feitos com o botão de rato premido (um movimento de arrasto completo compõe-se de um rato abaixo o evento, uma série de eventos de arrasto de rato de cada pixel o rato move-se, e um rato quando o botão se lança). O método de mouseDrag() parece a isto:

public boolean mouseDrag(Event evt, int x, int y) {
    ...
}

Observe que tanto para o mouseMove() como para métodos de mouseDrag(), os argumentos pelo x e coordenadas de y são a nova posição do rato, não a sua posição inicial.

Rato entra e eventos de saída de rato

Finalmente, há mouseEnter() e os métodos de mouseExit(). Estes dois métodos chamam-se quando o ponteiro de rato entra ou sai um applet ou uma porção disto applet. (Em caso de que se está admirando porque precisaria de saber isto, é mais útil em componentes awt que poderia pôr dentro de um applet. Aprenderá mais sobre o awt amanhã.)

Tanto mouseEnter() como mouseExit() têm assinaturas semelhantes aos métodos de clique de rato três argumentos: o objeto de evento e o x e as coordenadas y do ponto onde o rato entrou ou saiu o applet. Estes exemplos mostram as assinaturas de mouseEnter() e mouseExit():

public boolean mouseEnter(Event evt, int x, int y) {
    ...
}

public boolean mouseExit(Event evt, int x, int y) {
    ...
}

Um exemplo: desenho de linhas

Os exemplos sempre ajudam a fazer conceitos mais concretos. Nesta seção criará um applet que lhe permite desenhar linhas diretas na tela arrastando-se do startpoint ao endpoint. A figura 12.2 mostra o applet no trabalho.

A figura 12.2: Desenho de linhas.

Como com os Lugares applet (no qual este applet se baseia), vamos começar com a definição básica e trabalho o nosso caminho por ele, acrescentando os métodos apropriados para construir o applet. Aqui está uma definição de classe simples das Linhas applet, com um número de variáveis de exemplo iniciais e um método de init() simples:

import java.awt.Graphics;
import java.awt.Color;
import java.awt.Event;
import java.awt.Point;

public class Lines extends java.applet.Applet {

    final int MAXLINES = 10;
    Point starts[] = new Point[MAXLINES]; // starting points
    Point ends[] = new Point[MAXLINES];    // ending points
    Point anchor;    // start of current line
    Point currentpoint; // current end of line
    int currline = 0; // number of lines

    public void init() {
        setBackground(Color.white);
    }
}

Este applet acrescenta muitas outras coisas do que Lugares. Diferentemente de Lugares, que guarda a pista de coordenadas de número inteiro individuais, este guarda a pista de objetos de Point. Os pontos representam um x e uma coordenada de y, encapsulada em um objeto único. Para tratar com pontos, importa a classe de Point e funda um ramo de variáveis de exemplo que mantêm pontos:

Finalmente, o método de init(), como nos Lugares applet, estabelece o contexto do applet a white.

Três eventos principais este applet os negócios são mouseDown(), para fazer que o ponto da âncora da linha atual, mouseDrag(), anime a linha atual como se está desenhando, e mouseUp(), para estabelecer o ponto que termina da nova linha. Considerando que tem variáveis de exemplo para manter cada um destes valores, é simplesmente uma matéria de tapar as variáveis direitas nos métodos direitos. Aqui está mouseDown(), que estabelece o ponto da âncora (mas só se não excedemos o número máximo de linhas):

public boolean mouseDown(Event evt, int x, int y) {
   if (currline < MAXLINES) {
       anchor = new Point(x,y);
       return true;
  }
   else  {
      System.out.println("Too many lines.");
      return false;
   }
}

Enquanto o rato se está arrastando para desenhar a linha, o applet anima a linha que se desenha. Como arrasta o rato em volta, os novos movimentos de linha com ele do ponto da âncora à ponta do rato. O evento de mouseDrag() contém o ponto atual cada vez os movimentos de rato, portanto use aquele método para guardar a pista do ponto atual (e repintar para cada movimento portanto a linha "anima"). Observe que se tenhamos excedido o número máximo de linhas, não quereremos fazer algum disto. Aqui está o método the mouseDrag() para fazer todas aquelas coisas:

public boolean mouseDrag(Event evt, int x, int y) {
   if (currline < MAXLINES) {
       currentpoint = new Point(x,y);
       repaint();
       return true;
    }
   else return false;
}

A nova linha não se torna acrescentada às tabelas de velhas linhas até que o botão de rato se lance. Aqui está mouseUp(), que testa para assegurar-se que não excedeu o número máximo de linhas antes de chamar o método de addline() (descreveu depois):

public boolean mouseUp(Event evt, int x, int y) {
     if (currline < MAXLINES) {
         addline(x,y);
         return true;
     }
     else return false;
}

O método de addline() é onde as tabelas de começo e fim de pontos se atualizam e onde o applet se repinta para tomar a nova linha no efeito:

void addline(int x,int y) {
    starts[currline] = anchor;
    ends[currline] = new Point(x,y);
    currline++;
    currentpoint = null;
    anchor = null;
    repaint();
}

Observe que neste método também estabelece currentpoint e anchor a null. Porque? Como a linha atual que desenhava é acabada. Estabelecendo estes null variables to, pode testar para aquele valor no método de paint() para ver se tem de desenhar uma linha atual.

Pintar o applet significa desenhar todas as velhas linhas guardadas no starts e tabelas de ends, bem como desenhar a linha atual no progresso (cujos endpoints estão em anchor e currentpoint, respectivamente). Para mostrar a animação da linha atual, desenhe-o no azul. Aqui está o método de paint() das Linhas applet:

public void paint(Graphics g) {

    // Draw existing lines
    for (int i = 0; i < currline; i++) {
        g.drawLine(starts[i].x, starts[i].y,
            ends[i].x, ends[i].y);
    }

    // Draw current line
    g.setColor(Color.blue);
    if (currentpoint != null)
        g.drawLine(anchor.x, anchor.y,
            currentpoint.x, currentpoint.y);
}

Em paint(), quando desenha a linha atual, testa primeiro para ver se currentpoint é null. Se for, o applet não está no meio do desenho de uma linha, então não há razão de tentar desenhar uma linha que não existe. Testando para currentpoint (e estabelecendo currentpoint em null no método de addline()), pode pintar só de que precisa.

é isso - somente 60 linhas do código e alguns métodos básicos, e tem uma aplicação de desenho muito básica no seu Navegador da Web. A listagem 12.2 mostra o texto cheio das Linhas applet para que possa juntar as partes.


A listagem 12.2. As Linhas applet.
 1: import java.awt.Graphics;
 2: import java.awt.Color;
 3: import java.awt.Event;
 4: import java.awt.Point;
 5:
 6: public class Lines extends java.applet.Applet {
 7:
 8:     final int MAXLINES = 10;
 9:     Point starts[] = new Point[MAXLINES]; // starting points
10:     Point ends[] = new Point[MAXLINES];    // endingpoints
11:     Point anchor;    // start of current line
12:     Point currentpoint; // current end of line
13:     int currline = 0; // number of lines
14:
15:     public void init() {
16:         setBackground(Color.white);
17:     }
18:
19:     public boolean mouseDown(Event evt, int x, int y) {
20:        if (currline < MAXLINES) {
21:            anchor = new Point(x,y);
22:            return true;
23:       }
24:        else  {
25:           System.out.println("Too many lines.");
26:           return false;
27:        }
28:     }
29:
30:    public boolean mouseUp(Event evt, int x, int y) {
31:         if (currline < MAXLINES) {
32:             addline(x,y);
33:             return true;
34:         }
35:         else return false;
36:    }
37:
38:     public boolean mouseDrag(Event evt, int x, int y) {
39:        if (currline < MAXLINES) {
40:            currentpoint = new Point(x,y);
41:            repaint();
42:            return true;
43:         }
44:        else return false;
45:     }
46:
47:     void addline(int x,int y) {
48:         starts[currline] = anchor;
49:         ends[currline] = new Point(x,y);
50:         currline++;
51:         currentpoint = null;
52:         anchor = null;
53:         repaint();
54:     }
55:
56:     public void paint(Graphics g) {
57:
58:         // Draw existing lines
59:         for (int i = 0; i < currline; i++) {
50:             g.drawLine(starts[i].x, starts[i].y,
51:                  ends[i].x, ends[i].y);
52:         }
53:
54:         // draw current line
55:         g.setColor(Color.blue);
56:         if (currentpoint != null)
57:             g.drawLine(anchor.x,anchor.y,
58:             currentpoint.x,currentpoint.y);
59:     }
60:}

Eventos de teclado

Um evento de teclado gera-se sempre que um usuário aperte uma chave no teclado. Usando eventos de teclado, pode vir mantêm dos valores das chaves o usuário apertado para executar uma ação ou simplesmente introduzir o caráter dos usuários do seu applet.

O keyDown() e métodos de keyUp()

Para capturar um evento de teclado, use o método de keyDown():

public boolean keyDown(Event evt, int key) {
    ...
}

As chaves geradas pela chave abaixo os eventos (e passou em keyDown() como o argumento de key) são a representação de números inteiros valores de caráter de Unicode, que incluem carateres alfanuméricos, teclas de função, etiquetas, regressos, e assim por diante. Para usá-los como carateres (por exemplo, imprimi-los), tem de lançá-los a carateres:

currentchar = (char)key;

Aqui está um exemplo simples de um método de keyDown() que realmente apenas imprime a chave que somente datilografou tanto no seu Unicode como em representação de caráter (pode ser divertimento de ver que os carateres-chave produzem que valores):

public boolean keyDown(Event evt, int key) {
    System.out.println("ASCII value: " + key);
    System.out.println("Character: " + (char)key);
    return true;
}

Como com cliques de rato, cada chave abaixo o evento também tem uma chave correspondente evento. Para interceptar a chave eventos, use o método de keyUp():

public booklean keyUp(Event evt, int key)  {
   ...
}

Chaves à revelia

A classe de Event fornece o grupo de variáveis de classe que se referem a várias chaves não-alfanuméricas padrão, como a flecha e teclas de função. Se a interface do seu applet usar estas chaves, pode fornecer o código mais legível testando para estes nomes no seu método de keyDown() em vez de testar para os seus valores numéricos (e também com maior probabilidade será transversal plataforma se usar estas variáveis). Por exemplo, para testar se a flecha se apertou, poderia usar o seguinte fragmento do código:

if (key == Event.UP) {
    ...
}

Como os valores que estas variáveis de classe mantêm são números inteiros, também pode usar a afirmação de switch para testar para eles.

A tabela 12.1 mostra as variáveis de classe de evento padrão de várias chaves e as chaves reais que representam.

A tabela 12.1. As chaves padrão definem-se pela classe de Event.

Variável de classeChave representada
Event.HOME A chave de Casa
Event.END A chave de Fim
Event.PGUP A Página chave
Event.PGDN A Página Abaixo chave
Event.UP Flecha
Event.DOWN Abaixo flecha
Event.LEFT A flecha esquerda
Event.RIGHT A flecha direita
Event.f1 A chave f1
Event.f2 A chave f2
Event.f3 A chave f3
Event.f4 A chave f4
Event.f5 A chave f5
Event.f6 A chave f6
Event.f7 A chave f7
Event.f8 A chave f8
Event.f9 A chave f9
Event.f10 A chave f10
Event.f11 A chave f11
Event.f12 A chave f12

Um exemplo: entrada, exposição e movimento de carateres

Vamos olhar para um applet que demonstra eventos de teclado. Com este applet, datilografa um caráter, e aquele caráter expõe-se no centro da janela applet. Então pode deslocar aquele caráter na tela com as teclas de seta. Datilografar outro caráter em qualquer momento modifica o caráter como se expõe atualmente. A figura 12.3 mostra um exemplo.

A figura 12.3: As Chaves applet.

Observar
Para conseguir que este applet trabalhe, deveria clicar uma vez com o rato nele para as chaves para destacar-se. Isto deve assegurar-se que o applet tem o foco de teclado (isto é, que a sua de fato escuta quando datilografa carateres no teclado).

Este applet é de fato menos complicado do que o applets prévio que usou. Este tem só três métodos: init(), keyDown() e paint(). As variáveis de exemplo também são mais simples porque as únicas coisas das quais tem de guardar a pista são o x e as posições y do caráter atual e os valores daquele próprio caráter. Aqui está a definição de classe inicial:

import java.awt.Graphics;
import java.awt.Event;
import java.awt.Font;
import java.awt.Color;

public class Keys extends java.applet.Applet {

    char currkey;
    int currx;
    int curry;
}

Vamos começar acrescentando um método de init(). Aqui, init() é responsável por três coisas: escolher a cor de fundo, estabelecer a fonte do applet (aqui, Helvetica de 36 pontos corajoso), e estabelecer a posição que começa do caráter (o meio da tela, menos alguns pontos para cutucar nele e à direita):

public void init() {
    currx = (size().width / 2) - 8;
    curry = (size().height / 2) - 16;
    setBackground(Color.white);
    setFont(new Font("Helvetica", Font.BOLD, 36));
}

Como o comportamento deste applet é baseado na entrada de teclado, o método de keyDown() é onde a maioria do trabalho do applet se realiza:

public boolean keyDown(Event evt, int key) {
   switch (key) {
         case Event.DOWN:
             curry += 5;
             break;
         case Event.UP:
             curry -= 5;
             break;
         case Event.LEFT:
             currx -= 5;
             break;
         case Event.RIGHT:
             currx += 5;
             break;
         default:
             currkey = (char)key;
         }
         repaint();
         return true;
}

No centro do keyDown() o applet é uma afirmação de switch que testes de eventos-chave diferentes. Se o evento for uma tecla de seta, a modificação apropriada faz-se à posição do caráter. Se o evento for alguma outra chave, o próprio caráter modifica-se (isto é a parte à revelia do switch). O método termina com um repaint() e regressos true.

O método de paint() aqui é quase trivial; somente exponha o caráter atual na posição atual. Contudo, observe que quando o applet lança, não há caráter inicial e nada para desenhar, portanto tem de levar em conta isto. A variável de currkey inicializa-se a 0, portanto pinta o applet só se currkey tiver um valor real:

public void paint(Graphics g) {
    if (currkey != 0) {
        g.drawString(String.valueOf(currkey), currx,curry);
    }
}

A listagem 12.3 mostra o texto fonte completo das Chaves applet.


A listagem 12.3. As Chaves applet.
 1: import java.awt.Graphics;
 2: import java.awt.Event;
 3: import java.awt.Font;
 4: import java.awt.Color;
 5:
 6: public class Keys extends java.applet.Applet {
 7:
 8:     char currkey;
 9:     int currx;
10:    int curry;
11:
12:     public void init() {
13:         currx = (size().width / 2) -8;  // default
14:         curry = (size().height / 2) -16;
15:
16:         setBackground(Color.white);
17:         setFont(new Font("Helvetica",Font.BOLD,36));
18:     }
19:
20:     public boolean keyDown(Event evt, int key) {
21:         switch (key) {
22:         case Event.DOWN:
23:             curry += 5;
24:             break;
25:         case Event.UP:
26:             curry -= 5;
27:             break;
28:         case Event.LEFT:
29:             currx -= 5;
30:             break;
31:         case Event.RIGHT:
32:             currx += 5;
33:             break;
34:         default:
35:             currkey = (char)key;
36:         }
37:
38:         repaint();
39:         return true;
40:     }
41:
42:     public void paint(Graphics g) {
43:         if (currkey != 0) {
44:             g.drawString(String.valueOf(currkey), currx,curry);
45:         }
46:     }
47: }

Testar para chaves de modificador e múltiplos botões de rato

O turno, Controle (Ctrl) e a Meta é chaves de modificador. Não geram próprios eventos-chave, mas quando adquire um rato ordinário ou evento de teclado, pode testar para ver se aquelas chaves de modificador se seguraram quando o evento ocorreu. Às vezes pode óbvio deslocar-se as chaves alfanuméricas produzem eventos-chave diferentes do que não deslocados, por exemplo. Para outros eventos, eventos de contudo-rato no pormenor - pode querer tratar um evento com uma chave de modificador segurada diferentemente de uma versão regular daquele evento.

Observar
A chave de Meta usa-se comumente em sistemas UNIX; fazem o mapa normalmente dele a Alt em teclados de PC e Ordem (maçã) em Macintosh.

A classe de Event fornece três métodos para testar se uma chave de modificador se segura: shiftDown(), metaDown() e controlDown(). Os valores booleanos de todo o regresso baseados em se aquela chave de modificador de fato se segura. Pode usar estes três métodos em algum do evento - o manejo de métodos (rato ou teclado) chamando-os no objeto de evento passou naquele método:

public boolean mouseDown(Event evt, int x, int y ) {
    if (evt.shiftDown())
         // handle shift-click
    else // handle regular click
}

Um outro uso significante destes métodos de chave de modificador deve testar para o qual o botão de rato gerou um determinado evento de rato em sistemas com dois ou três botões de rato. À revelia, os eventos de rato (como rato abaixo e arrasto de rato) geram-se apesar do qual o botão de rato se usa. Contudo, os eventos de Java interiormente fazem o mapa deixado e ações de rato meias à Meta e Controle (Ctrl) chaves de modificador, respectivamente, testando então para os testes-chave da ação de botão de rato. Testando para chaves de modificador, pode descobrir que botão de rato se usou e realize o comportamento diferente daqueles botões do que ia para o botão esquerdo. Use uma afirmação de if para testar cada caso, como isto:

public boolean mouseDown(Event evt, int x, int y ) {
    if (evt.metaDown())
         // handle a right-click
    else if (evt.controlDown())
        // handle a middle-click
    else // handle a regular click
}

Observe que porque este mapeamento de múltiplos botões de rato a modificadores de teclado acontece automaticamente, não tem de fazer muito trabalho para assegurar-se o seu applets ou trabalho aplicado em sistemas diferentes com tipos diferentes de dispositivos de rato. Como o rato de botão direito ou botão esquerdo clica no mapa de eventos de chave de modificador, pode usar aqueles chaves de modificador reais em sistemas com menos botões de rato para gerar exatamente os mesmos resultados. Deste modo, por exemplo, segurar a tecla CTRL e clicar no rato no Windows ou manter a Tecla control no Macintosh são o mesmo como clique no botão de rato meio em um rato de três botões; segurar a Ordem (maçã) a chave e clicar no rato em Mac são o mesmo como clique no botão de rato direito em uns dois - ou rato de três botões.

Considere, contudo, que o uso de botões de rato diferentes ou chaves de modificador pode não ser imediatamente óbvio se o seu applet ou a aplicação correrem em um sistema com menos botões do que está acostumado a trabalhar com. Pense que a restrição da sua interface para um botão de rato único ou para o fornecimento de ajuda ou documentação explica o uso do seu programa neste caso.

O Manipulador de eventos awt

Os métodos à revelia sobre os quais aprendeu hoje para tratar eventos básicos em applets chamam-se de fato por um método de manipulador de eventos genérico chamado handleEvent(). O método de handleEvent() é como o awt genericamente trata com eventos que ocorrem entre componentes aplicados e os eventos baseados no usuário introduzem.

No default método de handleEvent(), os eventos básicos processam-se e os métodos sobre os quais aprendeu hoje chamam-se. Para tratar eventos outros do que os mencionados aqui (por exemplo, os eventos de scrollbars ou de outro usuário inter-relacionam elementos - sobre o qual aprenderá no Dia 13, "Criando Interfaces de Usuário com o awt"), modificar o comportamento de manejo de evento à revelia, ou criar e passar em volta dos seus próprios eventos, tem de ignorar handleEvent() nos seus próprios programas Java. O método de handleEvent() parece a isto:

public boolean handleEvent(Event evt) {
    ...
}

Para testar para eventos específicos, examine a variável de exemplo de id do objeto de Event que se passa na handleEvent(). A carteira de identidade de evento é um número inteiro, mas afortunadamente a classe de Event define um jogo inteiro de carteiras de identidade de evento como variáveis de classe para cujos nomes pode testar no corpo de handleEvent(). Como estas variáveis de classe são constantes de número inteiro, uns trabalhos de afirmação de switch em particular bem. Por exemplo, aqui está um método de handleEvent() simples para imprimir a informação sobre depuração sobre eventos de rato:

public boolean handleEvent(Event evt) {
    switch (evt.id) {
    case Event.MOUSE_DOWN:
        System.out.println("MouseDown: " +
                evt.x + "," + evt.y);
        return true;
    case Event.MOUSE_UP:
        System.out.println("MouseUp: " +
                evt.x + "," + evt.y);
        return true;
    case Event.MOUSE_MOVE:
        System.out.println("MouseMove: " +
                evt.x + "," + evt.y);
        return true;
    case Event.MOUSE_DRAG:
        System.out.println("MouseDrag: " +
                evt.x + "," + evt.y);
        return true;
    default:
        return false;
    }
}

Pode testar para os seguintes eventos de teclado:

Pode testar para estes eventos de rato:

Além destes eventos, a classe de Event tem uma suite inteira de métodos para tratar componentes awt. Aprenderá mais sobre estes eventos amanhã.

Observe que se ignora handleEvent() na sua classe, nenhum dos métodos de manejo do evento à revelia que aprendeu sobre hoje se chamará a menos que explicitamente os chame no corpo de handleEvent(), assim ter cuidado se decidir fazer isto. Um modo de vir em volta disto é testar para o evento interessa-se em, e se aquele evento não for ele, chame super.handleEvent() para que a superclasse que define handleEvent() possa processar coisas. Aqui está um exemplo de como fazer isto:

public boolean handleEvent(Event evt) {
    if (evt.id == Event.MOUSE_DOWN) {
        // process the mouse down
        return true;
    } else {
        return super.handleEvent(evt);
    }
}

Também, observe que como os métodos individuais de eventos individuais, handleEvent() também devolve um booleano. O valor que devolve aqui é especialmente importante; se passar o manejo do evento a outro método, deve devolver false. Se tratar o evento no corpo deste método, devolva true. Se passar o evento até uma superclasse, aquele método devolverá true ou false; não se tem.

Sumário

Tratar eventos na Caixa de ferramentas de Windowing Abstrata de Java é fácil. A maior parte do tempo tudo que tem de fazer é picar o método direito no seu código de applet e as suas intercepções de applet e trata aquele evento no momento oportuno. Aqui estão alguns eventos básicos que pode dirigir deste modo:

Todos os eventos no awt geram um objeto de Event; dentro daquele objeto, pode descobrir a informação sobre o evento, quando ocorreu, e o seu x e coordenadas de y (se aplicável). Também pode testar aquele evento para ver se uma chave de modificador se apertou quando o evento ocorreu, usando o shiftDown(), controlDown() e métodos de metaDown().

Finalmente, há método de handleEvent(), o "pai" dos métodos de evento individuais. O método de handleEvent() é de fato que as chamadas de sistema de Java dirigir eventos; a implementação à revelia chama os eventos de método individuais onde necessário. Para ignorar como os métodos se dirigem no seu applet, ignore handleEvent().

Perguntas e Respostas

Q:
Nos Lugares applet, as coordenadas de lugar guardam-se em tabelas, que têm um tamanho limitado. Como posso modificar este applet para que desenhe um número ilimitado de lugares?
A:
Pode fazer uma de umas coisas de par:
A primeira coisa a fazer é testar, no seu método de addspot(), se o número de lugares excedeu MAXSPOTS. Então crie uma tabela maior, copie os elementos da velha tabela naquela tabela maior (use o método de System.arraycopy() para fazer isto), e redestine o x e tabelas de y àquela tabela nova, maior.
A segunda coisa a fazer é usar a classe de Vector. Vector, parte do pacote de java.util, implementa uma tabela que é automaticamente o growable-tipo do parecido uma lista ligada está em outras línguas. A desvantagem de Vector é que para pôr algo em Vector, tem de ser um objeto real. Isto significa que terá de lançar números inteiros a objetos de Integer, e logo extrair os seus valores de objetos de Integer de tratá-los como números inteiros novamente. A classe de Vector permite-lhe acessar e modificar elementos no Vector como pode em uma tabela (usando chamadas de método, em vez de pôr em ordem a sintaxe). Verifique-o.
Q:
O que a Meta é-chave?
A:
É popular em sistemas UNIX, e muitas vezes feito o mapa a Alt na maior parte de teclados (Opção em Macs). Como Turno e Controle (Ctrl) são muito mais populares e comuns, é provavelmente uma boa ideia de basear as suas interfaces naquelas chaves de modificador se puder.
Q:
Como testo para ver se a tecla ENTER se apertou?
A:
Volte (alimentos de linha) é caráter 10; Entre (retorno de carro) é caráter 13. Observe que as plataformas diferentes podem enviar chaves diferentes para a chave real Regresso marcado. Especialmente, os sistemas de UNIX enviam alimentos de linha, os Macintosh enviam retornos de carro, e os sistemas de DOS enviam ambos. Assim para fornecer o comportamento de transversal plataforma, pode querer testar tanto para alimentos de linha como para retorno de carro.
A palavra da equipe de Java é que um Regresso é um Regresso é um Regresso, apesar da plataforma. Contudo, no momento desta escrita, é duvidoso se isto atualmente é verdade no Conjunto de Desenvolvedor de Java. Pode querer verificar a documentação API a classe de Event para ver se isto se modificou entrementes.
Q:
Olhei para o API da classe de Event, e há muitos outros tipos de evento enumerados lá do que aqueles menciona hoje.
A:
Sim. A classe de Event define muitos tipos diferentes de eventos, tanto para entrada de usuário geral, como o rato como para eventos de teclado sobre os quais aprendeu aqui, e também eventos para dirigir modificações do estado de componentes de interface de usuário, como janelas e scrollbars. Amanhã aprenderá sobre aqueles outros eventos.