Software">
Object-Oriented Python - En.pt
Object-Oriented Python - En.pt
Object-Oriented Python - En.pt
com
PARTE II
USUÁRIO GRÁFICO
INTER FAC ESWITHP YG AME
isso possa ser um resultado divertido. Em vez disso, usarei o ambiente pygame para
tornar certas técnicas de programação orientadas a objetos mais claras e mais visuais. Ao
trabalhar com pygame para tornar os objetos visíveis em uma janela e lidar com um
usuário interagindo com esses objetos, você deve obter uma compreensão mais profunda
de como usar efetivamente as técnicas de POO.
Este capítulo fornece uma introdução geral ao pygame, portanto, a maioria das
informações e exemplos neste capítulo usarão codificação procedural. Começando
com o próximo capítulo, explicarei como usar OOP efetivamente com pygame.
Instalando o Pygame
Pygame é um pacote gratuito para download. Usaremos o gerenciador de
pacotes pip(abreviatura depip instala pacotes) para instalar pacotes Python.
Conforme mencionado na introdução, estou assumindo que você instalou a
versão oficial do Python depython.org. O programa pip está incluído como parte
desse download, então você já deve tê-lo instalado.
Ao contrário de um aplicativo padrão, você deve executar o pip na linha de
comando. Em um Mac, inicie o aplicativo Terminal (localizado naServiços de utilidade
pública subpasta dentro doFormuláriospasta). Em um sistema Windows, clique no ícone
do Windows, digitecmde pressione ENTER.
NOTA Este livro não foi testado com sistemas Linux. No entanto, a maioria, se não todo, o conteúdo
deve funcionar com ajustes mínimos. Para instalar o pygame em uma distribuição Linux, abra
um terminal da maneira que você estiver acostumado.
importar pygame
Se você vir uma mensagem dizendo algo como “Olá da comunidade pygame” ou
se você não receber nenhuma mensagem, então o pygame foi instalado corretamente.
A falta de uma mensagem de erro indica que o Python conseguiu encontrar e carregar
o pacote pygame e está pronto para uso. Se você gostaria de ver um jogo de exemplo
usando pygame, digite o seguinte comando (que inicia uma versão doInvasores do
espaço):
python3 -m pygame.examples.aliens
90 capítulo 5
Antes de começarmos a usar o pygame, preciso explicar dois conceitos importantes.
Primeiro, explicarei como os pixels individuais são endereçados em programas que usam uma
GUI. Em seguida, discutirei os programas orientados a eventos e como eles diferem dos
programas típicos baseados em texto. Depois disso, codificaremos alguns programas que
demonstram os principais recursos do pygame.
Detalhes da janela
Uma tela de computador é composta por um grande número de linhas e colunas de
pequenos pontos chamadospíxeis(das palavraselemento de imagem). Um usuário
interage com um programa GUI por meio de uma ou mais janelas; cada janela é uma
parte retangular da tela. Os programas podem controlar a cor de qualquer pixel
individual em sua(s) janela(s). Se você estiver executando vários programas GUI, cada
programa normalmente é exibido em sua própria janela. Nesta seção, discutirei como
você aborda e altera pixels individuais em uma janela. Esses conceitos são
independentes do Python; eles são comuns a todos os computadores e são usados
em todas as linguagens de programação.
Você provavelmente está familiarizado com as coordenadas cartesianas em uma grade como a Figura 5-1.
eixo y
eixo x
-6 -5 -4 -3 -2 -1 1 2 3 4 5 6
-1
-2
-3
-4
-5
-6
Introdução ao Pygame 91
Qualquer ponto em uma grade cartesiana pode ser localizado especificando
suas coordenadas x e y (nessa ordem). A origem é o ponto especificado como (0, 0)
e se encontra no centro da grade.
As coordenadas da janela do computador funcionam de maneira semelhante (Figura 5-2).
0 Máx. x
Max y
3. Os valores xey são sempre inteiros. Cada par (x, y) especifica um único
pixel na janela. Esses valores são sempre especificados em relação ao canto superior
esquerdo da janela, não à tela. Dessa forma, o usuário pode mover a janela para qualquer
lugar da tela sem afetar as coordenadas dos elementos do programa exibidos na janela.
pixelLocalização = (3, 5)
92 capítulo 5
0 1 2 3 4 5 6 7 8 9 10 11 12 13…
10
11
12
13
…
Figura 5-3: Um único ponto (um único pixel) em uma janela de computador
Introdução ao Pygame 93
0 1 2 3 4 5 6 7 8 9 10 11 12 13…
10
11
12
13
…
Cores de pixel
As cores no pygame são fornecidas como valores RGB e as escrevemos como tuplas
Python de três números. Aqui está como criamos constantes para as cores principais:
94 capítulo 5
Aqui estão as definições de mais algumas cores. Você pode criar uma
cor usando qualquer combinação de três números entre 0 e 255:
TEAL = (0, 128, 128)# sem vermelho, verde com metade da força, azul com metade da
força AMARELO = (255, 255, 0) ROXO = (128, 0, 128)
No pygame, você precisará especificar cores quando quiser preencher o plano de fundo de uma
janela, desenhar uma forma em uma cor, desenhar um texto em uma cor e assim por diante. Definir cores
antecipadamente como constantes de tupla as torna muito fáceis de identificar posteriormente no código.
NOTA Chamadas paraimprimir()ainda pode ser muito útil para depuração, quando usado para escrever
resultados intermediários.
evento Algo que acontece enquanto seu programa está sendo executado e que seu programa deseja
ou precisa responder. A maioria dos eventos são gerados por ações do usuário
Introdução ao Pygame 95
Por exemplo, digamos que temos um programa GUI simples que exibe dois
botões: Bark e Meow. Quando clicado, o botão Bark reproduz o som de um cachorro
latindo e o botão Meow reproduz o som de um gato miando (Figura 5-5).
Usando Pygame
A princípio, o pygame pode parecer um pacote extremamente grande com muitas chamadas
diferentes disponíveis. Embora seja grande, na verdade não há muito que você precise
entender para colocar um pequeno programa em funcionamento. Para apresentar o pygame,
primeiro fornecerei um modelo que você pode usar para todos os programas pygame que
você criar. Então eu vou construir sobre esse modelo, adicionando peças-chave de
funcionalidade pouco a pouco.
Nas seções a seguir, mostrarei como:
96 capítulo 5
Abrindo uma janela em branco
A Listagem 5-1 é um modelo genérico que você pode usar como ponto de partida
para todos os seus programas pygame. Este programa abre uma janela e pinta todo o
conteúdo de preto. A única coisa que o usuário pode fazer é clicar no botão fechar
para sair do programa.
Arquivo: PygameDemo0_WindowOnly/PygameWindowOnly.py
#1 - Importar pacotes
importar pygame
de pygame.locals import *
import sys
FRAMES_PER_SECOND = 30
#3 - Inicialize o mundo
pygame.init()
janela = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
clock = pygame.time.Clock()
# 9 - Limpe a janela
Introdução ao Pygame 97
window.fill(PRETO)
1. Importe pacotes.
O modelo começa com oimportardeclarações. Primeiro importamos o próprio pacote pygame,
depois algumas constantes definidas dentro do pygame que usaremos mais tarde. A última
importação é asistemapacote, que usaremos para sair do nosso programa.
2. Defina constantes.
Em seguida, definimos quaisquer constantes para nosso programa. Primeiro definimos
o valor RGB paraPRETO,que usaremos para pintar o fundo da nossa janela. Em seguida,
definimos constantes para a largura e altura da nossa janela em pixels e uma constante
para a taxa de atualização do nosso programa. Este número define o número máximo
de vezes que o programa fará um loop (e, portanto, redesenhará a janela) por segundo.
Nosso valor de 30 é bastante típico. Se a quantidade de trabalho feito em nosso loop
principal for excessiva, o programa pode ser executado mais lentamente que esse
valor, mas nunca será executado mais rápido. Uma taxa de atualização muito alta pode
fazer com que o programa seja executado muito rápido. Em nosso exemplo de bola,
isso significa que a bola pode quicar na janela mais rápido do que o pretendido.
5. Inicialize as variáveis.
Aqui, eventualmente, inicializaremos quaisquer variáveis que nosso programa
usará. Atualmente não temos nenhum, então não temos código aqui.
98 capítulo 5
6. Faça um loop para sempre.
Aqui começamos nosso loop principal. Este é um simples enquanto verdadeiroLoop infinito.
Novamente, você pode pensar em cada iteração através do loop principal como um
quadro em uma animação.
encontrarmos esse evento, dizemos ao pygame para sair, o que libera todos os recursos
que ele estava usando. Então desistimos do nosso programa.
9. Limpe a janela.
Em cada iteração através do loop principal, nosso programa deve redesenhar tudo
na janela, o que significa que precisamos limpá-lo primeiro. A abordagem mais
simples é apenas preencher a janela com uma cor, o que fazemos aqui com uma
chamada para janela.preencher(),especificando um fundo preto. Também poderíamos
desenhar uma imagem de fundo, mas vamos adiar isso por enquanto.
Introdução ao Pygame 99
12. Desacelere um pouco as coisas.
Quando você executa este programa, o programa apenas exibe uma janela em branco
preenchida com preto. Para encerrar o programa, clique no botão Fechar na barra de título.
Vamos desenhar algo na janela. Há duas partes para mostrar uma imagem
gráfica: primeiro carregamos a imagem na memória do computador, depois
exibimos a imagem na janela do aplicativo.
Com o pygame, todas as imagens (e sons) precisam ser mantidas em arquivos externos ao
seu código. O Pygame suporta muitos formatos de arquivos gráficos padrão, incluindo.png,
.jpg, e.gif. Neste programa vamos carregar uma imagem de uma bola do arquivobola.png.
Como lembrete, o código e os recursos associados a todas as principais listagens deste livro
estão disponíveis para download emhttps://www.nostarch.com/objectorientedpython/ehttps://
github.com/IrvKalb/Object-Oriented-Python-Code/.
Embora só precisemos de um arquivo gráfico neste programa, é uma boa ideia usar uma
abordagem consistente para lidar com arquivos gráficos e de som, então vou apresentar um para
você aqui. Primeiro, crie uma pasta de projeto. Coloque seu programa principal nessa pasta, junto
com quaisquer arquivos relacionados que contenham classes e funções do Python. Em seguida,
dentro da pasta do projeto, crie umimagenspasta na qual você colocará os arquivos de imagem
que deseja usar em seu programa. Crie também umsonspasta e coloque os arquivos de som que
deseja usar lá. A Figura 5-6 mostra a estrutura sugerida. Todos os programas de exemplo neste
livro usarão este layout de pasta de projeto.
100 capítulo 5
PyCharm, ele define a pasta atual para aquela que contém seu programa Python principal para
que você possa usar caminhos relativos com facilidade. Neste livro, assumirei que você está
usando um IDE e representará todos os caminhos como caminhos relativos.
O caminho relativo para um arquivo gráfico (por exemplo,bola.png) na mesma pasta que
seu arquivo principal do Python seria apenas o nome do arquivo como uma string (por
exemplo, 'bola.png').Usando a estrutura de projeto sugerida, o
relativo caminho seria 'imagens/bola.png'.
Isso diz que dentro da pasta do projeto haverá outra pasta chamada imagens, e
dentro dessa pasta há um arquivo chamadobola.png. Em strings de caminho, os nomes
das pastas são separados pelo caractere barra.
No entanto, se você espera executar seu programa a partir da linha de comando,
precisará construir caminhos absolutos para todos os arquivos. Umcaminho absolutoé
aquele que começa na raiz do sistema de arquivos e inclui toda a hierarquia de pastas do
seu arquivo. Para construir um caminho absoluto para qualquer arquivo, você pode usar um
código como este, que cria uma string de caminho absoluto para obola.pngarquivo
noimagenspasta dentro da pasta do projeto:
Agora vamos criar o código do programa ball, começando com o modelo anterior de 12 etapas
e adicionando apenas duas novas linhas de código, conforme mostrado na Listagem 5-2.
Arquivo: PygameDemo1_OneImage/PygameOneImage.py
- - - recorte ---
#3 - Inicialize o mundo
pygame.init()
janela = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
clock = pygame.time.Clock()
#5 - Inicialize as variáveis
- - - recorte ---
NOTA Na documentação oficial do pygame, cada imagem, incluindo a janela do aplicativo, é conhecida
comosuperfície. Usarei termos mais específicos: vou me referir à janela do aplicativo
simplesmente como umjanelae para qualquer imagem carregada de um arquivo externo como
imagem. reservo o prazosuperfíciepara qualquer imagem desenhada em tempo real.
Nós então dizemos ao programa para desenhar a bola2toda vez que passamos pelo
loop principal. Especificamos a localização que representa a posição para colocar o canto
superior esquerdo do retângulo delimitador da imagem, normalmente como uma tupla de
coordenadas x e y.
O nome da funçãoblit()é uma referência muito antiga às palavrastransferência
de bloco de bits, mas neste contexto significa apenas “desenhar”. Como o
programa carregou a imagem da bola anteriormente, o pygame sabe o tamanho da
imagem, então só precisamos dizer onde desenhar a bola. Na Listagem 5-2, damos
um valor x de 100 e um valor y de 200.
Quando você executa o programa, em cada iteração através do loop (30
vezes por segundo) cada pixel na janela é definido como preto, então a bola
é desenhada sobre o fundo. Do ponto de vista do usuário, parece que nada
está acontecendo - a bola apenas fica em um ponto com o canto superior
esquerdo de seu retângulo delimitador no local (100, 200).
Arquivo: PygameDemo2_ImageClickAndMove/PygameImageClickAndMove.py
#1 - Importar pacotes
importar pygame
de pygame.locals import *
import sys
102 capítulo 5
1importar aleatório
#3 - Inicialize o mundo
pygame.init()
janela = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
clock = pygame.time.Clock()
#5 - Inicialize as variáveis
3bolaX = random.randrange(MAX_WIDTH)
bolaY = random.randrange(MAX_HEIGHT)
4ballRect = pygame.Rect(ballX, ballY, BALL_WIDTH_HEIGHT, BALL_WIDTH_HEIGHT)
<rectObject>=pygame.Rect(<x>,<e>,<largura>,<altura>)
104 capítulo 5
O método retorna um booleanoVerdadeirose o ponto dado está dentro do retângulo. Se
o usuário clicou na bola, selecionamos aleatoriamente novos valores para
bolaXebolaY.Usamos esses valores para criar um novo retângulo para a bola
no novo local aleatório.
A única mudança aqui é que sempre desenhamos a bola no local
dado pela tupla (bolaX, bolaY)7.O efeito é que sempre que o usuário clica
dentro do retângulo da bola, a bola parece se mover para algum novo
local aleatório na janela.
Manipulando o teclado
O próximo passo é permitir que o usuário controle algum aspecto do programa através do teclado.
Existem duas maneiras diferentes de lidar com as interações do teclado do usuário: quando uma tecla
individual é pressionada e quando um usuário mantém pressionada uma tecla para indicar que uma ação
deve ocorrer enquanto essa tecla estiver pressionada (conhecida comomodo contínuo).
Assim como os cliques do mouse, cada pressionamento de tecla gera dois eventos: tecla para baixo e tecla
Arquivo: PygameDemo3_MoveByKeyboard/PygameMoveByKeyboardOncePerKey.py
#1 - Importar pacotes
importar pygame
de pygame.locals import *
import sys
importar aleatório
#3 - Inicialize o mundo
pygame.init()
106 capítulo 5
Primeiro adicionamos algumas novas constantes1para definir as coordenadas
xey do canto superior esquerdo do retângulo de destino e a largura e altura do
destino. Em seguida, carregamos a imagem do retângulo alvo2.
No loop em que procuramos por eventos, adicionamos um teste para um pressionamento
de tecla verificando um evento do tipo pygame.KEYDOWN3.Se um evento de tecla pressionada for
detectado, analisamos o evento para descobrir qual tecla foi pressionada. Cada tecla tem uma
constante associada em pygame, então aqui verificamos se o usuário pressionou a seta para a
esquerda, para cima, para baixo ou para a direita. Para cada uma dessas chaves, modificamos o
valor da coordenada x ou y da bola apropriadamente por um pequeno número de pixels.
<booleanVariable>=<rect1>.colliderect(<rect2>)
<aTuplo>=pygame.key.get_pressed()
keyPressedTuple = pygame.key.get_pressed()
# Agora use uma constante para obter o elemento apropriado da tupla aIsDown =
keyPressedTuple[pygame.K_a]
Arquivo: PygameDemo3_MoveByKeyboard/PygameMoveByKeyboardContinuous.py
# pygame demo 3(b) - uma imagem, modo contínuo, mova enquanto uma tecla estiver pressionada
- - - recorte ---
# 7 - Verifique e manipule eventos para evento em pygame.event.get():
# Clicou no botão fechar? Saia do pygame e termine o programa if event.type
== pygame.QUIT:
pygame.quit()
sys.exit()
1keyPressedTuple = pygame.key.get_pressed()
if keyPressedTuple[pygame.K_UP]:#subindo
bolaY = bolaY - N_PIXELS_TO_MOVE
108 capítulo 5
A outra mudança é que essa abordagem permite verificar se várias chaves estão
inativas ao mesmo tempo. Por exemplo, se o usuário pressionar e segurar as teclas de seta
para a esquerda e para baixo, a bola se moverá diagonalmente para baixo e para a
esquerda. Você pode verificar quantas teclas estão sendo pressionadas conforme desejar.
No entanto, o número desimultâneopressionamentos de teclas que podem ser detectados
são limitados pelo sistema operacional, o hardware do teclado e muitos outros fatores. O
limite típico é de cerca de quatro chaves, mas sua milhagem pode variar.
Arquivo: PygameDemo4_OneBallBounce/PygameOneBallBounceXY.py
# pygame demo 4(a) - uma imagem, salte pela janela usando (x, y) coordenadas
#1 - Importar pacotes
importar pygame
de pygame.locals import *
import sys
importar aleatório
#3 - Inicialize o mundo
pygame.init()
janela = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
clock = pygame.time.Clock()
#5 - Inicialize as variáveis
Listagem 5-6: Uma animação baseada em localização, quicando uma bola pela janela
110 capítulo 5
e saísse da borda direita, mudaríamos o valor dexVelocidadea partir de3para
- 3fazer com que a bola comece a se mover para a esquerda e vice-versa. Em seguida, fazemos uma
Atributo Descrição
<correto>.x A coordenada x da borda esquerda doreto
<correto>.y A coordenada y da borda superior doreto
<correto>.deixei A coordenada x da borda esquerda doreto (igual a
<correto>.x)
<correto>.topo A coordenada y da borda superior doreto (igual a
<correto>.y)
<correto>.canto superior direito Uma tupla de dois inteiros: as coordenadas do canto superior direito
da reto
<correto>.canto inferior direito Uma tupla de dois inteiros: as coordenadas do canto inferior direito
da reto
(contínuo)
Atributo Descrição
<correto>.midtop Uma tupla de dois inteiros: as coordenadas do ponto médio da borda
superior doreto
Um pygameretotambém pode ser pensado e acessado como uma lista de quatro elementos.
Especificamente, você pode usar um índice para obter ou definir qualquer parte individual de um
reto.Por exemplo, usando obolaReto,os elementos individuais podem ser acessados como:
Arquivo: PygameDemo4_OneBallBounce/PygameOneBallBounceRects.py
# pygame demo 4(b) - uma imagem, salte pela janela usando rects
#1 - Importar pacotes
importar pygame
de pygame.locals import *
import sys
importar aleatório
112 capítulo 5
FRAMES_PER_SECOND = 30
N_PIXELS_PER_FRAME = 3
#3 - Inicialize o mundo
pygame.init()
janela = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
clock = pygame.time.Clock()
Listagem 5-7: Uma animação baseada em localização, quicando uma bola pela janela, usando retos
Tocando sons
Existem dois tipos de sons que você pode querer tocar em
seus programas: efeitos sonoros curtos e música de fundo.
Todos os efeitos sonoros devem estar em arquivos externos e devem estar em.ondaou
. oggformato. Tocar um efeito sonoro relativamente curto consiste em duas etapas: carregar
o som de um arquivo de som externo uma vez; então, no(s) momento(s) apropriado(s), toque seu som.
Para carregar um efeito sonoro na memória, você usa uma linha como esta:
<soundVariable>.Toque()
114 capítulo 5
Para reproduzir o efeito sonoro “boing” sempre que alteramos a direção
horizontal ou vertical da bola, modificamos a seção #8 para ficar assim:
Quando você encontra uma condição que deve reproduzir um efeito sonoro, você
adiciona uma chamada aoToque()método do som. Existem muitas outras opções para
controlar os efeitos sonoros; você pode encontrar detalhes na documentação oficial
emhttps:// www.pygame.org/docs/ref/mixer.html.
na memória:
o<caminho para o arquivo de som>é uma string de caminho onde o arquivo de som pode ser encontrado.
Você pode usar.mp3arquivos, que parecem funcionar melhor, bem como.ondaou.ogg arquivos. Quando
você deseja iniciar a reprodução da música, você precisa fazer esta chamada:
Para reproduzir uma música de fundo repetidamente, você pode passar um - 1por
<número de voltas>para executar a música para sempre. o<posição inicial>é normalmente
definido para0para indicar que você deseja reproduzir o som desde o início.
Existe uma versão modificada para download do programa quicando bola
que carrega corretamente o efeito sonoro e os arquivos de música de fundo e
inicia a reprodução do som de fundo. As únicas mudanças estão na seção #4,
conforme mostrado aqui.
Arquivo: PygameDemo4_OneBallBounce/PyGameOneBallBounceWithSound.py
Formas de desenho
O Pygame oferece várias funções integradas que permitem desenhar certas formas
conhecidas comoprimitivos, que incluem linhas, círculos, elipses, arcos, polígonos e
retângulos. A Tabela 5-2 fornece uma lista dessas funções. Observe que existem
duas chamadas que atraemanti-aliaslinhas. Estas são linhas que incluem cores
misturadas nas bordas para fazer com que as linhas pareçam suaves e menos
irregulares. Existem duas vantagens principais em usar essas funções de desenho:
elas são executadas com extrema rapidez e permitem que você desenhe formas
simples sem precisar criar ou carregar imagens de arquivos externos.
Função Descrição
pygame.draw.aaline() Desenha uma linha anti-alias
Arquivo: PygameDemo5_DrawingShapes.py
- - - recorte ---
enquanto Verdadeiro:
116 capítulo 5
# 8 - Faça qualquer ação "por frame"
# 9 - Limpe a janela
window.fill(CINZA)
# Desenha um arco
pygame.draw.arc(janela, AZUL, (20, 400, 100, 100), 0, 2, 5)
# Desenhe linhas com suavização de serrilhado: uma única linha, depois uma lista de pontos
pygame.draw.aaline(window, RED, (500, 400), (540, 470), 1) pygame.draw.aalines(window, BLUE, True,
((580, 400), (587, 450), (595,
460), (600, 444)), 1)
Listagem 5-8: Um programa para demonstrar chamadas para funções primitivas de desenho em pygame
Para sua referência, aqui está a documentação dos métodos pygame para desenhar
esses primitivos. Em todos os itens a seguir, o corO argumento espera que você
passe uma tupla de valores RGB:
Linha anti-alias
Linhas anti-alias
118 capítulo 5
Arco
Círculo
Elipse
Linha
Linhas
Polígono
Resumo
Neste capítulo, apresentei o básico do pygame. Você instalou o pygame em seu
computador, então aprendeu sobre o modelo de programação orientada a eventos e o
uso de eventos, que é muito diferente da codificação de programas baseados em
texto. Expliquei o sistema de coordenadas de pixels em uma janela e a forma como as
cores são representadas no código.
Para começar logo no início com o pygame, apresentei um modelo de 12 seções
que não faz nada além de abrir uma janela e pode ser usado para construir qualquer
programa baseado em pygame. Usando essa estrutura, construímos programas de
amostra que mostravam como desenhar uma imagem na janela (usando blit()), como
detectar eventos do mouse e como lidar com a entrada do teclado. A próxima
demonstração explicou como construir uma animação baseada em localização.
Retângulos são muito importantes no pygame, então eu abordei como os atributos de
umretoobjeto pode ser usado. Também forneci alguns códigos de exemplo para mostrar
como reproduzir efeitos sonoros e música de fundo para aumentar o prazer do usuário com
seus programas. Por fim, apresentei como usar os métodos pygame para desenhar formas
primitivas em uma janela.
Embora eu tenha introduzido muitos conceitos dentro do pygame,
quase tudo que mostrei neste capítulo foi essencialmente procedural. oreto
object é um exemplo de código orientado a objetos construído diretamente no pygame.
No próximo capítulo, mostrarei como usar OOP no código para usar o pygame de forma
mais eficaz.
120 capítulo 5
6
OBJEC T- ORIENTED YG AME
dentro de uma janela (Listagem 5-6, se você precisar refrescar sua memória).
Esse código funciona, mas os dados para a bola e o código para manipular a
bola estão interligados, o que significa que há muito código de inicialização, e o
código para atualizar e desenhar a bola está embutido na estrutura de 12 etapas.
O primeiro passo é criar uma pasta de projeto, na qual você precisa de umBall.py para
o novoBolaclass, o arquivo de código principalMain_BallBounce.py, e umimagens pasta
contendo obola.pngarquivo de imagem.
A Listagem 6-1 mostra o código do novoBolaclasse.
Arquivo: PygameDemo6_BallBounceObjectOriented/Ball.py
importar pygame
de pygame.locals import *
import random
122 Capítulo 6
2self.image = pygame.image.load('images/ball.png')
# Um rect é composto por [x, y, largura, altura] ballRect = self.image.get_rect()
self.width = ballRect.width self.height = ballRect.height self.maxWidth = windowWidth - self.width
self.maxHeight = windowHeight - self.height
5atualização def(self):
# Verifique se está batendo em uma parede. Se sim, mude essa direção. if
(self.x < 0) ou (self.x >= self.maxWidth):
self.xSpeed = -self.xSpeed
6def draw(self):
self.window.blit(self.image, (self.x, self.y))
Arquivo: PygameDemo6_BallBounceObjectOriented/Main_BallBounce.py
#1 - Importar pacotes
importar pygame
de pygame.locals import *
import sys
importar aleatório
1da importação de bola *# traz o código da classe Ball
FRAMES_PER_SECOND = 30
#3 - Inicialize o mundo
pygame.init()
janela = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
clock = pygame.time.Clock()
#5 - Inicialize as variáveis
2oBola = Bola(janela, WINDOW_WIDTH, WINDOW_HEIGHT)
# 8 - Faça qualquer ação "por frame" 3oBall.update()# diz para a Bola se atualizar
124 Capítulo 6
# 9 - Limpe a janela antes de desenhá-la novamente window.fill(PRETO)
Listagem 6-2: O novo programa principal que instancia um Bolae faz chamadas para seus métodos
Arquivo: PygameDemo6_BallBounceObjectOriented/Main_BallBounceManyBalls.py
- - - recorte ---
N_BOLAS = 3
- - - recorte ---
#5 - Inicialize as variáveis 1
bolaLista = []
para oBall no intervalo (0, N_BALLS):
# Cada vez que passar pelo loop, crie um objeto Ball oBola = Bola(janela,
WINDOW_WIDTH, WINDOW_HEIGHT)
- - - recorte ---
código OOP: classes bem escritas geralmente podem ser reutilizadas sem alterações.
Podemos alterar o valor da constanteN_BOLASa partir de3para algum valor muito maior,
como300,para criar rapidamente essa quantidade de bolas (Figura 6-1). Alterando
apenas uma única constante, fazemos uma grande mudança no comportamento do
programa. Cada bola mantém sua própria velocidade e localização e se desenha.
126 Capítulo 6
Figura 6-1: Criando, atualizando e desenhando 300 Bolaobjetos
O comportamento do botão deve ser comum e consistente para todos os botões usados em uma
GUI, portanto, construiremos uma classe que cuide dos detalhes do comportamento. Uma vez
que criamos uma classe de botão simples, podemos instanciar qualquer número de botões e
todos eles funcionarão exatamente da mesma maneira.
Vamos considerar quais comportamentos nossa classe de botão deve suportar. Vamos precisar
de métodos para:
Arquivo: PygameDemo7_SimpleButton/SimpleButton.py
# classe SimpleButton
#
# Usa uma abordagem de "máquina de estado"
#
importar pygame
da importação de pygame.locals *
class SimpleButton():
# Usado para rastrear o estado do botão
STATE_IDLE = 'ocioso'# botão está para cima, o mouse não está sobre o botão
STATE_ARMED = 'armado'# botão está pressionado, passe o mouse sobre o botão
STATE_DISARMED = 'desarmado'# clicou no botão, saiu
128 Capítulo 6
self.surfaceDown = pygame.image.load(down)
# Pega o retículo do botão (usado para ver se o mouse está sobre o botão) self.rect =
self.surfaceUp.get_rect() self.rect[0] = loc[0]
self.rect[1] = loc[1]
self.state = SimpleButton.STATE_IDLE
eventPointInButtonRect = self.rect.collidepoint(eventObj.pos)
if self.state == SimpleButton.STATE_IDLE:
if (eventObj.type == MOUSEBUTTONDOWN) e eventPointInButtonRect:
self.state = SimpleButton.STATE_ARMED
retorna falso
def draw(self):4
# Desenha a aparência atual do botão para a janela if self.state == SimpleButton.STATE_ARMED:
self.window.blit(self.surfaceDown, self.loc)
Esta linha cria umBotão Simplesobjeto, especificando um local para desenhá-lo (como
sempre, as coordenadas são para o canto superior esquerdo do retângulo delimitador) e
fornecendo os caminhos para as imagens para cima e para baixo do botão. No loop
principal, sempre que qualquer evento acontecer, precisamos chamar o handleEvent() para
ver se o usuário clicou no botão. Se o usuário clicar no botão, o programa
deverá realizar alguma ação. Também no loop principal, precisamos chamar
oempate()método para fazer o botão aparecer na janela.
Figura 6-2: A interface do usuário de um programa com uma única instância de umBotão Simples
Arquivo: PygameDemo7_SimpleButton/Main_SimpleButton.py
- - - recorte ---
#5 - Inicialize as variáveis
# Cria uma instância de um SimpleButton
130 Capítulo 6
1oButton = SimpleButton(janela, (150, 30),
'imagens/buttonUp.png',
'imagens/buttonDown.png')
# 9 - Limpe a janela
window.fill(CINZA)
Não precisamos fazer nenhuma alteração no Botão Simplesarquivo de classe para fazer isso.
Simplesmente modificamos nosso código principal para instanciar três Botão Simples
objetos em vez de um.
Arquivo: PygameDemo7_SimpleButton/Main_SimpleButton3Buttons.py
oButtonA.draw()
oButtonB.draw()
oButtonC.draw()
Ao executar o programa, você verá uma janela com três botões. Clicar em
qualquer um dos botões imprime uma mensagem mostrando o nome do botão
que foi clicado.
A ideia chave aqui é que, como estamos usando três instâncias do
mesmo Botão Simplesclasse, o comportamento de cada botão será idêntico. Um
benefício importante dessa abordagem é que qualquer alteração no código no
Botão Simplesclasse afetará todos os botões instanciados da classe. O
programa principal não precisa se preocupar com nenhum detalhe do
funcionamento interno do código do botão, precisando apenas chamar
ohandleEvent()método de cada botão no loop principal. Cada botão
retornaráVerdadeiroouFalsopara dizer que foi ou não clicado.
132 Capítulo 6
Construindo uma exibição de texto reutilizável orientada a objetos
Existem dois tipos diferentes de texto em um programa pygame: texto de exibição e texto de
entrada. O texto de exibição é gerado pelo seu programa, equivalente a uma chamada para o
imprimir()função, exceto que é exibido em uma janela pygame. O texto de entrada é uma string
de entrada do usuário, equivalente a uma chamada para entrada().Nesta seção, discutirei o
texto de exibição. Veremos como lidar com o texto de entrada no próximo capítulo.
pygame.font.init()
Arquivo: PygameDemo8_SimpleTextDisplay/SimpleText.py
# classe SimpleText
importar pygame
da importação de pygame.locals *
5def draw(self):
self.window.blit(self.textSurface, self.loc)
Você pode pensar em umTexto Simplesobjeto como um campo na janela onde você
deseja que o texto seja exibido. Você pode usar um para exibir texto de etiqueta imutável
ou para exibir texto que muda ao longo de um programa.
oTexto Simplesclasse tem apenas três métodos. O __iniciar__()método1 espera
que a janela seja desenhada, o local no qual desenhar o texto na janela, qualquer
texto inicial que você deseja ver exibido no campo e uma cor de texto. Ligando
pygame.font.init()2inicia o sistema de fontes do pygame. A chamada na primeira
instanciadaTexto Simplesobjeto realmente faz a inicialização; qualquer
adicionalTexto Simplesobjetos também farão esta chamada, mas como as fontes já
foram inicializadas, a chamada retorna imediatamente. Criamos um novo Fonte
objeto compygame.font.SysFont()3.Em vez de fornecer um nome de fonte específico,
Nenhumindica que usaremos qualquer que seja a fonte padrão do sistema.
osetValue()O método renderiza uma imagem do texto a ser exibido e salva
essa imagem noself.textSurfacevariável de instância4.À medida que o programa é
executado, sempre que você quiser alterar o texto exibido, você chama osetValue()
método, passando o novo texto a ser exibido. osetValue()O método também tem
uma otimização: ele lembra o último texto que renderizou e, antes de fazer
qualquer outra coisa, verifica se o novo texto é igual ao texto anterior. Se o texto
não mudou, não há nada a fazer e o método apenas retorna. Se houver novo
texto, ele renderiza o novo texto em uma superfície a ser desenhada.
oempate()método5desenha a imagem contida noself.textSurface
variável de instância na janela no local fornecido. Este método deve
ser chamado em cada frame.
Existem várias vantagens nessa abordagem:
134 Capítulo 6
• CadaTexto SimplesO objeto lembra a janela na qual ele desenha, o local
onde o texto deve ser colocado e a cor do texto. Portanto, você só precisa especificar
esses valores uma vez, ao instanciar um
Texto Simplesobjeto, normalmente antes do início do loop principal.
• CadaTexto SimplesO objeto também é otimizado para lembrar tanto o texto que foi
solicitado a desenhar pela última vez quanto a imagem (self.textSurface)que fez a partir do texto atual.
Ele só precisa renderizar uma nova superfície quando o texto muda.
• Para mostrar vários pedaços de texto em uma janela, você só precisa instanciar
váriosTexto Simplesobjetos. Este é um conceito chave da programação orientada a objetos.
Arquivo: PygameDemo8_SimpleTextDisplay/Main_BallTextAndButton.py
#1 - Importar pacotes
importar pygame
de pygame.locals import *
import sys
importar aleatório
1da importação de bola *# traz o código da classe Ball
da importação SimpleText * da
importação SimpleButton *
# 2 - Definir constantes PRETO = (0, 0, 0) BRANCO = (255, 255, 255) WINDOW_WIDTH = 640
WINDOW_HEIGHT = 480
FRAMES_PER_SECOND = 30
#3 - Inicialize o mundo
pygame.init()
janela = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
clock = pygame.time.Clock()
#5 - Inicialize as variáveis
2oBola = Bola(janela, WINDOW_WIDTH, WINDOW_HEIGHT)
oFrameCountLabel = SimpleText(janela, (60, 20),
'O programa passou por tantos loops: ', BRANCO)
3if oRestartButton.handleEvent(evento):
contador de quadros = 0# botão clicado, reset do contador
# 8 - Faça qualquer ação "por frame" 4oBall.update()# diz para a bola se atualizar
contador de quadros = contador de quadros + 1# incrementa
cada frame 5oFrameCountDisplay.setValue(str(frameCounter))
Listagem 6-7: Um exemplo de programa principal para mostrarBola,Texto Simples, eBotão Simples
136 Capítulo 6
Na instanciação doTexto Simplesobjetos, o último argumento é uma cor de
texto e especificamos que os objetos devem ser renderizados em BRANCOpara
que possam ser vistos contra umPRETOfundo. No próximo capítulo, mostrarei
como expandir oTexto Simplesclass para incorporar mais atributos, sem complicar
a interface da classe. Construiremos um objeto de texto mais completo que tenha
valores padrão razoáveis para cada um desses atributos, mas que permita
substituir esses padrões.
Retornos de chamada
ligue de volta Uma função ou método de um objeto que é chamado quando uma determinada ação, evento ou
condição acontece
Uma maneira fácil de entender isso é pensar no filme de sucesso de 1984 Caça-
fantasmas. O slogan do filme é “Quem você vai chamar?” No filme, os Caça-Fantasmas
veicularam um anúncio na TV que dizia às pessoas que, se vissem um fantasma (esse é o
evento a ser procurado), deveriam ligar para os Caça-Fantasmas (o retorno de chamada)
para se livrar dele. Ao receber a chamada, os Caça-Fantasmas tomam as medidas
apropriadas para eliminar o fantasma.
Como exemplo, considere um objeto de botão que é inicializado para ter um
retorno de chamada. Quando o usuário clicar no botão, o botão chamará a função ou
método de retorno de chamada. Essa função ou método executa qualquer código
necessário para reagir ao clique do botão.
def minhaFunção():
print('myCallBackFunction foi chamado')
138 Capítulo 6
fora disso. Isso geralmente envolve vários encadeamentos Python e está além do
escopo deste livro, mas a técnica de usar um retorno de chamada é a maneira geral
como isso é feito.
Arquivo: PygameDemo9_SimpleButtonWithCallback/Main_SimpleButtonCallback.py
#1 - Importar pacotes
importar pygame
from pygame.locals import *
from SimpleButton import *
import sys
FRAMES_PER_SECOND = 30
# Definir uma classe com um método a ser usado como "callback" class CallBackTest():2
- - - cortou quaisquer outros métodos nesta classe ---
def meuMétodo(self):
print('O usuário pressionou ButtonC, chamado myMethod do objeto CallBackTest')
#3 - Inicialize o mundo
pygame.init()
janela = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
clock = pygame.time.Clock()
oButtonC.handleEvent(evento)7
Listagem 6-8: Uma versão do programa principal que lida com cliques de botão de três maneiras diferentes
140 Capítulo 6
Começamos com uma função simples, myCallBackFunction()1,que apenas imprime uma
mensagem para anunciar que foi chamado. A seguir, temos um Teste de retorno de chamada
classe que contém o métodomeuMétodo()2,que imprime sua própria mensagem para anunciar que foi
chamado. Nós criamos umoCallBackTestobjeto doTeste de retorno de chamadaclasse3.Precisamos deste
objeto para que possamos configurar um retorno de chamada para
oCallBack.myMethod().
Então criamos trêsBotão Simplesobjetos, cada um usando uma abordagem
diferente4.O primeiro,oBotãoA,não tem retorno de chamada. O segundo, oBotãoB,define seu
retorno de chamada para a funçãomyCallBackFunction().O terceiro,oBotãoC,define seu
retorno de chamada paraoCallBack.myMethod().
No loop principal, verificamos se o usuário está clicando em qualquer um
dos três botões chamando ohandleEvent()método de cada botão. DesdeoBotãoA
não tem retorno de chamada, devemos verificar se o valor retornado é Verdadeiro5e, em caso
afirmativo, execute uma ação. Quando oBotão Bé clicado6,amyCallBackFunction()
será chamada e imprimirá sua mensagem. Quando oBotãoCé clicado7,
a meuMétodo()método dooCallBackTestobjeto será chamado e imprimirá
sua mensagem.
Alguns programadores preferem usar uma abordagem de retorno de chamada,
porque o destino a ser chamado é configurado quando você cria o objeto. É
importante entender essa técnica, especialmente se você estiver usando um pacote
que a exija. No entanto, usarei a abordagem original de verificar o valor retornado por
uma chamada parahandleEvent()em todo o meu código de demonstração.
Resumo
Neste capítulo, mostrei como você pode começar com um programa procedural e
extrair o código relacionado para construir uma classe. Nós criamos umBolaclass para
demonstrar isso, então modifiquei o código principal do nosso programa de
demonstração do capítulo anterior para chamar métodos da classe para informar oBola
objetoo quefazer, sem se preocuparComo asatinge o resultado. Com todo o código
relacionado em uma classe separada, é fácil criar uma lista de objetos e instanciar e
gerenciar quantos objetos quisermos.
Construímos então umBotão Simplesclasse e umTexto Simplesclasse que escondem a
complexidade dentro de sua implementação e criam código altamente reutilizável. No
próximo capítulo, desenvolverei essas classes para desenvolver classes de exibição de
texto e botões de “força profissional”.
Finalmente, apresentei o conceito de callback, onde você passa uma função ou método em
uma chamada para um objeto. O retorno de chamada é posteriormente chamado de volta quando
um evento acontece ou uma ação é concluída.
Figura 7-1: Como os argumentos passados para um método correspondem aos seus parâmetros
No entanto, o Python (e algumas outras linguagens) permite que você torne alguns
dos argumentos opcionais. Se um argumento opcional não for fornecido em uma chamada,
podemos fornecer um valor padrão para usar na função ou método. Vou explicar por meio
de uma analogia do mundo real.
Se você pedir um hambúrguer em um restaurante Burger King, seu
hambúrguer virá com ketchup, mostarda e picles. Mas o Burger King é
famoso por dizer: “Você pode fazer do seu jeito”. Caso queira alguma
outra combinação de condimentos, deve dizer o que quer (ou não quer)
ao fazer seu pedido.
Começaremos escrevendo umpedirBurgers()função que simula fazer
um pedido de hambúrguer da maneira normal que definimos funções,
sem implementar valores padrão:
def orderBurgers(nBurgers, ketchup, mostarda, picles):
Vamos ver como o Python nos permite configurar parâmetros opcionais que
podem receber valores padrão se nada for especificado.
144 Capítulo 7
Parâmetros posicionais e de palavra-chave
pedirHambúrgueres(2)
orderBurgers(2, mostarda=Falso)
ou:
O chamador deve especificar um sabor, mas por padrão receberá uma colher em
um cone sem granulado. O chamador pode substituir esses padrões com valores de
palavra-chave diferentes.
146 Capítulo 7
o chamador pode opcionalmente passar em uma única cobertura desejada. Se o
chamador quiser uma cobertura, devemos cobrar extra.
Na Listagem 7-1, usaremos um parâmetro posicional para oTamanhoe
parâmetros de palavras-chave para oestiloecobertura.O padrão paraestiloé a corda
'regular'. Como a escolha de cobertura é opcional, usaremos o valor especial do
Python deNenhumcomo o padrão, mas o chamador pode passar a cobertura de
sua escolha.
Arquivo: OrderPizzaWithNone.py
se tamanho == 'pequeno':
preço = 10,00
elif tamanho == 'médio':
preço = 14,00
senão:# ampla
preço = 18,00
if estilo == 'deepdish':
preço = preço + 2,00# cobra extra pelo deepdish
line = 'Você pediu uma ' + tamanho + ' ' + estilo + ' pizza com ' 1se a
cobertura for Nenhum:# verifica se nenhuma cobertura foi passada
print(linha + 'sem cobertura')
else:
print(linha + cobertura)
preço = preço + PRICE_OF_TOPPING
O uso de valores padrão torna a chamada de funções e métodos mais simples, mas há uma
desvantagem. Sua escolha de cada palavra-chave para parâmetros de palavras-chave é
muito importante. Depois que os programadores começam a fazer chamadas que
substituem os valores padrão, é muito difícil alterar o nome de um parâmetro de palavra-
chave porque esse nome deve ser alterado emtudochamadas para a função ou método em
lockstep. Caso contrário, o código que estava funcionando irá quebrar. Para código mais
amplamente distribuído, isso pode causar muita dor aos programadores que usam seu
código. Resumindo, não altere o nome de um parâmetro de palavra-chave a menos que seja
absolutamente necessário. Então, escolha sabiamente!
Também é muito importante usar valores padrão que devem atender a maior variedade
possível de usuários. (Em uma nota pessoal, euodiarmostarda! Sempre que vou ao Burger
King, tenho que me lembrar de não especificar mostarda ou compro o que considero um
hambúrguer intragável. Eu acho que eles fizeram uma má escolha padrão.)
Na próxima seção, apresentarei uma coleção de classes que você pode usar para criar
facilmente elementos GUI, como botões e campos de texto dentro do pygame. Essas
classes serão inicializadas usando alguns parâmetros posicionais, mas também terão
vários parâmetros de palavras-chave opcionais, todos com padrões razoáveis para permitir
que os programadores criem widgets GUI especificando apenas alguns argumentos
posicionais. Um controle mais preciso pode ser obtido especificando valores para
substituir os valores padrão dos parâmetros de palavras-chave.
Para um exemplo aprofundado, veremos um widget para exibir texto na janela do
aplicativo. O texto pode ser mostrado em uma variedade de fontes, tamanhos de fonte,
cores, cores de fundo e assim por diante. Nós vamos construir um Texto de exibiçãoclasse
que terá valores padrão para todos esses atributos, mas dará ao código do cliente a
opção de especificar valores diferentes.
O pacote pygwidgets
O restante deste capítulo se concentrará napygwidgets (pronunciado
“pig wijits”), que foi escrito com dois objetivos em mente:
Botão personalizado
148 Capítulo 7
TextCheckBox
Caixa de seleção com arte padrão, construída a partir de uma string de texto
TextRadioButton
Botões de rádio com arte padrão, construídos a partir de uma string de texto
Texto de exibição
Entrada de texto
Arrasta
Imagem
Coleção de imagens
Animação
SpriteSheetAnimation
Exibe uma sequência de imagens de uma única imagem maior
Configurando
importar widgets
Conforme mostrado no Capítulo 5, uma das primeiras coisas que você faz em
todo programa pygame é definir a janela do aplicativo. A linha a seguir cria uma
janela do aplicativo e salva uma referência a ela em uma variável chamada janela:
O passo 1 para usar qualquer widget é instanciar um com uma linha como esta:
pressionado) acontecer e o widget manipular o evento, esta chamada retornará Verdadeiro.O código no topo
da página principalenquantoloop geralmente se parece com isso:
enquanto Verdadeiro:
if oWidget.handleEvent(evento):
# O usuário fez algo no oWidget que devemos responder
# Adicione o código aqui
O passo 3 é adicionar uma linha perto da parte inferior do enquantoloop para chamar o
empate()método do widget, para fazê-lo aparecer na janela:
oWidget.draw()
150 Capítulo 7
Como especificamos a janela para desenhar, o local e todos os
detalhes que afetam a aparência do widget na etapa 1, não passamos
nada na chamada paraempate().
oImage.draw()
oImage.setLoc((novoX, novoY))
Na próxima vez que a imagem for desenhada, ela aparecerá nas novas coordenadas.
A documentação lista muitos métodos adicionais que você pode chamar para inverter,
girar, dimensionar, obter a localização e o retângulo da imagem e assim por diante.
O MÓDULO SPRITE
O Pygame possui um módulo embutido para mostrar imagens em uma janela, chamado de
módulo sprite . Tais imagens são chamadasduendes . O módulo sprite fornece umSprite
classe para lidar com sprites individuais e um Grupoclasse para lidar com vários
Spriteobjetos. Juntas, essas classes fornecem excelente funcionalidade e, se você
pretende fazer programação pygame pesada, provavelmente vale a pena dar uma
olhada nelas. No entanto, para explicar os conceitos de POO subjacentes, optei por
não usar essas classes. Em vez disso, continuarei com os elementos gerais da GUI
para que possam ser usados em qualquer ambiente e linguagem Se você quiser
aprender mais sobre o módulo sprite, veja o tutorial
emhttps://www.pygame.org/docs/tut/ SpriteIntro.html
Quando você instancia um botão, caixa de seleção ou widget de botão de opção em pygwidgets,
você tem duas opções: instanciar uma versão de texto que desenha sua própria arte e adiciona um
rótulo de texto com base em uma string que você passa ou instanciar uma versão personalizada
onde você fornece a arte. A Tabela 7-1 mostra as diferentes classes de botões disponíveis.
Botões de texto
Você também pode visualizar a documentação de uma classe chamando o built-in ajuda()
função no shell Python assim:
152 Capítulo 7
Quando você cria uma instância de umTextButton,você só precisa passar
na janela, o local na janela e o texto a ser mostrado no botão. Se você
especificar apenas esses parâmetros posicionais, seu botão usará padrões
razoáveis para largura e altura, as cores de fundo para os quatro estados do
botão (diferentes tons de cinza), a fonte e o tamanho da fonte. Por padrão,
nenhum efeito sonoro será reproduzido quando o usuário clicar no botão.
O código para criar umTextButtonusando todos os padrões fica assim:
palavra-chave como:
Botões personalizados
oBotão personalizadoclass permite que você use sua própria arte para um botão.
Para instanciar umbotão personalizado,você só precisa passar uma janela, um local
e um caminho para a imagem do estado ativo do botão. Aqui está um exemplo:
Aqui também especificamos um efeito sonoro que deve ser reproduzido quando o
usuário clica no botão e fornecemos um apelido interno que podemos usar mais tarde.
Usando botões
enquanto Verdadeiro:
if oButton.handleEvent(evento):
# O usuário clicou neste botão
<Qualquer código que você queira executar aqui quando o botão for clicado>
- - - recorte ---
oButton.draw()# na parte inferior do loop while, diga para desenhar
Como vimos no Capítulo 6, lidar com entrada e saída de texto no pygame é complicado,
mas aqui apresentarei novas classes para um campo de exibição de texto e um campo de
texto de entrada. Ambas as classes têm parâmetros mínimos necessários (posicionais) e
têm padrões razoáveis para outros atributos (fonte, tamanho da fonte, cor e assim por
diante) que são facilmente substituídos.
Saída de texto
154 Capítulo 7
instanciar umTexto de exibiçãocampo, os únicos argumentos necessários são a janela e o
local. O primeiro parâmetro de palavra-chave évalor,que pode ser especificado com uma
string como texto inicial a ser mostrado no campo. Isso normalmente é usado para um
valor de usuário final padrão ou para texto que nunca muda, como um rótulo ou
instruções. Desde valoré o primeiro parâmetro de palavra-chave, ele pode ser fornecido
como um argumento posicional ou de palavra-chave. Por exemplo, isso:
oTextField.draw()
E, claro, você pode criar quantosTexto de exibiçãoobjetos como desejar, cada um exibindo um
texto diferente e cada um com sua própria fonte, tamanho, cor e assim por diante.
Entrada de texto
enquanto Verdadeiro:
if oInputField.handleEvent(evento):
# O usuário pressionou Enter ou Return
userText = oInputField.getValue() # pega o texto que o usuário digitou
<Qualquer código que você deseja executar usando a entrada do usuário>
- - - recorte ---
oInputField.draw()# na parte inferior do loop while principal
método do objeto.
Na parte inferior do principalenquantoloop, precisamos chamar oempate()método
para permitir que o campo se desenhe.
Se uma janela contiver vários campos de entrada, as teclas pressionadas serão tratadas
pelo campo com o foco atual do teclado, que é alterado quando um usuário clica em um campo
diferente. Se você deseja permitir que um campo tenha o foco inicial do teclado, você pode definir
ofoco inicialparâmetro de palavra-chave paraVerdadeironoEntrada de texto
objeto de sua escolha ao criar esse objeto. Além disso, se você tiver vários Entrada
de textocampos em uma janela, uma abordagem típica de design de interface do
usuário é incluir um botão OK ou Enviar. Quando este botão é clicado, você pode
chamar oObter valor()método de cada campo.
156 Capítulo 7
NOTA No momento da redação, oEntrada de textoclass não lida com o realce de vários caracteres arrastando
o mouse. Se essa funcionalidade for adicionada em uma versão posterior, nenhuma alteração será
necessária nos programas que usamEntrada de textoporque o código estará inteiramente dentro
dessa classe. Qualquer novo comportamento será suportado automaticamente em todos
Entrada de textoobjetos.
A Figura 7-4 mostra uma captura de tela de um programa de exemplo que demonstra
objetos instanciados de muitas das classes em pygwidgets,IncluindoImagem,
DisplayText, InputText, TextButton, CustomButton, TextRadioButton,
CustomRadioButton, TextCheckBox, CustomCheckBox, ImageCollection, eArrastador.
A fonte deste programa de exemplo pode ser encontrada nopygwidgets_test
pasta no meu repositório GitHub,https://github.com/IrvKalb/pygwidgets/.
sobre por que esse tipo de consistência é tão importante nos próximos dois capítulos.
Resumo
Este capítulo forneceu uma introdução à orientação a objetospygwidgets
pacote de widgets de interface gráfica do usuário. Começamos discutindo valores padrão
para parâmetros em métodos e expliquei que um parâmetro de palavra-chave permite que
um valor padrão seja usado se nenhum valor de argumento correspondente for especificado
em uma chamada.
158 Capítulo 7
Em seguida, apresentei-lhe opygwidgetsmódulo, que contém várias
classes de widgets GUI pré-construídas e mostrou como usar várias delas.
Por fim, mostrei um programa de amostra que fornece exemplos da maioria
desses widgets.
Há duas vantagens principais em escrever aulas como as de pygwidgets. Primeiro, as
classes podem ocultar a complexidade dos métodos. Depois de ter sua aula funcionando
corretamente, você nunca mais precisará se preocupar com os detalhes internos.
Segundo, você pode reutilizar o código criando quantas instâncias de uma classe forem
necessárias. Suas classes podem fornecer funcionalidade básica incluindo parâmetros de
palavras-chave com valores padrão bem escolhidos. No entanto, os valores padrão
podem ser facilmente substituídos para permitir a personalização.
Você pode publicar as interfaces de suas classes para que outros
programadores (e você mesmo) aproveitem em diferentes projetos. Uma
boa documentação e consistência ajudam bastante a tornar esses tipos de
classes altamente utilizáveis.