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

Interacting With Widgets

00:00 In the previous lesson, I showed you how to use CSS to style your Textual application. In this lesson, I’ll show you some widgets that your user can interact with.

00:10 So far you’ve only seen text widgets, but Textual comes with a lot more. Like any GUI, you can create buttons and they come in a variety of styles. You of course can style them yourself using the concepts from the previous lesson, but there are shortcuts here as well using names like primary, success, and warning.

00:28 Similar to categories found in CSS-style libraries like Bootstrap. The only thing a user can do with a button is press it, so what if you want them to type something in?

00:39 Well, Textual has input fields as well. By default, they take text, but you can also use password mode and there are ways of configuring them so they only accept numbers. While showing off these widgets, I also want to demonstrate the most common debugging technique for Textual. Since it uses terminal escape sequences to move things around on the screen, you can’t just use a regular old print() statement.

01:05 Any attempt to output to the terminal is going to mess things up, or it would if Textual hadn’t done something about it. Also, breakpoints can be problematic. This is twofold.

01:16 First, Textual uses asyncio, which means there are coroutines, and sometimes possibly threads running. Breakpoints are more complicated when they stop one thread but not another.

01:26 And if you’re like me and your preferred debugger is terminal-based, well, that’s out as well, since it uses similar mechanisms as Textual to make changes to the screen.

01:37 Textual doesn’t leave you out in the cold though. First off, they’ve overloaded the print() statement to work with their tools. You saw how to run your program using the textual run command in the previous lesson.

01:48 If you do, you can also open another terminal and run textual console inside of it. With that, calling print() from your program will cause a message to show up in the console.

02:01 The textual console command also takes optional arguments where -X means to exclude certain kinds of messages. Textual gives you all sorts of info when it’s running and can sometimes be kind of noisy. On the screen, here is my collection of -X arguments that I usually use, which keeps the logging quieter, mostly sticking just to what I print out myself.

02:23 That said, if you’re truly trying to understand what’s going on, you might want to run textual console on its own without any of these additional arguments.

02:32 Let’s go build an app that can interact with our users.

02:36 My input app is a sampler of buttons and input fields, both of which you import from the widgets module. This is the simplest form of the button widget.

02:46 When you construct it, you pass in the text that you want on the button. Those button variations I mentioned can be invoked in a couple of ways. The first is how I’m doing it here using the variant argument. By default, primary uses a blue similar to the default theme for Bootstrap.

03:04 Instead of using the variant argument, you can call one of the predefined variant method factories. This one creates the Success variant button, which again, following Bootstrap, is a green.

03:15 There’s also Warning and Error factories as well. This is an input field widget. Like on the web, the placeholder argument is for some dimmed text, giving the user a hint about what should go in the field.

03:30 You can mask an input field by setting the password argument to true. You can also limit what kind of content goes in the field. Here, by setting type to number, I’m restricting the field to digits only.

03:45 Although Textual is a terminal framework, it responds to your mouse as well. You can set the tooltip value on an input field to show some info when you mouse over the widget.

03:56 Pressing buttons emits the button_pressed event, and so like with our key event handler, you can declare an on_button_pressed() method, which gets called whenever a button has been pushed.

04:08 I haven’t done it here, but you typically set IDs on all of your buttons. If you do, that ID gets set on the event object, allowing you to do different things for each button.

04:19 Instead, I’m just calling print() for all of our button presses. Remember, this will only work if you start in --dev mode, and even then it will only get printed to the companion console.

04:31 Otherwise, this call would get ignored.

04:34 The event object includes a reference to the button pressed. This is where you might check the ID and perform code associated with the click. Instead, I’m accessing the label property and printing it out.

04:48 The rest of the code here is the usual stuff.

04:51 Let me go back into split screen mode and show you the app and the console. On the right, I’ll run the console, and on the left I’ll run the app.

05:10 In the app you can see all of the color variations of the buttons. One of the beauties of specifying primary rather than blue, is that you can change the app’s theme and all of the primary buttons will get their new color.

05:24 You can even give your users some choice. I’ll show you more about that later. Notice just how noisy the console is without any restrictions. Textual itself is showing all sorts of debug information.

05:38 Most of what you’re seeing on the screen right now has to do with the buttons being laid out. Let me restart the console in a quieter mode.

05:49 I’ve pasted all those -Xs rather than make you watch me type it all, and I need to restart the app on the left-hand side.

06:00 Now that it’s connected, I can click a button

06:03 and you get the corresponding print on the right.

06:08 How about those inputs? When I put the cursor here and start typing, it wipes out the placeholder. Password is masked. Shhh, it’s a secret, and when I mouse over the numbers field, you see the tooltip.

06:28 You can’t see anything happening right now because I’m not typing numbers,

06:33 and when I do, the field shows the results.

06:37 Textual has a pretty exhaustive list of widgets available, including all the usual suspects you have with web forms. The list on the screen isn’t even all of them.

06:47 I do want to point out a couple though. Remember when I said that the folks who brought you Textual also brought you the Rich terminal library? Well, the two libraries are compatible.

06:56 If you’ve built a Rich component for your other applications, you can wire that into Textual using the Pretty widget class.

07:05 The other one I want to highlight is the Markdown widget. This isn’t for Textual markup. All of the components that take text support that. This is for Markdown like you use on a GitHub README.

07:17 So if you’ve got Markdown in a file, you can use this widget and Textual will render it for you.

07:24 So far, you’ve been yielding widgets directly. Textual also has special container widgets that allow you to group things together. More complex layouts are next.

Become a Member to join the conversation.