Python + Pyside2 ou simplesmente "Calculadora"

Olá Habr!

Meu nome é Sasha. Eu sou um desenvolvedor júnior. Eu trabalho como testador de software. Eu escrevo principalmente testes usando Python + Selenium, mas o Python se tornou tão interessante que eu queria me aprofundar nele e aprender o maior número possível de estruturas! Eu queria escrever um aplicativo de desktop, como simples "Calculadora". Minha escolha caiu em Pyside2. Não pretendo ter o código ou a lição perfeita. Há simplesmente um desejo de compartilhar experiências se alguém, como eu, quiser começar a se atrapalhar em Python. Se ajudo alguém, consegui o resultado.

Vamos começar!

Eu escrevi meu código no PyBarm IDE do JetBrains. SO - Windows.

Instale o PySide2:

pip install PySide2 

Onde você tem a pasta raiz do Python, acesse-a e depois na pasta “Lib” -> “site-packages” -> pasta “Pyside2”. Você terá um programa de designer - este é o programa QtDesigner, que permitirá que você crie sua própria interface de programa. É importante notar que, quando você criar seu arquivo no diretório do seu projeto, ele terá o formato .ui , que o Python não entenderá, portanto, precisaremos convertê-lo para o formato .py , mas isso é mais tarde.

Primeiro, crie seu formulário.

imagem

Criamos nosso design, chamamos os botões à direita na subseção “Object Inspector”. Vale dizer que o QtDesigner suporta uma folha de estilos em cascata e, se for mais fácil, localizando o parâmetro "styleSheet" nas propriedades, você tem a oportunidade de criar seu próprio design com base no conhecimento de CSS.

imagem

Em seguida, precisamos converter nosso arquivo .ui em um formato para que o Python o entenda. Vá para a linha de comando e escreva

 pyside2-uic "you_file.ui" -o "your_file.py" 

O que o comando pyside2-uic faz? Ele converte seu arquivo .ui em um arquivo .py python e cria uma classe Python a partir dele. Talvez as pessoas com conhecimento digam que um arquivo de interface do usuário pode ser conectado sem conversão a um projeto, mas eu serei limpo e melhor, como está escrito nos manuais do Pyside2.

Em seguida, vá para o código.

Abra o PyCharm, nosso diretório de projetos, e crie um arquivo chamado calc_ui.py ou something_ui.py, dependendo do programa que você está executando. O prefixo _ui no final do arquivo nos ajudará a não nos perder nos arquivos. Em termos gerais, deve ficar assim:

imagem

Vamos começar editando o arquivo que convertemos de .ui para .py .

Abaixo, procuramos esse código e o copiamos e depois o excluímos deste arquivo.

 if __name__ == '__main__': import sys app = QtWidgets.QApplication(sys.argv) Form = QtGui.QWidget() ui = Ui_Form() ui.setupUi(Form) Form.show() sys.exit(app.exec_()) 

Criamos nosso arquivo principal, onde a lógica do programa será gravada. Eu o chamei assim, não surpreendentemente de “calc.py” (acima na tela do diretório está visível).

Cole nosso código copiado lá e comece a editá-lo.

sys de importação que lançaremos no início, pois é uma regra de boa forma.

Importamos alguns módulos necessários para trabalhar com nosso formulário e, do arquivo "calc_ui.py", importamos a classe principal Ui_MainWindow .

Em seguida, edite se __name__ . Excluímos tudo o que não é necessário. Você deve ter isso:

 if __name__ == '__main__': #   QApplication app = QtWidgets.QApplication(sys.argv) #    ,     calc = Calculator() #  sys.exit(app.exec_()) 

Comentei o código claramente esperançoso. Vamos continuar a criar a classe Calculadora .

 class Calculator(QtWidgets.QMainWindow, Ui_MainWindow): #   def __init__(self): super().__init__() #    Ui ( ) self.setupUi(self) #    self.show() 

Além disso, nossa tarefa é garantir que algo aconteça quando apertarmos os botões "1", "2", "3" etc.

No mesmo local, no construtor da classe, declaramos a conexão do botão com qualquer função:

  # pressed self.pushButton.clicked.connect(self.digit_pressed) # 1 self.pushButton_2.clicked.connect(self.digit_pressed) # 2 self.pushButton_3.clicked.connect(self.digit_pressed) # 3 self.pushButton_4.clicked.connect(self.digit_pressed) # 4 self.pushButton_5.clicked.connect(self.digit_pressed) # 5 self.pushButton_6.clicked.connect(self.digit_pressed) # 6 self.pushButton_7.clicked.connect(self.digit_pressed) # 7 self.pushButton_8.clicked.connect(self.digit_pressed) # 8 self.pushButton_9.clicked.connect(self.digit_pressed) # 9 self.pushButton_10.clicked.connect(self.digit_pressed) # 0 self.pushButton_add.clicked.connect(self.pressed_equal) # + self.pushButton_ded.clicked.connect(self.pressed_equal) # - self.pushButton_div.clicked.connect(self.pressed_equal) # / self.pushButton_mul.clicked.connect(self.pressed_equal) # * self.pushButton_exp.clicked.connect(self.pressed_equal) # ** self.pushButton_log.clicked.connect(self.pressed_equal) # log self.pushButton_procent.clicked.connect(self.pressed_equal) # % self.pushButton_ENTER.clicked.connect(self.function_result) # = self.pushButton_C.clicked.connect(self.function_clear) # C self.pushButton_point.clicked.connect(self.make_fractional) # . self.pushButton_delete.clicked.connect(self.function_delete) # < self.pushButton_open_skob.clicked.connect(self.create_big_example) # ( 

A função self.digit_pressed já está indicada no código dos botões, vamos dar uma olhada no que faz se o usuário clicar no botão com números:

  # lineEdit -  ,         # text() -  ,      # setText() -          # sender() - ,     (   ,    ) def digit_pressed(self): button = self.sender() if self.lineEdit.text() == '0': #        "0",     ,     self.lineEdit.setText(button.text()) else: if self.result == self.lineEdit.text(): self.lineEdit.setText(button.text()) else: self.lineEdit.setText(self.lineEdit.text() + button.text()) self.result = 0 

Comentários sobre o código também estão presentes.

Agora considere uma função que responderá ao pressionar as operações "+" , "-" etc.

  clear() -  ,       def pressed_equal(self): button = self.sender() self.first_value = float(self.lineEdit.text()) self.lineEdit.clear() self.label.setText(str(self.first_value) + button.text()) self.equal = button.text() 

Escrevemos o primeiro valor na variável self.first_value e limpamos nosso campo para inserir o valor da operação e, em seguida, enviamos para lineEdit (nosso principal campo de entrada e resultado), juntamente com o número e a operação.

Por que flutuar ? Posso responder para que eu decidi fazer tudo flutuar e, ao emitir o valor para o bloco de resultados, se o resultado tiver ".0" no final, exclua esta parte para que o número seja um número inteiro. Eu não pensei em um melhor.

Agora temos funções para pressionar números e para pressionar operações, o que vem a seguir? Em seguida, precisamos exibir o resultado, este é o botão = (ENTER) .

  def function_result(self): if self.equal == '+': self.function_addition() elif self.equal == '-': self.function_subtraction() elif self.equal == "/": self.function_divison() elif self.equal == '*': self.function_multiply() elif self.equal == "^": self.exponentiation() elif self.equal == "%": self.function_percent() elif self.equal == "log": self.function_log() 

Deixe-me lembrá-lo de que a variável self.first_value agora é exatamente a primeira variável que inserimos e self.equal contém a operação que pressionamos. Depois de inserir o segundo número e pressionar = , tentamos descobrir qual é a operação e depois determinamos a segunda variável.

Passamos às funções das operações. Eu entendi assim:

  def function_addition(self): self.determinate_second_value() self.result = float(self.first_value + self.second_value) self.form_result() def function_subtraction(self): self.determinate_second_value() self.result = float(self.first_value - self.second_value) self.form_result() def function_divison(self): self.determinate_second_value() self.result = float(self.first_value / self.second_value) self.form_result() def function_multiply(self): self.determinate_second_value() self.result = float(self.first_value * self.second_value) self.form_result() def function_exponentiation(self): self.determinate_second_value() self.result = float(self.first_value ** self.second_value) self.form_result() def function_percent(self): self.determinate_second_value() self.result = float(self.first_value * (self.second_value / 100)) self.form_result() def function_log(self): self.determinate_second_value() self.result = float(math.log(self.first_value, self.second_value)) self.form_result() 

A função self.determinate_second_value () determina o segundo valor da variável que inserimos . Não é um pouco lógico e torto, mas, como é, tentarei levar em consideração todos os erros posteriormente nos comentários, quando pessoas inteligentes disserem como fazê-lo.

Um pouco de refresco.

  • self.first_value - tem o valor do primeiro número inserido
  • self.equal - tem str a variável da operação que pressionamos
  • self.second_value - possui o valor da segunda variável

Em seguida, em cada uma das funções de operações, chamamos self.form_result () , que, estranhamente, forma nosso resultado. Mantemos o resultado na variável self.result .

  def form_result(self): self.result = str(self.result) if self.result[-2:] == '.0': self.result = self.result[:-2] self.lineEdit.setText(str(self.result)) self.label.clear() 

Vou explicar por auto-resultado [-2:] . [-2:] significa que estamos comparando os 2 últimos caracteres da string com ".0".

Portanto, nosso resultado é exibido no bloco lineEdit principal, parabéns.

Também anexarei aqui um código que remove um caractere de uma sequência ou o número inteiro ou adiciona "." (ponto) para criar um número fracionário:

  def make_fractional(self): value = self.lineEdit.text() if '.' not in value: self.lineEdit.setText(value + '.') def function_delete(self): value = self.lineEdit.text() self.lineEdit.setText(value[:-1]) def function_clear(self): self.lineEdit.setText('0') 

Todo o código sob o spoiler:

Código inteiro
 from PySide2 import QtWidgets from calc_ui import Ui_MainWindow import sys import math class Calculator(QtWidgets.QMainWindow, Ui_MainWindow): def __init__(self): super().__init__() #    Ui ( ) self.setupUi(self) self.show() self.lineEdit.setText('0') self.first_value = None self.second_value = None self.result = None self.example = "" self.equal = "" # pressed self.pushButton.clicked.connect(self.digit_pressed) # 1 self.pushButton_2.clicked.connect(self.digit_pressed) # 2 self.pushButton_3.clicked.connect(self.digit_pressed) # 3 self.pushButton_4.clicked.connect(self.digit_pressed) # 4 self.pushButton_5.clicked.connect(self.digit_pressed) # 5 self.pushButton_6.clicked.connect(self.digit_pressed) # 6 self.pushButton_7.clicked.connect(self.digit_pressed) # 7 self.pushButton_8.clicked.connect(self.digit_pressed) # 8 self.pushButton_9.clicked.connect(self.digit_pressed) # 9 self.pushButton_10.clicked.connect(self.digit_pressed) # 0 self.pushButton_add.clicked.connect(self.pressed_equal) # + self.pushButton_ded.clicked.connect(self.pressed_equal) # - self.pushButton_div.clicked.connect(self.pressed_equal) # / self.pushButton_mul.clicked.connect(self.pressed_equal) # * self.pushButton_exp.clicked.connect(self.pressed_equal) # ** self.pushButton_log.clicked.connect(self.pressed_equal) # log self.pushButton_procent.clicked.connect(self.pressed_equal) # % self.pushButton_ENTER.clicked.connect(self.function_result) # = self.pushButton_C.clicked.connect(self.function_clear) # C self.pushButton_point.clicked.connect(self.make_fractional) # . self.pushButton_delete.clicked.connect(self.function_delete) # < self.pushButton_open_skob.clicked.connect(self.create_big_example) # ( def digit_pressed(self): # sender - ,     (   ,    ) button = self.sender() if self.lineEdit.text() == '0': self.lineEdit.setText(button.text()) else: if self.result == self.lineEdit.text(): self.lineEdit.setText(button.text()) else: self.lineEdit.setText(self.lineEdit.text() + button.text()) self.result = 0 def form_result(self): self.result = str(self.result) if self.result[-2:] == '.0': self.result = self.result[:-2] self.lineEdit.setText(str(self.result)) self.label.clear() def make_fractional(self): value = self.lineEdit.text() if '.' not in value: self.lineEdit.setText(value + '.') def function_delete(self): value = self.lineEdit.text() self.lineEdit.setText(value[:-1]) def function_clear(self): self.lineEdit.setText('0') def pressed_equal(self): button = self.sender() self.first_value = float(self.lineEdit.text()) self.lineEdit.clear() self.label.setText(str(self.first_value) + button.text()) self.equal = button.text() def function_addition(self): self.determinate_second_value() self.result = float(self.first_value + self.second_value) self.form_result() def function_subtraction(self): self.determinate_second_value() self.result = float(self.first_value - self.second_value) self.form_result() def function_divison(self): self.determinate_second_value() self.result = float(self.first_value / self.second_value) self.form_result() def function_multiply(self): self.determinate_second_value() self.result = float(self.first_value * self.second_value) self.form_result() def function_exponentiation(self): self.determinate_second_value() self.result = float(self.first_value ** self.second_value) self.form_result() def function_percent(self): self.determinate_second_value() self.result = float(self.first_value * (self.second_value / 100)) self.form_result() def function_log(self): self.determinate_second_value() self.result = float(math.log(self.first_value, self.second_value)) self.form_result() def determinate_second_value(self): self.second_value = float(self.lineEdit.text()) self.lineEdit.clear() self.label.setText(str(self.first_value) + self.equal + str(self.second_value)) def function_result(self): if self.equal == '+': self.function_addition() elif self.equal == '-': self.function_subtraction() elif self.equal == "/": self.function_divison() elif self.equal == '*': self.function_multiply() elif self.equal == "^": self.exponentiation() elif self.equal == "%": self.function_percent() elif self.equal == "log": self.function_log() if __name__ == '__main__': #   QApplication app = QtWidgets.QApplication(sys.argv) #    calc = Calculator() #  sys.exit(app.exec_()) 


Sim, a calculadora não calcula grandes funções e expressões, estou trabalhando nisso!

Muito obrigado pela atenção. Boa sorte e desenvolva-se! Isso é demais.

Também gostaria de convidar você para o meu canal JuniorProger Telegram, onde falo sobre a vida de um programador Junior e sua maneira espinhosa, mas muito interessante de se tornar um especialista em TI.

Source: https://habr.com/ru/post/pt458536/


All Articles