Completing the View
00:00 Completing the App’s View. The GUI that you have at this point doesn’t really look like a calculator. You need to finish this by adding a display to show the target math operation and a keyboard of buttons representing the numbers and basic math operators.
00:16
You’ll also add buttons representing other required symbols and actions such as clearing the display. First, you need to update your imports. To arrange the buttons, you’ll use a QGridLayout
object, the QLineEdit
class will work as the calculator’s display and QPushButton
will provide the required buttons.
00:37
You’ll use a QVBoxLayout
to layout manager for the calculator’s global layout. Now you can update the initializer for PyCalcWindow
.
00:49
First self.generalLayout
is set to be QVBoxLayout
. You’ll use generalLayout
as the app’s general layout. In this, you’ll place the display at the top and the keyboard buttons in a grid layout, at the bottom.
01:06
Then you add calls to two private methods that you’ll create, createDisplay()
and createButtons()
. They won’t work at this point because you haven’t implemented them.
01:17
So to fix this, you’ll start by coding createDisplay()
. First you add another import of Qt, which will be used for alignment.
01:30
Next, you define a new constant to hold the display height in pixels. Now you go on to define createDisplay()
inside the PyCalcWindow
class.
01:44
To create the calculator’s display, you use a QLineEdit
widget. Then you set a fixed height of 35 pixels for the display using the DISPLAY_HEIGHT constant.
01:59 The display will have its text right-aligned. Finally, the display will be read-only to prevent direct editing by the user. The last line of code adds a display to the calculator’s general layout.
02:16
Next, you’ll implement the createButtons
method to create the required buttons for the calculator’s layout. These buttons will live in a grid layout, so you need a way to represent their coordinates on the grid.
02:29 Each coordinate pair will consist of a row and a column. To represent a coordinate pair, you’ll use a list of lists. Each nested list will represent a row.
02:41
First, you define a new constant called BUTTON_SIZE
. You’ll use this constant to provide the size of the calculator’s buttons. Here the buttons will have a square shape with 40 pixels per side.
02:54
With this initial setup, you can code the createButtons
method. You’ll use a list of lists to hold the keys or buttons and their positions and the calculator’s keyboard.
03:04
A QGridLayout
will allow you to arrange the buttons on the calculator’s window. First you create the empty dictionary self.buttonMap
to hold the calculator buttons.
03:14 Then you create a list of lists to store the key labels. Each row or nested list will represent a row in the grid layout while the index of each key label will represent the corresponding column on the layout.
03:30
Then you define two for
loops. The outer loop iterates over the rows and the inner loop iterates over the columns.
03:41
Inside the inner loop, you create the buttons and add them to both self.buttonMap
and buttonsLayout
. Every button will have a fixed size of 40 by 40 pixels, which you set with setFixedSize
and the BUTTON_SIZE
constant.
04:02
Finally, you embed the grid layout into the calculator’s general layout by calling addLayout
on the generalLayout
object.
04:12 You can now run the calculator and see the display and buttons are present, but at the moment, nothing is functional, so it’s time to fix that.
04:22
At the moment, you have no way to update the information shown on the display. So you’ll fix this by adding a few extra methods to PyCalcWindow
.
04:39
setDisplayText
uses setText
to set and update the display’s text. It also uses setFocus
to set the cursor’s focus on the display.
04:57
displayText
is a getter method that returns the display’s current text. When the user clicks the equal sign on the calculator’s keyboard, the app will use the return value of displayText
as the math expression to be evaluated.
05:16
clearDisplay
sets the display’s text to an empty string so that the user can introduce a new math expression. This method will be triggered every time the user presses the C
button on the calculator’s keyboard.
05:31 Now the calculator’s GUI is ready for use. You can run it, but it’s still not functional. This is because you haven’t implemented the model and the controller components.
05:41 So in the next section, you’ll fix that by writing a calculator’s model and controller.
Darren Jones RP Team on July 2, 2024
I did actually ponder that very point when doing this part of the course, but I felt that it slightly clouded the code later on when that method gets used. I don’t think it was entirely clear cut though, and there is the old saying that the hardest thing in programming is naming variables and functions!
Leodanis Pozo Ramos RP Team on July 2, 2024
The code in this article follows that naming style of PyQt, which doesn’t add the .get*
prefix to getter methods. It only use the .set*
prefix on setter methods. For example, QLabel.setText()
is the setter while QLabel.text()
is the getter. See doc.qt.io/qt-6/qlabel.html#text-prop
Ed Schneider on July 4, 2024
Whenever adopting a framework like Qt a user is faced with the issue of how much do I follow suit. Setting and Getting, I’ve been told, is more natural to C++ as is the use of Camel Case when naming variables and functions. The tutorial recommends using Camel Case rather than mixing Camel Case with Python’s snake case. I can understand the author’s recommendation when building an app from scratch. But if you’re adding Qt to an existing snake case oriented app I think the opposite is more appropriate. Then you can quickly see that anything using snake case is something you developed and anything with a name in Camel Case is from Qt. Be prepared for linters giving false positives, warnings about case issues, either way you go.
It would seem that following the Qt style is the author’s recommended way to go. But that brings up a related and much more important issue. Using the Model View Controller approach is NOT normal in Qt. Qt has an alternative to MVC which they call Model/View architecture which according to the Qt documentation “If the view and the controller objects are combined, the result is the model/view architecture.” According to the Qt bible for Python, Fitzpatrick’s Create GUI Applications with Python & Qt6, p.300 “In Qt land the distinction between the View & Controller gets a little murky.” Bottom line Qt apps don’t seem to use MVC. I liked the tutorial’s use of MVC because is did NOT follow suit. It made me think.
And last and definitely least, the tutorial uses PyQt6 rather than PySide6. PySide6 is now the Qt company’s recommended version of Qt for Python, they own it.
This is a very well done tutorial. I still recommend it highly even with these issues.
Become a Member to join the conversation.
jwil on June 29, 2024
Would it be better to name the function getDisplayText instead of displayText? It seems to be the getter that pairs with setDisplayText. ~4:50 (line 62)