Enviar um café pro programador

Mostrando postagens com marcador Event Handling. Mostrar todas as postagens
Mostrando postagens com marcador Event Handling. Mostrar todas as postagens

Tratamento de Eventos com Mouse

Neste tutorial, vamos criar um programa para usar, ao mesmo tempo, 5 tratamento de eventos envolvendo mouse, como clicar, soltar e arrastar.

Event Handler com mouse em programação gráfica em Python

Eventos com Mouse: <ButtonRelease-1> e <B1-Motion>

Vamos te mostrar como criar um programa que detecta se o mouse está dentro da janela, se está fora, se você clicou em algum ponto, soltou e arrastou, bem como mostra as coordenadas em pixels desses eventos.

Para isso, vamos usar 5 eventos:
  1. <Button-1> - Botão 1 do mouse (mais a esquerda) é pressionado
  2. <ButtonRelease-1> - Botão 1 é liberado (released)
  3. <Enter> - Mouse entrou no frame (janela)
  4. <Leave> - Mouse deixou o frame da janela
  5. <B1-Motion> - Botão 1 do mouse foi arrastado (clicar e segurar)

Desses cinco, dois são novos: o <ButtonRelease-1> e o <B1-Motion>, mas bem fáceis de entender com a explicação do programa, a seguir.

Vamos lá, inicialmente criamos nossa classe MouseEvent, que herda a Frame, logo é um frame.
Inicializamos a classe master (Frame.__init__), depois empacotamos o frame, definimos um título e seu tamanho.

Depois, vamos criar o objeto StringVar(), que vai ser um label que dinâmico, que vai ficar variando e mudando de valor (alterando seu texto). Inicialmente, definimos o texto "Mouse fora da janela" para ele.

Depois, criamos nosso Label, com o parâmetro textvariable recebendo o objeto StringVar.

Agora vamos fazer os binds.
O primeiro, <Button-1>, chama o método botaoPressionado, que recebe o evento do clique e mostra sua posição através dos atributos event.x e event.y, no label.

O segundo bind é com o evento <ButtonRelease-1>, que chama o método botaoLiberado que faz o mesmo do método anterior, mas mostra onde você soltou o botão do mouse.

Depois vem o <Enter> e o <Leave>, eventos que já estudamos, que identificam se o mouse entrou ou saiu do widget em questão, no caso, o frame.


Por fim, o bind com o evento <B1-Motion>, que vai identificar até onde o mouse estará sendo arrastado (clicar, segura e se mover).

Veja como ficou nosso código Python:


from tkinter import *

class MouseEvent( Frame ):
 def __init__( self ):
  # Criando o frame, título e tamanho
  Frame.__init__( self )
  self.pack( expand = YES, fill = BOTH )
  self.master.title( "Eventos com Mouse" )
  self.master.geometry( "300x200" )
  
  # String com a posição do mouse
  self.mousePosicao = StringVar()
  self.mousePosicao.set( "Mouse fora da janela" )
  
  # Criando e posicionando o label embaixo
  self.positionLabel = Label( self,textvariable = self.mousePosicao )
  self.positionLabel.pack( side = BOTTOM )
  
  # Criando os binds com os eventos de mouse
  self.bind( "<Button-1>", self.botaoPressionado )
  self.bind( "<ButtonRelease-1>", self.botaoLiberado )
  self.bind( "<Enter>", self.entrouJanela )
  self.bind( "<Leave>", self.saiuJanela )
  self.bind( "<B1-Motion>", self.mouseArrastado )
  
  mainloop()
  
 def botaoPressionado( self, event ):
  self.mousePosicao.set( "Pressionado em [ " + str( event.x ) +
        ", " + str( event.y ) + " ]" )
 def botaoLiberado( self, event ):
  self.mousePosicao.set( "Solto em [ " + str( event.x ) +
        ", " + str( event.y ) + " ]" )
 def entrouJanela( self, event ):
  self.mousePosicao.set( "Mouse na janela )
 def saiuJanela( self, event ):
  self.mousePosicao.set( "Mouse fora da janela" )
 def mouseArrastado( self, event ):
  self.mousePosicao.set( "Arrastado até [ " + str( event.x ) +
        ", " + str( event.y ) + " ]" )
  
# Chamando a classe
MouseEvent()

O evento < Return > : Apertando Enter

Neste tutorial, vamos aprender como lidar e tratar o evento de pressionar a tecla enter do teclado, através do <Return> event.

Através de um programinha simples, vamos entender o que ocorre por trás dos panos quando você digita a tecla enter do seu teclado e algo acontece em um programa.



<Return> event - Pressionar tecla enter

Sem mais delongas, vamos criar a seguinte aplicação:

Evento de dar enter

Na janelinha principal, exibimos um widget do tipo Entry de entrada de dados.
Você digita algo e dá enter.


Ao fazer isso, vai abrir uma nova janela, com o nome do widget e o conteúdo que está dentro dele.
Vamos te mostrar o código, e logo abaixo, a explicação:

from tkinter import *
from tkinter import messagebox

class EntryTeste( Frame ):
 def __init__( self ):
  # Inicializando configurações do frame
  Frame.__init__(self)
  self.pack()
  self.master.title( "<Return> teste" )
  self.master.geometry( "300x50" )
  self.frame = Frame( self )
  self.frame.pack( pady = 5 )
  
  # Criando a caixa de entrada
  self.caixa = Entry( self.frame, name = "caixa1" )
  
  # Fazendo o bind dela com o event handler exibe() 
  self.caixa.bind( "<Return>", self.exibe )
  self.caixa.pack( side = LEFT, padx = 5 )
  
  # Looping pra rodar a GUI
  self.mainloop()
  
 # Event handler
 def exibe(self, event):
  nomeCaixa = event.widget.winfo_name()
  conteudoCaixa = event.widget.get()
  messagebox.showinfo( "Texto na caixa", "Nome do widget: " + nomeCaixa + "\nConteúdo: " + conteudoCaixa )
  
# Criando um objeto
minhaGui = EntryTeste()

A classe onde toda mágica vai acontecer se chama EntryTeste() e ela herda a classe Frame.
Ou seja, ela é um frame também, ela vai ser a janela principal.

Iniciamos o método construtor chamando o construtor da classe base, e em seguida se empacotando.
Com o método master.title(string) definimos o título da janelinha que vai abrir.
Com o método master.geometry("largura x comprimento") definimos o tamanho do frame.

Depois, criamos o frame frame1 que vai ser o container da caixa de entrada, e empacotamos ele com o espaçamento vertical (pad y) de 5 pixels.


Vamos criar a caixa de entrada, objeto de nome caixa do tipo Entry, vamos dar o nome de caixa1 pra esse widget.

Agora vem a parte mais importante, o bind.
Vamos ligar o evento <Return>, que representa o ato de apertar o enter com o event handler de nome exibe, que é um método que será chamado sempre que você der enter.

Esse método recebe o objeto event.
Vamos extrair algumas informações interessantes desse objeto.

Vamos usar: event.widget.winfo_name() pra pegar o nome do widget
E também: event.widget.get() pra pegar o conteúdo que foi digitado na caixa de entrada.

Em seguida, esse método, que é nosso event handler (tratador de eventos), vai exibir uma caixa de diálogo com essas duas informações: nome do widget e conteúdo que você escreveu nele, antes de dar enter.
Conseguiram entender?

Quebrando a cabeça

Não tenha vergonha de ter que ler, reler, quebrar a cabeça, mexer uma coisa aqui, alterar outra ali.
Faz parte do aprendizado.

Rode o código a seguir, e tente entender linha por linha o que está acontecendo.
Se tiver dúvida de algo, não existe em pesquisar no Google, todo programador faz isso, sempre, pro resto da vida, mesmo os melhores do mundo.


from tkinter import *
from tkinter import messagebox

class EntryTeste( Frame ):
 def __init__( self ):
  # Inicializando os frames, títulos e tamanhos
  Frame.__init__( self )
  self.pack( expand = YES, fill = BOTH )
  self.master.title( "Componentes de entrada" )
  self.master.geometry( "325x100" ) # width x length
  
  # Criando o primeiro frame que vai armazenar
  # as duas primeiras caixas de entrada
  self.frame1 = Frame( self )
  self.frame1.pack( pady = 5 )
  
  # Criando a primeira caixa de entrada
  self.text1 = Entry( self.frame1, name = "caixa1" )
  
  # Associando o evento <Return> com o
  # event handler exibe()
  self.text1.bind( "<Return>", self.exibe )
  self.text1.pack( side = LEFT, padx = 5 )
  
  # Criando a segunda caixa e seu bind
  self.text2 = Entry( self.frame1, name = "caixa2" )
  self.text2.insert( INSERT, "Digite um texto aqui" )
  self.text2.bind( "<Return>", self.exibe )
  self.text2.pack( side = LEFT, padx = 5 )
  
  # Segundo frame, com as duas outras caixas
  self.frame2 = Frame( self )
  self.frame2.pack( pady = 5 )
  
  # Criando a caixa que não dá pra editar
  self.text3 = Entry( self.frame2, name = "caixa3" )
  self.text3.insert( INSERT, "Texto ineditável" )
  self.text3.config( state = DISABLED )
  self.text3.bind( "<Return>", self.exibe )
  self.text3.pack( side = LEFT, padx = 5 )
  
  # Criando a caixa estilo senha
  self.text4 = Entry( self.frame2, name = "caixa4", show = "*" )
  self.text4.insert( INSERT, "Texto escondido" )
  self.text4.bind( "<Return>", self.exibe )
  self.text4.pack( side = LEFT, padx = 5 )
  
  mainloop()
 
 def exibe( self, event ):
  # Pegando o nome do widget
  nomeCaixa = event.widget.winfo_name()
  # Pegando o conteúdo do widget
  conteudoCaixa = event.widget.get()
  messagebox.showinfo( "Texto na caixa", nomeCaixa + ": " + conteudoCaixa )
  
# Chamando a classe
EntryTeste()


Tratamento de Eventos: Método bind() e Classe Event (Event Handling Model)

Neste tutorial de GUI, vamos aprender o que são eventos, para que servem, como funcionam bem como fazer seu tratamento (event handling) em programação gráfica no Python.

Acessar conteúdo em PDF: Apostila de Python

Tratamento de Eventos - Event Handling

Dizemos que a programação gráfica é event driven, ou seja, acionada por eventos.

Esses eventos nada mais são que algum tipo de interação da GUI com o usuário, como digitar algum texto, clicar no mouse, fechar uma janela, maximizar, selecionar algum radiobutton etc.

Os programas em GUI são ditos assíncronos, pois eles rodam e ficam lá parados, esperando o usuário fazer algo, diferente de um script puramente textual, que segue uma ordem mais direta e clara.

Em GUI, algo só acontece se você fizer algo acontecer.
E quando você faz algo, algum evento, uma informação, um evento é enviado pro programa, através de um objeto da classe Event.

Para processar ou tratar um evento, precisamos de duas coisas:
bind: o programa tem que ligar, vincular (bind em inglês) um evento a um componente gráfico, um widget
event handler (ou callback): temos que implementar um 'tratador' de eventos

Ou seja, temos que fazer uma ligação de um evento com um componente, por exemplo, clicar num botão, e criar uma maneira de processar esse evento: quando clicar no botão, abra outra janela, por exemplo.

Em outra palavras, o eventi handler nada mais é que um bom e velho conhecido método que é sempre invocado quando um evento ocorre.

Exemplo de Event Handling: bind() e <Button-1>

Para fazermos uma bind num widget, usamos o método bind():

  • widget.bind( evento , tratador_do_evento )

Um exemplo de evento é o "<Button-1>"
Ele fica 'de olho' se o primeiro botão do mouse (o mais da esquerda) é pressionado.

Vamos dar um exemplo com o widget do tipo Frame.
Criamos uma janela principal, que é um objeto da classe Tk()
Em seguida, criamos um frame nessa janela principal, de tamanho 100x100

E associamos ao widget meuframe o bind:
meuframe.bind("<Button-1>", tratador_evento)

Pronto. Sempre que alguém clicar no widget o evento <Button-1> ocorre e chamamos o método tratador_evento, enviando pra ele um objeto event.

Este método simplesmente printa no terminal de comando o local que foi printado. Essa informação está nos atributos event.x (posição horizontal) e event.y (posição vertical).



Teste o código:

from tkinter import *

# É o event handler
def tratador_evento(event):
    print("Você clicou na posição:", event.x, event.y)

janela_principal = Tk()
meuframe = Frame(janela_principal, width=100, height=100)
meuframe.bind("<Button-1>", tratador_evento)
meuframe.pack()

janela_principal.mainloop()

O resultado vai ser algo assim:

Event handling em Python



  1. <Button-1> se refere ao botão mais a esquerda do mouse.
  2. <Button-2> se refere ao botão do meio, quando existe.
  3. <Button-3> é o evento que se refere ao botão mais a direita.


Experimente clicar com o botão mais a direita e veja que nada ocorre.
Troque <Button-1> por <Button-3> e tente novamente.

É como se seu programa GUI ficasse o tempo todo perguntando:
Evento ocorreu? Não? Ok
Evento ocorreu? Não? Tá bom
Evento ocorreu? Não? Tudo certo
....
Evento ocorreu? Sim? Qual? Ah, o <Button-3>, ok, então chama o método tratador_evento, ele que vai tratar ele.
...
Evento ocorreu? Não? ...

O Python fica na espreita, aguardando algum evento ocorrer. Se ocorrer, ele identifica qual foi e chama o handler correspondente.

E o que é esse handler? E o que ele faz?
Simples: o que você quiser, o que você decide, é você quem manda nessa bagaça toda. Vamos aprender um pouco mais como tratar alguns eventos.