Programação RPi Python 11: GUI Python com Tkinter

Programação RPi Python 11: GUI Python com Tkinter

No tutorial anterior, aprendemos sobre os recursos orientados a objetos do Python, que são importantes para organizar o código e estruturar nossos aplicativos. Agora, vamos discutir como projetar interfaces gráficas em Python.

Aplicações embarcadas desenvolvidas em microcontroladores normalmente possuem LEDs, LCDs de caracteres ou pequenos LCDs gráficos como dispositivos de exibição. No entanto, esses monitores não possuem muitas interfaces sofisticadas. Mas um computador de placa única (como Raspberry Pi) pode ser configurado como um sistema desktop. Na verdade, configuramos nosso Raspberry Pi (RPi) usando um desktop Linux. Como tal, é possível desfrutar de interfaces ricas e grandes aplicações executadas em circuitos embarcados semelhantes.

Embora os microcontroladores ofereçam velocidade, os computadores de placa única apresentam vantagens que incluem um sistema operacional com fácil acesso a recursos de linguagem de alto nível. Interfaces gráficas ricas, acesso a bancos de dados, visualização de dados, gráficos 3D, redes e mineração de dados são apenas alguns dos recursos HLL que podem ser usados ​​em um projeto embarcado com SBCs.

Por exemplo, ao fazer a interface de um sensor com um microcontrolador, podemos apenas coletar dados do sensor e implementar ações imediatas com base nos dados coletados. Mas, se esse mesmo sensor estiver interligado com um computador de placa única (SBC), é possível realizar diversas tarefas.

Esses incluem:

  • Gravar e manter uma grande quantidade de dados de sensores em bancos de dados
  • Executando análises
  • Visualizando dados
  • Executando mineração de dados
  • Compartilhando dados e quaisquer resultados com outros dispositivos em uma rede
  • Implementar ações imediatas e de longo prazo

Um dispositivo baseado em microcontrolador executado em um código de nível de firmware não consegue executar essas tarefas complexas por conta própria. No máximo, ele pode ser configurado como um dispositivo Internet das Coisas (IoT), conectando-o a uma rede. Os dados físicos coletados podem então ser manipulados em uma plataforma em nuvem. Esta é uma grande razão pela qual os computadores de placa única têm um papel distinto no domínio incorporado.

Outro motivo: os usuários trabalham com o co-design de hardware-software em sistemas embarcados ao trabalhar em SBCs. Embora os aplicativos baseados em microcontroladores se concentrem no hardware, o usuário pode mudar o foco para os aspectos de software. Os SBCs permitem a criação de software embarcado de alto nível que utiliza o poder de um componente de hardware.

Em última análise, é o software executado no hardware que faz mais sentido. A interface e o controle de LEDs é o “Hello World” dos sistemas embarcados.

A seguir está uma captura de tela de uma interface gráfica de usuário (GUI) projetada para nossa primeira receita de driver de LED. Reserve um minuto para revisar esta GUI e tente adivinhar o nível de controle que podemos exercer sobre um componente de hardware com um SBC.

A GUI Python Tkinter para um driver RPi LED.

Em todas as nossas receitas RPi, frequentemente usamos programação GUI e multithreading. Ao usar sensores, incluiremos visualização de dados, programação de banco de dados e mineração de dados no software embarcado.

Da mesma forma, quando controlamos atuadores, construímos robôs ou usamos módulos de hardware sofisticados (como uma câmera ou microfone, etc.), é possível incluir recursos de software relevantes, como processamento de imagem, áudio, programação multimídia, gráficos 3D e programação de jogos. , etc.

A programação GUI e o multithreading são componentes de software essenciais de todas as nossas receitas.

Programação GUI em Python
Python é uma linguagem poderosa de muito alto nível (VHLL). Ele permite o projeto de interfaces gráficas ricas e fornece uma série de técnicas de visualização de dados com capacidade de mineração de dados. Esta é uma vantagem distinta em aplicações embarcadas sofisticadas.

Ao usar RPi em aplicações embarcadas, trataremos os circuitos embarcados como fontes de dados físicos (quando interligados com sensores) e controladores sofisticados (quando interligados com atuadores).

As interfaces gráficas projetadas em Python interagem com os circuitos incorporados, visualizam dados de sensores, manipulam dados para análise e tomada de decisões e fornecem interatividade adicional que normalmente não é possível com microcontroladores.

Janela principal da GUI Python Tkinter para o aplicativo de eletrônica embarcada RPi.

Existem várias opções em Python para desenvolver interfaces gráficas de usuário. Os mais populares incluem:

Tkinter- a interface Python padrão para o kit de ferramentas Tk GUI e o padrão de fato GUI em Python. O Tkinter é gratuito e incluído automaticamente na instalação do Python no Linux, Microsoft Windows e Mac OS X. Para usá-lo em um aplicativo, entretanto, o pacote Tkinter deve ser importado.

WxPython – um kit de ferramentas GUI de plataforma cruzada e código aberto para Python. Sua principal vantagem são os widgets nativos (widgets nativos específicos do sistema operacional).

PyQT – ligação para o kit de ferramentas GUI multiplataforma Qt. É provavelmente a GUI mais poderosa e substancial para Python. PyQT é ideal para grandes aplicações e está disponível sob GPL e licenças comerciais. Pode ser complicado de usar para aplicações comerciais.

PySide – semelhante ao PyQT em funcionalidade, mas o PySide é coberto pela licença LGPL. Portanto, está prontamente disponível para uso em aplicações comerciais.

Existem muitos outros pacotes GUI para Python. Antes de usar um aplicativo, é importante aprender sobre seus recursos, portabilidade, ferramentas de desenvolvimento, licenciamento e limitações. Para aplicações grandes, PyQT e PySide são normalmente as melhores opções (e PySide tem uma licença mais liberal).

Existem também editores WYSIWYG disponíveis para PyQT e PySide que tornam o design de interfaces rápido e fácil. Tkinter é a melhor escolha para aplicações básicas.

Usaremos o Tkinter para projetar a GUI para receitas RPi. Ele ocupa pouco espaço com uma execução relativamente rápida em comparação com outros pacotes. O gerenciamento de layout também é bastante eficiente. Esses recursos tornam o Tkinter uma opção ideal para UI incorporada.

No entanto, teremos que escrever código para cada widget e lidar com eventos às vezes é complicado. Esses esforços serão para acelerar nossos pequenos aplicativos incorporados.

Multithreading tarefas incorporadas

Em aplicativos incorporados, é comum repetir determinadas tarefas. Por exemplo, podemos precisar repetidamente buscar dados de um sensor ou exibir mensagens em um dispositivo de exibição. Mas os aplicativos de desktop raramente envolvem tais tarefas — você nunca iria querer que o código de um aplicativo de desktop executasse um loop infinito sem fim.

Em nossas receitas RPi, implementaremos loops infinitos típicos de aplicações embarcadas. No entanto, se executarmos esses loops a partir do aplicativo GUI, nossa interface congelará e não seremos capazes de inserir nenhum outro comando.

Portanto, para cada tarefa incorporada, criaremos um thread separado e a GUI será executada como um processo diferente no Linux. Podemos passar comandos para eliminar esses threads com um pequeno truque de codificação para interromper as tarefas sempre que necessário. Com threads, podemos tratar receitas RPi como aplicativos embarcados baseados em microcontroladores, mas com mais eficiência.

Com o multithreading, há também as vantagens de lidar simultânea e independentemente com vários componentes de hardware. Multi-threading não é possível em microcontroladores, o que apenas mostra que o SBC executando um sistema operacional incorporado é fundamental.

Tkinter
Tkinter é a biblioteca GUI padrão para Python. Ele fornece uma interface orientada a objetos para o kit de ferramentas Tk GUI. Qualquer GUI consiste em uma janela principal na qual diferentes elementos gráficos – como rótulos, caixas de texto, botões, botões de opção, botões de seleção, telas, etc.

Esses elementos gráficos, incluindo a janela principal e outras janelas, são chamados de widgets. As ações do usuário, como clicar em um botão, focar em uma caixa de texto, selecionar um botão de opção, etc., são chamadas de eventos. Em resposta a um evento, é possível abrir outra janela, que é então chamada de janela filha da janela pai.

Para criar uma interface de usuário com Tkinter, primeiro importe o módulo Tkinter, o que pode ser feito em código Python como qualquer outro módulo. O nome do módulo é “Tkinter” em Python 2 e “tkinter” em Python 3.

Estas são instruções válidas para importar o módulo Tkinter em Python 3:

importar tkinter

ou
da importação do tkinter *
ou
importar tkinter como tk

No terceiro exemplo acima, “tk” é a referência definida para a classe Tk. Esta referência pode ser qualquer identificador. Após importar o módulo Tkinter, crie uma janela principal do aplicativo GUI. Isso pode ser feito criando um objeto de instância da classe Tk. Para a janela principal (que não é filha de nenhuma outra janela), o objeto Tk é criado sem nenhum argumento.

Estas são declarações válidas para criar a janela principal

raiz = Tk

ou
raiz = tkinter.Tk

ou
root = tk.Tk # tk é referência à classe Tk na instrução de importação

Para criar uma janela filha, o objeto de instância com o método Toplevel deve primeiro ser criado – que deve ser passado para a janela pai (objeto) como um argumento.

Aqui está uma declaração válida para criar uma janela filha:

LED_window = nível superior (raiz)

Todos os widgets de janela, incluindo a janela principal, suportam vários métodos. De todos os métodos, o método loop principal é o mais importante.

Até que o método mainloop seja chamado em um widget de janela, ele não aparecerá na tela. O método mainloop inicia um loop infinito para executar a janela GUI, aguardar a ocorrência de um evento e processar o evento enquanto a janela não estiver fechada.

Portanto, o método mainloop deve ser a última instrução a ser chamada em um widget de janela. Quaisquer outros métodos chamados no widget após mainloop serão não será executado e retornará um erro.

Estas são declarações válidas para iniciar a janela principal do Tkinter:

raiz = Tk
raiz.mainloop

Estas são instruções válidas para iniciar uma janela filha:

LED_window = nível superior (raiz)
LED_window.mainloop

Uma janela pode ser destruída chamando o método destroy .

Aqui está uma instrução válida para destruir uma janela (chamada janela):

janela.destroy

O estilo e o comportamento de uma janela podem ser alterados chamando diferentes métodos. Por exemplo, para definir o título da janela, o método title está disponível.

Esta é uma instrução válida para definir o título de uma janela (chamada janela):

window.title (“Aplicativo de controle de eletrônicos incorporados Raspberry Pi”)

Para definir o tamanho e a posição da janela na tela, o método geometria pode ser usado. O método de geometria pode receber quatro argumentos opcionais como segue:

window.geometry(“larguraxaltura+/-posição_horizontal+/-posição_vertical”)

Esta é uma declaração válida para definir o tamanho e a posição de uma janela (chamada janela):

janela.geometria (“300×300+100+50”)

Todos os quatro argumentos (largura da janela, altura da janela, posição horizontal e posição vertical) aceitam valores inteiros em pixels.

Observação:

  • Se a posição horizontal tiver um sinal de mais à esquerda, a borda esquerda da janela estará a tantos pixels da borda esquerda da tela.
  • Se a posição horizontal tiver um sinal de menos à esquerda, a borda direita da janela estará a tantos pixels da borda direita da tela.
  • Da mesma forma, se a posição vertical tiver um sinal de mais à esquerda, a borda superior da janela estará a tantos pixels da borda superior da tela, e se a posição vertical tiver um sinal de menos à esquerda, a borda inferior da janela terá essa quantidade de pixels. da borda inferior da tela.

O tamanho mínimo e máximo de uma janela também pode ser definido usando os métodos minsize e maxsize . Ambos os métodos consideram a largura e a altura da janela em pixels e como argumentos.

Aqui está uma declaração válida para definir o tamanho mínimo de uma janela (chamada janela):

janela.minsize(480, 480)

Por padrão, uma janela é redimensionável e um usuário pode alterar o tamanho da janela arrastando suas bordas. O comportamento de redimensionamento de uma janela pode ser alterado usando o método resizable .

Este método usa dois argumentos booleanos para definir a largura e a altura da janela redimensionável como True ou False.

O módulo Tkinter também permite a criação de interfaces estáticas. Quando o usuário redimensiona uma janela, seu layout pode ficar desajeitado devido à natureza estática da interface. Portanto, é aconselhável definir a capacidade de redimensionamento de uma janela como False da seguinte forma:

window.resizable (Falso, Falso)

Uma janela é redimensionada automaticamente de acordo com os widgets filhos contidos nela. Se o tamanho máximo for definido para uma janela, alguns dos widgets filhos poderão não estar visíveis. Como resultado, nunca é recomendado definir o tamanho máximo de uma janela.

Uma janela pode ter vários estados, como:

  • Normal – exibido na tela em seu tamanho e posição padrão
  • Ampliado – exibido cobrindo a tela inteira
  • Ícone – minimizado na barra de tarefas
  • Retirado – janela fechada

Por padrão, a janela aparece em seu estado “normal”. Se estiver configurado para redimensionar horizontal e verticalmente, ele poderá ser ampliado para o tamanho de tela inteira clicando no botão maximizar. Ele também pode ser “ampliado” de dentro do código, configurando-o para seu estado, como:

window.state('ampliado')

Uma janela pode ser minimizada para o ícone clicando no botão minimizar. Ele pode ser minimizado para um ícone de dentro do código usando o método iconify ou definindo seu estado como 'ícone' da seguinte maneira:

janela.state('ícone')

ou
janela.iconify

Uma janela pode ser restaurada ao seu estado normal clicando em seu ícone na barra de tarefas. Ele pode ser restaurado para um estado normal de dentro do código usando o método deiconify ou definindo seu estado como “normal:”

janela.estado('normal')

ou
janela.deiconify

Estaremos usando os widgets com tema ttk em nossas janelas GUI. O ttk é um módulo separado que fornece acesso aos widgets com o tema Tk. Ele separa o código que implementa a aparência dos widgets, bem como o código que implementa o comportamento dos widgets.

Isso significa que precisaremos importar o ttk separadamente com o Tkinter. Aqui estão instruções válidas para importar ttk:

importar ttk
ou
da importação ttk *
ou
de tkinter importar ttk
A seguir estão instruções válidas para iniciar uma janela principal em branco:
da importação do tkinter *
de tkinter importar ttk
raiz = Tk
root.title (“APP de controle eletrônico incorporado RPi”)
raiz.minsize(480, 480)
raiz.resizable(0, 0)
raiz.mainloop

Esta é uma janela principal da GUI em branco que não contém outros widgets. Observe que o método mainloop é chamado na última instrução da janela principal.

Menus da janela principal da GUI Python Tkinter para um aplicativo de eletrônica embarcado RPi.

Permaneça conectado. Você está prestes a testemunhar uma abordagem multithreading para aplicativos incorporados usando Raspberry Pi. Estaremos controlando os circuitos embarcados por meio de um aplicativo GUI de desktop enquanto implementamos as operações embarcadas do microcontrolador em um computador de placa única.

No próximo tutorial, aprenderemos mais sobre o Tkinter e os widgets ttk, adicionando um menu ao nosso aplicativo de controle eletrônico embarcado RPi. Também continuaremos adicionando quadros GUI ao nosso aplicativo para cada componente eletrônico incorporado (dispositivos de exibição, sensores, módulos, motores e interfaces de comunicação) controlados pelo aplicativo.

Conteúdo Relacionado

Voltar para o blog

Deixe um comentário

Os comentários precisam ser aprovados antes da publicação.