Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Putting It All Together: Textual Demo

00:00 In the previous lesson, I showed you how to use actions as event handlers. Up until now, all the apps you’ve seen have been to demonstrate a feature of Textual.

00:08 In this lesson, I’ll show you a simple program putting many of the things you’ve learned together in a practical example.

00:15 The goal for this lesson is to create a calculator for binary numbers. To keep it simple, I’ll stick with just addition and subtraction. Our app will display the binary number that is being operated on as well as its decimal equivalent.

00:28 It will have buttons for the zero and one so that you can enter a number, and buttons for the operations plus, minus, equals, and clear. The app will need to track what information is in the display, as well as store the accumulated value of the operations do far. When the user hits plus, minus or equals, the current value will get combined with the accumulated value to show an answer. Let’s go take a look at the code involved in our binary calculator.

00:58 I’ll start by explaining the layout of our app. I’m using a grid container, so most of the layout info is inside the style sheet. This is bincalc.tcss.

01:08 This sets the layout to a grid, and the grid will have four columns and five rows. There will be two digit displays showing the binary and decimal version of the current number.

01:19 They’ll go in the first row and take up two columns each. I want all my buttons to expand to be the size of the grid cell they’re within, so I’m setting both the width and height to a hundred percent.

01:31 I’m also setting the font color to auto so that Textual automatically picks a color that goes with the background I give the button.

01:38 Some of my styling is for specific button types. This CSS class is for the one and zero buttons. There’ll be a bit bigger, taking up two rows and columns each.

01:49 The dollar sign primary value is a TCSS variable saying to use the primary variant of the button. If you’ve used CSS templating languages like SCSS, this syntax mimics that.

02:03 Then the last chunk here includes a CSS class for my operation buttons, those being the plus and minus. Then ID-based rules for clear and equals. Note the use of $success similar to the $primary above.

02:18 Alright, that’s the styling. Let’s look at the Python that goes with it.

02:23 This is bincalc.py. The imports are the usual stuff, and I’m referencing the TCSS style sheet I just showed you. I’m using BINDINGS for my key press operations, starting with my favorite, too lazy to use Ctrl + q shortcut.

02:39 Each of the buttons are associated with key bindings as well, allowing you to use the keyboard or the mouse for the app. The operation_pressed action takes an argument. Seeing as I’m only supporting plus and minus, I’m going to turn all operations into addition by multiplying the value by one or negative one.

02:58 Similarly, I’ve got a single action to handle both the zero and one buttons using an argument to parameterize the action invocation.

03:06 These are my variables for the data I’ll need, starting with the accumulated value. Then the current operation being positive or negative one and the current digits to display on the screen.

03:18 That last one’s a little redundant, but I’ll come back to that in a sec.

03:24 Inside the .compose() method, I’m building our interface starting with a Digits display widget, still fun to say, for our binary representation.

03:33 Then another one for our decimal equivalent. Remember, both of these widgets span two columns, so the two of them will take up the entire first row. Next is the zero button.

03:44 Buttons can take an action argument allowing you to register an event handler with them directly. This handler will use the exact same action as the one bound to the zero key above. One small thing though: actions have scope and by default the action scope for a button is the button itself.

04:01 To use an app level handler, you need to prefix the action with the app qualifier like I’m doing here. This way the button and the key press can invoke the exact same code.

04:12 Here I’ve got a similar concept for our clear button. Our grid is four columns of five rows. I want the zero button to take up two columns and the clear button to take up one, which means the cell after it in the fourth column needs to be empty.

04:28 You can’t really do empty, so I’m putting a Label widget with nothing in it inside this cell to take up the space.

04:36 This is our plus button. Like with the equivalent binding, it calls the action with an argument of one. It’s also got a label spacer after it, and the rest here is similar with our one’s digit, our minus and our equals buttons.

04:51 This is a utility method. There are two displays of our number, one in binary and one in decimal, so anytime you want to change one, you have to change the other.

05:01 The function’s argument is the binary number, so the first call simply updates the Digits widget, and then the second one has to convert the binary into decimal using the int() constructor, and then since the widget takes a string, converts the result of that before the widget’s update method is called.

05:19 The clear action resets our accumulated value, resets the base operation, wipes out the current value of digits, and then updates our displays. The digit_pressed action gets called when the user presses one or zero or clicks their corresponding buttons.

05:36 The action takes an argument, which is the value being invoked. The action adds the digit to our current value variable, and then updates the display. The current value variable stores our numbers as a string, so that plus equals is really appending a digit.

05:51 After I wrote this code, I realized this was redundant. The binary digits widget will always contain the same thing as the current value variable, so I could have just accessed that instead.

06:03 It would always have had a leading zero, but that would just get ignored in the math. Oh, well, nothing like explaining your code to someone else to discover that it’s not as good as it could be.

06:13 The operation_pressed action is our handler for the plus and minus buttons. It takes an argument, which is either the integer one or negative one.

06:23 If our current value is empty, treat it like it’s zero. Otherwise, convert it to decimal to do the math on it. Since our only operations are plus and minus, I’ve turned that into always plus with some multiplication.

06:37 For plus, operation will be one accumulating the value. For minus the operation will be minus one, turning the accumulation into subtraction. Note that here I’m using the object’s operation, not the function argument.

06:51 Pressing plus or minus is actually about adding or subtracting the next thing, so this operation causes the previous add or subtract to run and then sets up the next one.

07:04 This is the action for the equals keys and buttons. If there’s no digits yet, just do nothing otherwise accumulate based on the previous plus or minus operation.

07:15 Then update the display with the final value. Below this, I reset the current digits in operation, but note that I don’t change the accumulated value. That way you can add something to the result of the equals button. And that’s pretty much it.

07:29 Just the usual run method below this. Let’s go try this out.

07:40 101 is five, so our conversion’s working.

07:45 Plus 3 is eight,

07:51 minus 1 is seven,

07:55 and clear resets us back. Nice. I hope seeing everything put together has helped you understand how to build Textual apps. This example is a simplified version of one that comes with Textual that creates a regular decimal calculator, supporting addition, subtraction, multiplication, and division.

08:14 The next lesson is the last where I’ll summarize the course and point you at further resources, including where you can find that calculator example I just mentioned.

Become a Member to join the conversation.