If you're seeing this message, it means we're having trouble loading external resources on our website.

Se você está atrás de um filtro da Web, certifique-se que os domínios *.kastatic.org e *.kasandbox.org estão desbloqueados.

Conteúdo principal

Uma função botão

Se você passou pelo curso Introdução ao JS, já criou alguns botões simples nos desafios de lógica Seu Primeiro Botão e Um Botão Mais Inteligente. Caso tenha esquecido, vamos retomar como fazer um botão simples.
Primeiro, quais são os requisitos mínimos de um botão?
  1. Uma forma na tela (normalmente um retângulo)
  2. Inclui um rótulo ou ícone que descreve o que ele faz
  3. Responde aos cliques nele (mas não em outro lugar)
Podemos cobrir os requisitos 1 e 2 facilmente:
fill(0, 234, 255);
rect(100, 100, 150, 50, 5);
fill(0, 0, 0);
textSize(19);
text("Useless button", 110, 133);
Para cobrir o requisito 3, precisamos definir uma função mouseClicked que será chamada quando o usuário clicar. Dentro dela, precisamos verificar se mouseX e mouseY estão dentro da caixa delimitadora do botão. Para o botão acima, ela estende-se de x=100 até x=250, e de y=100 até y=150, conforme ilustrado abaixo:
Podemos verificar as coordenadas utilizando && para unir as quatro condições:
mouseClicked = function() {
    if (mouseX >= 100 && mouseX <= 250 &&
        mouseY >= 100 && mouseY <= 150) {
        println("Ainda continua inútil");    
    }
};
Tente clicar no botão e na área em volta para ver se ele funciona:
Ele definitivamente funciona, mas isso também me preocupa. Estou preocupado por não ser código muito reutilizável. Quanto trabalho eu terei se quiser mudar o botão de posição? (Experimente acima!) Eu vejo muitos números fixados no código – como as coordenadas na função mouseClicked, o que imediatamente me leva a pensar se não há uma maneira mais simples de fazer isso.
Para começar, vamos criar variáveis para a posição e tamanho, de forma que possamos mudar esses valores em um só lugar e, mesmo assim, manter o clique funcionando. Eu adicionei btnX, btnY, btnWidth e btnHeight ao programa abaixo. Experimente mudar seus valores e clicar no botão:
Bem, assim está melhor. No entanto, quanto trabalho terei se quiser adicionar mais um botão? Tenho que copiar e colar tudo aquilo, e criar btn2X, btn2Y? Ah, isso não parece muito divertido. Isso parece um bom motivo para escrever uma função que se encarregará de fazer tudo que for igual para os botões, e usará parâmetros para lidar com o que for diferente. Nós poderíamos escrevê-la assim, transformando as variáveis em parâmetros:
var drawButton = function(btnX, btnY, btnWidth, btnHeight) {
    fill(0, 234, 255);
    rect(btnX, btnY, btnWidth, btnHeight, 5);
    fill(0, 0, 0);
    textSize(19);
    textAlign(LEFT, TOP);
    text("Useless button", btnX+10, btnY+btnHeight/4);
};
Então, chamamos a função assim:
drawButton(100, 100, 150, 50);
Mas, e o nosso código de mouseClicked? Vê qual seria o problema com isso?
mouseClicked = function() {
    if (mouseX >= btnX && mouseX <= (btnX+btnWidth) &&
        mouseY >= btnY && mouseY <= (btnY+btnHeight)) {
        println("Ainda continua inútil");    
    }
};
Se tivéssemos todo esse código junto, teríamos um erro de "Oh, não" com "btnX não está definido" - e ele está certo! Nós transformamos btnX em um parâmetro de função, o que significa que não é mais uma variável global. Isso é ótimo para a reutilização da função drawButton, mas, agora, a função mouseClicked não tem como saber as coordenadas que precisa verificar.
Então nós precisamos descobrir uma boa maneira de passar a informação para drawButton e disponibilizar essa informação para mouseClicked. Eu tenho algumas opções:
  1. Criar novamente variáveis globais para a posição e o tamanho (btnX, btnY, btnWidth, btnHeight)
  2. Criar um arranjo global que armazena todos os parâmetros (var btn1 = [...];)
  3. Criar um objeto global que armazena todos os parâmetros (var btn1 = {..})
  4. Usar princípios de orientação a objetos para definir o botão e armazenar as propriedades (var btn1 = new Button(...))
Qual escolher? Bem, eu não gosto muito da primeira porque teríamos que adicionar muitas variáveis globais e eu tenho uma alergia a variáveis globais. Eu não amo a segunda técnica porque é difícil ler código que pega dados baseados em índices de arranjos. Gosto da terceira técnica porque ela usa somente uma variável global, e assim o código fica mais legível. Eu também gosto da quarta técnica, que usa princípios orientados a objetos para criar tipos de objeto Button genéricos, mas vamos deixar isso para depois.
Podemos criar nosso objeto global btn1 da seguinte forma:
var btn1 = {
    x: 100,
    y: 100,
    width: 150,
    height: 50
};
E alterar a função drawButton para aceitar um único objeto, do qual então pega as propriedades:
var drawButton = function(btn) {
    fill(0, 234, 255);
    rect(btn.x, btn.y, btn.width, btn.height, 5);
    fill(0, 0, 0);
    textSize(19);
    textAlign(LEFT, TOP);
    text("Useless button", btn.x+10, btn.y+btn.height/4);
};
A função mouseClicked irá verificar as propriedades da variável global:
mouseClicked = function() {
    if (mouseX >= btn1.x && mouseX <= (btn1.x+btn1.width) &&
        mouseY >= btn1.y && mouseY <= (btn1.y+btn1.height))     {
        println("Ainda continua inútil");    
    }
};
Experimente fazer isso! Como antes, tente alterar parâmetros diferentes do botão e ver se ele continua funcionando:
A ideia de fazer isso é que possamos adicionar mais botões com facilidade, o último teste de reusabilidade. Podemos fazer isso?
Vamos começar com uma nova variável global, btn2, com deslocamento na direção y do primeiro botão:
var btn2 = {
    x: 100,
    y: 200,
    width: 150,
    height: 50
};
Em seguida, vamos desenhar esse botão:
drawButton(btn2);
Desse modo, conseguiremos desenhar 2 botões na tela, mas somente o primeiro responderá a cliques. Nós podemos fazer o segundo responder ao duplicar a lógica e substituir btn2 por btn1, assim:
mouseClicked = function() {
    if (mouseX >= btn1.x && mouseX <= (btn1.x+btn1.width) &&
        mouseY >= btn1.y && mouseY <= (btn1.y+btn1.height))     {
        println("Ainda continua inútil");    
    }

    if (mouseX >= btn2.x && mouseX <= (btn2.x+btn2.width) &&
        mouseY >= btn2.y && mouseY <= (btn2.y+btn2.height))     {
        println("O segundo também ainda inútil!");    
    }
};
Mas todo esse código repetido não te deixa de nariz torcido? Vamos criar uma função isMouseInside que sabe verificar qualquer objeto de botão e retorna "verdadeiro" se o mouse estiver dentro dele:
var isMouseInside = function(btn) {
    return (mouseX >= btn.x &&
            mouseX <= (btn.x+btn.width) &&
            mouseY >= btn.y && 
            mouseY <= (btn.y+btn.height));
};
Agora, podemos usar a função dentro de mouseClicked para reduzir drasticamente a quantidade de código repetido:
mouseClicked = function() {
    if (isMouseInside(btn1))     {
        println("Ainda continua inútil ");    
    } else if (isMouseInside(btn2))     {
        println("2nd one still quite useless!");    
    }
};
Aí está! Usamos funções para desenhar vários botões, e ficou relativamente fácil adicionar novos botões. Tente fazer isso abaixo:
Poderíamos continuar – criando arranjos de todos os botões de um programa, tornando possível personalizar o texto e a cor de um botão – mas espero que o que foi feito já tenha te dado uma boa base para criar botões simples usando funções. Em seguida, vamos percorrer passo a passo a criação de botões usando princípios orientados a objeto.

Quer participar da conversa?

Você entende inglês? Clique aqui para ver mais debates na versão em inglês do site da Khan Academy.