Um rapaz me perguntou como seria fazer um drag'n drop (na mão) de um elemento gráfico em uma tela.
Então resolvi postar uma resposta aqui no blog. :)
Como ele não especificou a linguagem, vou fazer em Java/AWT (será que alguém ainda usa isso?!? :P ), que foi a linguagem que mais trabalhei nos últimos 10 anos...
Primeiramente, vamos criar uma janela de tamanho fixo (no caso, 300x300):
//Herda de Frame (Janela)
public class MainClass extends Frame {
//Construtor da classe
public MainClass() {
//Tamanho da janela
this.setSize(300, 300);
//Título da janela
this.setTitle("Exemplo Gráfico");
}
//Método principal que inicia a aplicação
public static void main(String arg[]) {
//Instância o objeto
MainClass main = new MainClass();
//Exibe a tela
main.setVisible(true);
}
}
Para evitar que a janela fique "ad-eterno" na tela, mesmo clicando no "X", vamos implementar a função de fechar da janela em seu construtor:
...
//Construtor da classe
public MainClass() {
...
//"Escutador" de eventos de janela
this.addWindowListener(new WindowAdapter() {
//Método que é executado quando o usuário clicar no botão de fechar da janela (ou algum evento que tenha a mesma funcionalidade, como o Ctrl+X no MS-Windows)
@Override
public void windowClosing(WindowEvent e) {
//Encerra a aplicação
System.exit(0);
}
});
...
}
...
Legal, temos uma janela feita em Java! :)
Vamos para o segundo passo: criamos um objeto gráfico (neste caso, um retângulo) como uma propriedade da classe e instanciamos esta em seu construtor:
public class MainClass extends Frame {
private Rectangle rect;
...
public MainClass() {
...
//Retângulo a ser desenhado
rect = new Rectangle(50, 50, 60, 30);
...
}
...
}
E agora vamos desenhar este retângulo na tela, reescrevendo os métodos paint e update:
...
//Para evitar o "pisca-pisca" (efeito de blink) da tela
@Override
public void update(Graphics g) {
this.paint(g);
}
//Desenha um retângulo vermelho em um fundo preto (retângulo do tamanho da tela)
@Override
public void paint(Graphics g) {
//Pinta a tela de preto
g.setColor(Color.BLACK);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
//Pinta um retângulo vermelho
g.setColor(Color.RED);
g.fillRect((int)rect.getX(), (int)rect.getY(),
(int)rect.getWidth(), (int)rect.getHeight());
}
...
Executamos e temos um retângulo vermelho em um fundo preto (eu já disse isso em algum lugar?). :)
Nesta terceira etapa, precisamos identificar os eventos de drag'n drop, que são (eu acho...):
1) O evento de botão do mouse pressionado para obter o efeito de "pegar" o retângulo;
2) O evento de soltar o botão do mouse para obter o efeito de "largar" o retângulo;
3) E o evento de movimento do mouse, para que o retângulo acompanhe o "ponteiro" do mouse enquanto ele não for solto;
Com isso, a classe vai ficar mais ou menos assim:
import java.awt.*;
import java.awt.event.*;
//Herda de Frame (Janela)
public class MainClass extends Frame {
//Retângulo a ser desenhado
private Rectangle rect;
//Flag que indica se o objeto esta sendo "arrastado"
private boolean elementDragged;
//Ponto (x,y) da tela onde o ponteiro do mouse estava inicialmente
private Point initial;
//Construtor da classe
public MainClass() {
//Retângulo a ser desenhado
rect = new Rectangle(50, 50, 50, 50);
//Tamanho da janela
this.setSize(300, 300);
//Título da Janela
this.setTitle("Exemplo Gráfico");
this.addEventListener();
}
//Método privado que adiciona os eventos
private void addEventListener() {
//"Escutador" de eventos de janela
this.addWindowListener(new WindowAdapter() {
//Método que é executado quando o usuário clicar no botão de fechar da janela (ou algum evento que tenha a mesma funcionalidade, como o Ctrl+X no MS-Windows)
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
//"Escutador" de eventos do mouse
this.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
mousePressedEvent(e);
}
@Override
public void mouseReleased(MouseEvent e) {
mouseReleasedEvent(e);
}
});
//"Escutador" de eventos de movimento do mouse
this.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
mouseDraggedEvent(e);
}
});
}
//Quando o botão do mouse é pressionado, este método é executado
private void mousePressedEvent(MouseEvent e) {
//Se o ponteiro do mouse esta dentro do retângulo...
if (rect.contains(e.getPoint())) {
//Obtenho o ponto inicial do ponteiro do mouse
initial = new Point((int)(e.getPoint().getX() - rect.getX()),
(int)(e.getPoint().getY() - rect.getY()));
//E digo que o retângulo pode ser "arrastado"
elementDragged = true;
}
}
//Quando o mouse é "arrastado", este método é executado
private void mouseDraggedEvent(MouseEvent e) {
//Se o retângulo pode ser "arrastado"
if (elementDragged) {
//Faço ele movimentar-se de acordo com a posição do ponteiro do mouse
rect.setLocation((int)((e.getPoint().getX() - initial.getX())),
(int)(e.getPoint().getY() - initial.getY()));
//Redesenho a tela
this.repaint();
}
}
//Quando o botão do mouse é "solto", este método é executado
public void mouseReleasedEvent(MouseEvent e) {
//Digo que o retângulo não esta mais "arrastavel"
elementDragged = false;
//E "zero" a posição inicial
initial = null;
}
//Para evitar o "pisca-pisca" (efeito de blink) da tela
@Override
public void update(Graphics g) {
this.paint(g);
}
//Desenha um retângulo vermelho em um fundo preto (retângulo do tamanho da tela)
@Override
public void paint(Graphics g) {
//Pinta a tela de preto
g.setColor(Color.BLACK);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
//Pinta um retângulo vermelho
g.setColor(Color.RED);
g.fillRect((int)rect.getX(), (int)rect.getY(),
(int)rect.getWidth(), (int)rect.getHeight());
}
//Método principal que inicia a aplicação (tudo começa aqui... :) )
public static void main(String arg[]) {
//Instância a classe
MainClass main = new MainClass();
//Exibe a tela
main.setVisible(true);
}
}
Parece que funciona... (eu testei no MacOSX 10.7.4, com o JDK 1.6.0_33)
Até mais!
Nenhum comentário:
Postar um comentário