PyQt 08 – QLineEdit e mais Qt Designer

Março 4th, 2010 by rudsonalves Leave a reply »

A próxima widget a ser apresentada é a QLineEdit, uma entrada de texto simples, em uma única linha, que permite alguns comandos de edição simples como paste, copy, drag, drop, undo e redo, além de aceitar as mais usuais combinações de teclas de atalho. Para uma descrição mais aprofundada, veja o manual da QLineEdit

Neste texto vou montar um pequeno diálogo para o cadastro de usuários, utilizando os widgets QLineEdit e QLabel, manualmente e depois usando o Qt Designer. A partir deste artigo, todos os diálogos serão criados apenas com o uso do Qt Designer.

Construindo o diálogo de cadastro manualmente

Como no artigo anterior, inicie o aplicativo com as linhas gerais, abaixo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/bin/env python                 
# -*- coding: iso-8859-1 -*- 
#                                 
# Diálogo para cadastro por Rudson R. Alves
#
 
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
 
class cadastro_Dialog(QDialog):
  def __init__(self, parent = None):
    super(cadastro_Dialog, self).__init__(parent)
 
    # ... definir o diálogo aqui ...
 
app = QApplication(sys.argv)
dlg = cadastro_Dialog()
dlg.exec_()

Isto cria a estrutura geral do aplicativo. Se executar o código acima, ele irá gerar um diálogo vazio. Para este texto, será criado um diálogo com a aparência da figura a seguir:

O código para gerar este diálogo é apresentado a seguir:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#!/bin/env python                                     
#-*- coding: iso-8859-1 -*-                           
#                                                     
# Diálogo para cadastro por Rudson R. Alves           
#                                                     
 
import sys                                            
from PyQt4.QtCore import *                            
from PyQt4.QtGui import *                             
 
class cadastro_Dialog(QDialog):                       
  def __init__(self, parent = None):                  
    super(cadastro_Dialog, self).__init__(parent)     
 
    # cria uma vbox para o diálogo inteiro e o aplica ao diálogo
    vbox = QVBoxLayout()                                        
    self.setLayout(vbox)                                        
 
    # cria label e nome_lineEdit do nome
    label = QLabel("Nome:")             
    self.nome_lineEdit = QLineEdit("")  
    # cria uma hbox para adicionar label e nome_lineEdit
    hbox = QHBoxLayout()                                
    # povoa a hbox                                      
    hbox.addWidget(label)                               
    hbox.addWidget(self.nome_lineEdit)                  
    # adiciona a hbox ao vbox                           
    vbox.addLayout(hbox)                                
 
    # cria label, senha_lineEdit e senha_check_lineEdit
    label = QLabel("Senha:")                           
    self.senha_lineEdit = QLineEdit()                  
    self.senha_check_lineEdit = QLineEdit()            
    # cria uma nova hbox                               
    hbox = QHBoxLayout()                               
    # povoa a hbox                                     
    hbox.addWidget(label)                              
    hbox.addWidget(self.senha_lineEdit)                
    hbox.addWidget(self.senha_check_lineEdit)          
    # adiciona a hbox ao vbox                          
    vbox.addLayout(hbox)                               
 
    # cria label e foto_lineEdit
    label = QLabel("Foto:")
    self.foto_lineEdit = QLineEdit()
    # cria uma nova hbox
    hbox = QHBoxLayout()
    # povoa a hbox
    hbox.addWidget(label)
    hbox.addWidget(self.foto_lineEdit)
    # adiciona a hbox ao vbox
    vbox.addLayout(hbox)
 
    # cria foto_label e image
    self.foto_label = QLabel()
    self.foto_label.setAlignment(Qt.AlignCenter)
    self.foto_label.setPixmap(QPixmap('qlineedit-01.jpeg'))
    # adiciona a foto_label a vbox
    vbox.addWidget(self.foto_label)
 
app = QApplication(sys.argv)
dlg = cadastro_Dialog()
dlg.exec_()

o código está todo comentado, mas ainda cabe algumas adições aqui. Observe que o widgets nomeados label, definido na linha 20 e redefinido nas linhas 31 e 44 não foram definidas com o prefixo ‘self.‘, como nas variáveis nome_lineEdit, senha_lineEdit, senha_check_lineEdit, foto_lineEdit e foto_label.

Isto se deve ao fato de não haver a necessidade de acessar estes objetos durante a execução do programa. Os widgets nomeados hbox e vbox seguem o mesmo princípio da widget label. Num diálogo criado no Qt Designer, todos os widgets serão definidos com o prefixo ‘self.’, mesmo que não venham a ser acessados posteriormente. Isto em si não interfere no funcionamento ou eficiência do diálogo.

A figura a seguir enfatizam as hbox e vbox criadas para organizarem o diálogo.

Os quadros em vermelho são as hbox criadas nas linhas 23, 35 e 47, respectivamente. A vbox está em verde e ela contem as três hbox criadas e o elemento foto_label

A classe QPixmap, linha 57, cria uma representação da imagem jpeg que pode ser compreendido pelo QLabel.setPixmap, para desenhar a imagem.

Construindo o diálogo de cadastro pelo Qt Designer

A construção do diálogo pelo Qt Designer segue o mesmo princípio das linhas apresentadas acima. Em princípio crie um diálogo com todos os elementos disposto aproximadamente nas posições desejadas.

As propriedades editadas em cada widget são apresentadas na tabela abaixo:

Tab 01: Propriedades das widgets. A coluna # contém o número do widget, representado na figura anterior.

# Propriedade Valor
1 objectName nome_lineEdit
2 objectName senha_lineEdit
3 objectName senha_check_lineEdit
4 objectName foto_lineEdit
5 objectName foto_label
5 pixmap qlineedit-01.jpeg
5 alignment-> Horizontal AlignHCenter

Em seguida selecione o QLabel ‘Nome:’ e o QLineEdit nome_lineEdit e clique no botão Lay out Horizontally. Isto fará o primeiro hbox da linha 23, do código anterior.

Repita o processo para os QLabel ‘Senha:’ e os QLineEdit senha_lineEdit e senha_check_lineEdit. Faça isto mais uma vez para o QLabel ‘Foto:’ e o QLineEdit foto_lineEdit. Isto deve deixar o diálogo com a aparência abaixo:

Para terminar o diálogo, desmarque todos os widgets, conforme a figura acima, e clique no botão Lay out Vertically. Isto irá arranjar os hbox e o foto_lineEdit em uma lista vertical. O diálogo pronto fica com a aparência abaixo:

Troque o objectName do diálogo para ‘cadastro_Dialog‘ e salve com o nome ‘cadastro.ui‘. Depois gere o diálogo com o comando pyuic4:

[simterm]
$ pyuic4 -o cadastro.py cadastro.ui ##blue##
[/simterm]

O código básico, para gerar o diálogo deve carregar o módulo cadastro.py (linha 10, no código abaixo), herdar a classe Ui_cadastro_Dialog (linha 12) e executar o método setupUi (linha 15) para criar os elementos do diálogo. As linhas abaixo fazem o serviço.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/bin/env python
#-*- coding: iso-8859-1 -*-
#
# Diálogo para cadastro por Rudson R. Alves
#
 
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from cadastro import *
 
class cadastro_Dialog(QDialog, Ui_cadastro_Dialog):
  def __init__(self, parent = None):
    super(cadastro_Dialog, self).__init__(parent)
    self.setupUi(self)
 
app = QApplication(sys.argv)
dlg = cadastro_Dialog()
dlg.exec_()

Explorando os sinais do QLineEdit

A implementação deste diálogo será em cima dos sinais emitidos pelo widget QLineEdit. Estes sinais são listados na tabela a segui:

Tab 02: Sinais do QLineEdit

Sinal Descrição
cursorPositionChanged(int old_pos, int new_pos) este sinal é emitido sempre que o cursor se move de uma posição antiga para uma posição nova
editingFinished() este sinal é emitido quando as teclas Return ou Enter são pressionadas, ou a linha perde o foco
returnPressed() este sinal é emitido quando as teclas Return ou Enter são pressionadas
selectionChanged() este sinal é emitido quando a seleção é alterada
textChanged(QString text) este sinal é emitido quanto o texto é alterado. text é o texto alterado
textEdited(QString text) este sinal é emitido quando o texto é editado. text é o texto editado. Diferentemente do textChanged, este sinal não é enitido quanto o texto é alterado via comando como o setText

As linhas a seguir permite explorar cada sinal descrito na tabela acima. As três linhas abaixo capturam o sinal cursorPositionChanged, que retorna a posição anterior e atual do cursor na linha em edição, nas variáveis old_pos e new_pos.

17
18
19
  @pyqtSignature("int, int")
  def on_nome_lineEdit_cursorPositionChanged(self, old_pos, new_pos):
    print 'cursorPositionChanged: cursor movido de %d para %d' % (old_pos, new_pos)

Observe que para recuperar os dois inteiros, é necessário passar como argumento ao pyqtSignature os tipos em uma única string, “int, int”. Execute o diálogo, escreva algo no QLineEdit e mova o cursor ao longo do texto. As mudanças na posição do cursor serão impressos no terminal.

Para facilitar a visualização dos diferentes sinais, comente as linhas acima e adicione as próximas linhas para implementar a captura dos sinais editingFinished e returnPressed no QLineEdit nome_lineEdit.

21
22
23
24
25
26
27
  @pyqtSignature("")
  def on_nome_lineEdit_editingFinished(self):
    print 'editingFinished...'
 
  @pyqtSignature("")
  def on_nome_lineEdit_returnPressed(self):
    print 'returnPressed...'

Com estas linhas, um editingFinished… será impresso sempre que um return ou enter for pressionado em nome_lineEdit, ou este widget perder o foco. Já um returnPressed será emitido apenas quando um return for pressionado em nome_lineEdit.

Para as próximas linhas não é necessário comentar as linhas anteriores. Apenas adicione as próximas linhas para implementar o sinal selectionChanged.

29
30
31
  @pyqtSignature("")
  def on_nome_lineEdit_selectionChanged(self):
    print 'selectionChanged...'

Execute novamente o diálogo e insira algum texto no widget nome_lineEdit. Selecione partes do texto e altere a seleção algumas vezes para que o sinal selectionChanged seja capturado.

Os dois últimos sinais são implementados com as linhas abaixo:

33
34
35
36
37
38
39
40
41
42
43
  @pyqtSignature("QString")
  def on_nome_lineEdit_textChanged(self, text):
    print 'textChanged: >%s<' % text
 
  @pyqtSignature("QString")
  def on_nome_lineEdit_textEdited(self, text):
    print ' textEdited: >%s<' % text
 
  @pyqtSignature("")
  def on_foto_lineEdit_returnPressed(self):
    self.nome_lineEdit.setText(self.foto_lineEdit.text())

Este código é apenas para teste, por isto ainda não tem o objetivo de ser funcional. As linhas acima capturam os dois sinais textChanged e textEdited em nome_lineEdit.

As três últimas linhas, 41 à 43, implementam a captura do sinal returnPressed em foto_lineEdit. Quando um return é pressionado, durante a edição deste widget, foto_lineEdit, o texto contido nele é copiado para o nome_lineEdit, linha 44. Observe que neste caso apenas um sinal textChanged é emitido por nome_lineEdit, neste momento, já que textEdited não é sensível a edições via comando.

Implementando o Diálogo

Este diálogo irá pegar o nome do usuário, uma senha e o caminho de uma foto e retornar. A senha deve ser omitida e conferida antes de ser aceita. O código a seguir faz esta implementação:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#!/bin/env python                         
#-*- coding: iso-8859-1 -*-               
#                                         
# Diálogo para cadastro por Rudson R. Alves
#                                          
 
import sys, os                             
from PyQt4.QtCore import *                 
from PyQt4.QtGui import *                  
from cadastro import *                     
 
class cadastro_Dialog(QDialog, Ui_cadastro_Dialog):
  def __init__(self, parent = None):               
    super(cadastro_Dialog, self).__init__(parent)  
    self.setupUi(self)                             
 
    self.senha_lineEdit.setEchoMode(QLineEdit.PasswordEchoOnEdit)
    self.senha_check_lineEdit.setEchoMode(QLineEdit.Password)    
 
    self.nome = self.nome_lineEdit.text()
    self.senha = self.senha_lineEdit.text()
    self.foto = self.foto_lineEdit.text()  
 
  @pyqtSignature("")
  def on_nome_lineEdit_editingFinished(self):
    #print 'Nome editado...'                 
    self.nome = self.nome_lineEdit.text()    
 
  @pyqtSignature("")
  def on_nome_lineEdit_returnPressed(self):
    self.senha_lineEdit.setFocus()         
 
  @pyqtSignature("")
  def on_senha_lineEdit_editingFinished(self):
    #print 'Senha editada...'                 
    self.senha = self.senha_lineEdit.text()   
 
  @pyqtSignature("")
  def on_senha_lineEdit_returnPressed(self):
    self.senha_check_lineEdit.setFocus()    
 
  @pyqtSignature("")
  def on_senha_check_lineEdit_editingFinished(self):
    #print 'Senha check editada...'                 
    if self.senha != self.senha_check_lineEdit.text() or self.senha == "":
      QMessageBox.question(None, "Senha erro", \                          
        "As senhas digitadas não conferrem ou senha em branco.\nReentre com a senha.")                                                                          
      self.senha_lineEdit.setText("")                                           
      self.senha_check_lineEdit.setText("")                                     
      self.senha = ""                                                           
      self.senha_lineEdit.setFocus()                                            
 
  @pyqtSignature("")
  def on_senha_check_lineEdit_returnPressed(self):
    self.foto_lineEdit.setFocus()                 
 
  @pyqtSignature("")
  def on_foto_lineEdit_editingFinished(self):
    #print 'Foto editada...'
    self.foto = self.foto_lineEdit.text()
    if self.foto != "":
      if os.path.isfile(self.foto):
        self.foto_label.setPixmap(QPixmap(self.foto))
      else:
        self.foto = ""
 
app = QApplication(sys.argv)
dlg = cadastro_Dialog()
dlg.exec_()
 
print 'Nome:   %s' % dlg.nome
print 'Senha:  %s' % dlg.senha
print 'Imagem: %s' % dlg.foto

As linhas 17 e 18 alteram o atributo EchoMode dos widgets QLineEdit senha_lineEdit e senha_check_lineEdit. Observe que estas alterações podem muito bem serem feitas com a edição do diálogo no Qt Designer, sem a necessidade da adição destas linhas.

Os EchoModes aceitos pelo QLineEdit são apresentados na tabela abaixo.

Tab 03: Modos do echo de caracteres no QLineEdit

Constante Valor Descrição
QLineEdit.Normal 0 Apresenta os caracteres como eles são digitados. Padrão.
QLineEdit.NoEcho 1 Não mostra nada.. Este modo é apropriado para passwords onde o números de caracteres digitados também deve ser permanecer em segredo
QLineEdit.Password 2 Mostra asteriscos, ou uma bolinha, no lugar dos caracteres pressionados
QLineEdit.PasswordEchoOnEdit 3 Apresenta os caracteres digitados durante a edição e mostra asteriscos terminar

Para este diálogo utilizei os modos QLineEdit.Password e QLineEdit.PasswordEchoOnEdit, apenas a título de demonstração.

As linhas com o comando print, comentadas, (26, 35, 44 e 59) são apenas para rastreio do código em tempo de execução. Isto pode ser de muita ajuda, caso não se tenha um debug para acompanhar a execução do código.

Como o evento returnPressed não muda o foco para a widget seguinte, implementei esta mudança para cada QLineEdit, nas linhas 30 (nome_lineEdit), 39 (senha_lineEdit) e 54 (senha_check_lineEdit).

As variáveis nome, senha e foto, definidas nas linhas 20 a 22, em princípio não são necessárias, uma vez que seus valores podem ser lidos das widgets nome_lineEdit), senha_lineEdit e foto_lineEdit. No entanto, dá um controle melhor sobre as variáveis editadas, além de um acesso mais simples, como feito nas linhas 71 a 73, quando imprime os resultados capturados pelo diálogo.

A linha 45 avalia se as senhas em senha_lineEdit e senha_check_lineEdit são equivalentes, além de recusar uma senha em branco.

A linha 61 verifica se o nome do arquivo passado existe, no entanto não checa se ele é uma imagem.

O código é apenas para demonstra o diálogo em funcionamento, carecendo de comentários e melhor tratamento de possíveis exceções. Mas espero que tenha atingido o objetivo de apresentar a widget QLineEdit.

O código e diálogo apresentados neste texto podem ser baixados do link: pyqt-08.zip.

Advertisement

11 comments

  1. Rodrigo disse:

    Excelente!

    Obrigado!

  2. Legal o post !

    Só gostaria de tirar uma dúvida com relação ao load/display da foto (ou de qualquer outra imagem no Widget):

    Porque quando passo um path local na imagem, o Widget a ignora e não mostra ?

    self.foto_label.setPixmap(QPixmap(‘”C:\\Renato\\Imagem_001.jpg”‘))

    http://www.dinointeractive.com/code/pyqt_image_gallery/pyqt_image_gallery.py

    No exemplo a cima, acontece a mesma coisa …mesmo passando um caminho completo da imagem no if __name__ não consigo visualiza-la

    pics = [“C:\\Renato\\Imagem_001.jpg”]

    Abraços,

  3. rudsonalves disse:

    Desculpe pela demora na resposta Renato.

    Testei no Linux com diversos paths e não tive nenhum problema. Tentei executar este programa no Windows e não apareceu a imagem.

    Infelizmente não uso muito o Windows, para lhe ser de muita ajudar nisto. Vou ficar lhe devendo.

  4. Rudson,

    Gostaria de parabenizá-lo pelo excelente trabalho.
    Sou iniciante em python e estou acompanhando atentamente este tutorial e, portanto, colhendo bons frutos.

    Estou muito grato!

  5. What’s up to all, how is all, I think every one is getting more from this site, and your views are good for new viewers.

  6. Latisha disse:

    It’s hard to find your blog in google. I found it on 11 spot, you should build quality backlinks , it will help
    you to get more visitors. I know how to help you, just search in google – k2 seo
    tips and tricks

  7. Eusebia disse:

    I read a lot of interesting articles here.
    Probably you spend a lot of time writing, i know
    how to save you a lot of time, there is an online tool that creates unique,
    google friendly posts in seconds, just search in google
    – laranitas free content source

  8. Pedro Monteiro disse:

    Oi rudsonalves, você poderia me tirar uma dúvida? Em uma aplicação onde uso QWizard, como posso gravar as informações de um usuário (QLineEdit e QRadioButton) obtidas em uma QWizardPage para então mostrar essa informação em outra QWizardPage?

    • rudsonalves disse:

      Nunca usei uma QWizardPage, mas acho que pode pegar as informações das formas convencionais, acessando as widgets. Teria de ver o código para entender como esta criando as widgets QLineEdit e QRadioButton, como os está conectando em seu código. Coloquei em minha lista de interesse a QWizardPage. Se desejar use o e mail para contato.

    • rudsonalves disse:

      Pelo que vi da QWizard é basicamente o mesmo que fazer um diálogo. Se escrever o código na mão basta acessar as widgets pelos nomes. Se usar o Qt Designer da mesma forma, ao criar as widgets você pode renomeá-las. Bem legal a QWizard. Nunca a havia usado. Uma hora destas texto um código com a QWizard e posto aqui.

Deixe uma resposta