📜 ⬆️ ⬇️

Python + Pyside2 or just "Calculator"

Hi, Habr!

My name is Sasha. I am a Junior developer. I work as a software tester. Basically, I write tests with Python + Selenium, but Python has become so interesting that I wanted to delve into it and learn as many frameworks as possible! I wanted to write a desktop application, ala simple “Calculator”. My choice fell on Pyside2. I do not claim the perfect code or lesson. Simply, there is a desire to share experiences, if someone, like me, wants to start fumbling in Python. If I help someone, I have achieved the result.

Let's start!

I wrote my code in the IDE of JetBrains "PyCharm". OS - Windows.
')
Install PySide2:

pip install PySide2 

Where you have the Python root folder, go to it, then to the folder “Lib” -> “site-packages” -> “Pyside2”. You will have a designer program - this is a QtDesigner program that will allow you to make your own program's interface. It is worth noting that when you create your file in the directory of your project, it will have the format .ui , which is understandable Python will not understand, so we will need to convert it to the format .py , but that later.

First create your form.

image

We make our design, we call the buttons on the right in the subsection “Object Inspector”. It is worth saying that QtDesigner supports a cascading style sheet, and if it is easier, then by finding the parameter “styleSheet” in the properties, you have the opportunity to make your design based on the knowledge of CSS.

image

Next, we need to convert our .ui file to a format that Python would understand. Go to the command line and write

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

What does the "pyside2-uic" command do? It converts your .ui file into a py pythonic file and creates a Python class from it. Perhaps knowledgeable people will say that the ui file can be connected without conversion to the project, but I will be neat and better done, as written in the Pyside2 manuals.

Next, go to the code.

Open PyCharm, our project directory, and create the file calc_ui.py or something_ui.py, depending on what program you are doing. Prefix _ui At the end of the file will help us not to get confused in the files. In general, it should look like this:

image

We start by editing the file that we converted from .ui to .py .

Below we look for this code and copy it, then delete it from this file.

 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_()) 

We create our main file, where the program logic will be written. I called it, as, not surprisingly, “calc.py” (this can be seen above on the directory screen).

We paste our copied code there and start editing it.

import sys we throw in the beginning, as this is a good tone rule.

We import a couple of necessary modules for working with our form and import the main Ui_MainWindow class from our calc_ui.py file.

Next, edit if __name__ . Delete all not necessary. You should have this:

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

I commented on the code I hope clearly. Let's proceed to the creation of the class Calculator .

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

Next, our task is so that something happens when we poke on the buttons "1", "2", "3", etc.

In the same place, in the class constructor, we declare that the button is connected to a function:

  # 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) # ( 

The code on the buttons already shows the self.digit_pressed function, let's take a look at it, what does it do if the user presses the button with numbers:

  # 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 

Comments on the code are also present.

Now consider the function that will respond to pressing the operations "+" , "-" , 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() 

We write the first value into the self.first_value variable and clean our field to enter the value of the operation, and then output to the lineEdit (our main input and result field) all together with the number and the operation.

Why float ? I can answer in such a way that I decided to make everything float , and when displaying the value in the result block, if the result is at the end of ".0", delete this part so that the number is integer. I did not think better.

We now have functions for pressing numbers and pressing operations, what next? Next we need to display the result, this is the button = (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() 

Let me remind you that the self.first_value variable is now exactly the first variable that we enter, and self.equal holds the operation that we pressed. After we enter the second number and click on = , we try to find out what kind of operation it is, and then we define the 2nd variable.

Moving on to the operations functions. It worked out for me like this:

  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() 

The self.determinate_second_value () function defines the second value of a variable that we entered. It is not logical and crooked, but as it is, I will try to take into account all the errors later in the comments, when smart people will say how to correctly.

A little refreshment.


Further, in each of the operations functions, we call self.form_result () , which, strangely enough, forms our result. We keep the result in the self.result variable.

  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() 

I will explain for self.result [-2:] . [-2:] says that we are comparing the last 2 characters of the string with ".0".

So our result is displayed in the main lineEdit unit, congratulations.

I also attach here a code that deletes one character from a string, either completely the whole number or adds "." (point) to create a fractional number:

  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') 

All code under the spoiler:

All code
 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_()) 


Yes, the calculator does not compute large functions and expressions, I'm working on it!

Thank you very much for your attention. Good luck and develop! That's cool.

I would also like to invite you to my JuniorProger Telegram channel, where I talk about the life of a Junior programmer and his thorny, but very interesting way of becoming an It-specialist.

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


All Articles