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

Structuring With a Grid

00:00 In the previous lesson, I introduced you to layout containers. In this lesson, I’ll cover one of the more powerful ones, the grid container. As the name implies, the grid layout uses rows and columns to define a series of cells.

00:14 Each widget you yield inside of it goes in the next available cell. To control the shape of the grid, you use CSS properties. grid-size specifies how many rows and columns.

00:26 grid-rows and grid-columns allow you to express the proportions of the rows and columns, and you can have a cell in the grid overlap rows and columns through the use of row-span and column-span.

00:39 I’ve been lazy and pretty much ripped an example right out of Textual’s documentation. Let me show you how grids work. In this app, I’ve got seven text widgets that I’m going to lay out using the grid container.

00:52 I’ve gone back to using a separate CSS style file, which I’ll show you in a second.

00:57 You can use a grid container through a context manager. In fact, that’s actually my preferred approach as I find it easier to read. But there’s a sneakier way as well, which this example shows off.

01:09 The grid container is actually specified in the style sheet, so each widget in the .compose() that gets yielded is going to go into the next available spot defined in the grid.

01:20 This first Static uses an ID so that I can style it specifically, but the rest just get used as they are each going in the next available cell as the grid defines.

01:34 This is the corresponding style sheet file. There is a special class known as a Screen, which is the container that your app uses. It’s beyond the scope of this course, but you can define multiple screens and pop them up.

01:47 This allows you to do things like modal dialogue boxes, or to move between different widget layouts quickly. All apps have at least one screen by default.

01:57 By assigning the layout property a value of grid, your Screen class, in our case, the only one in the app, uses the grid container for layout.

02:07 This is why I didn’t use a grid in the .compose(). This is borderline of that stuff I was complaining about with CSS. I prefer to use the container explicitly myself so that everything that affects my layout is in one place, but this is also a choice.

02:22 The grid-size property indicates how many rows and columns, or more accurately, I should say, how many columns and rows as that’s the order here.

02:30 So three columns and four rows.

02:34 The grid-rows property allows you to control how the rows relate to each other. The value of 1fr means relative sizing. If I wanted the second row to be twice the size, I could add 2fr after it.

02:48 I’m 90% sure I could have just left this out as it’s likely the default, but I wanted to show you the concept. Same idea for column sizing, and the grid-gutter value specifies how many characters to use as spacing between each row and column.

03:03 Here is some default styling for my Static widgets. The color property is the font color. Setting it to auto means Textual will pick something that contrasts with the background color nicely.

03:14 Setting the height to 100% tells Static to grow to the size of the parent it’s inside of, which in this case will be the cell in the grid, and this is some special styling for that first Static widget that had an ID.

03:28 Instead of using the default background, I’m going to overload it using tint, which does a color calculation kind of mimicking opacity.

03:37 The row-span value says this cell should span three rows, and the column-span value says it should span two columns. So our first widget will take up a bunch more space, and then the rest will take up the allotted parts of the grid that remain.

03:51 Let’s take a look

03:57 and here you go. Textual automatically takes up as much space as it can filling the whole terminal area. Our grid has four rows, so the vertical space gets divided by four, and the horizontal space gets divided into the three columns.

04:12 Our first widget spans three rows and two columns, which means our second widget goes into the remaining space in the first row. That’s the one labeled Cell 2.

04:22 The first two slots in the second row are taken up by the Cell 1 widget, and so our third widget goes into the open spot in the second row. Likewise, for cell four, then the remaining three cells populate the last row.

04:37 You can achieve this same layout by mixing horizontal and vertical containers and setting their sizes correctly, but why do that when with a few CSS properties, you can get the layout you want.

04:49 Next up, I’ll dig into events a little more as well as their shortcut—actions.

Become a Member to join the conversation.