WEBVTT

0
00:00.210 --> 00:04.710
So now that our program works for text-based questions,

1
00:05.160 --> 00:10.160
it's time to upgrade this program so that it actually has a graphical user

2
00:10.530 --> 00:13.830
interface. You'll notice that in the project folder,

3
00:14.150 --> 00:16.790
there is a file called ui.py,

4
00:17.420 --> 00:22.160
and this is pretty much empty at the moment, other than a single constant

5
00:22.430 --> 00:24.950
which sets the theme color. Now,

6
00:24.950 --> 00:28.310
what we're trying to create is something that looks like this.

7
00:28.790 --> 00:31.850
So we have some sort of a score board label,

8
00:32.060 --> 00:36.110
we have a canvas with a white background,

9
00:36.440 --> 00:37.670
and then on the canvas,

10
00:37.700 --> 00:42.020
we've got some text in the middle and then we've got a true button and a false

11
00:42.020 --> 00:46.820
button each using the true and false images from this folder.

12
00:47.480 --> 00:51.680
Now we've seen how we can create graphical user interfaces using tkinter.

13
00:52.130 --> 00:55.190
But in this case, we're going to do something a little bit different.

14
00:55.790 --> 00:59.060
We're going to create our user interface in tkinter

15
00:59.330 --> 01:01.730
but we're going to do it inside a class.

16
01:02.210 --> 01:05.870
If you remember from day 17 where this project comes from,

17
01:06.260 --> 01:09.170
that was when we learned about Object Oriented Programming,

18
01:09.530 --> 01:13.850
and we learned about how to separate out our concerns like

19
01:13.910 --> 01:18.110
the part that fetches the data or the part that model each of the questions

20
01:18.380 --> 01:22.070
or the part that handles the actual quiz functionality,

21
01:22.430 --> 01:27.430
and they are all separated in that own class. In order to create our user

22
01:27.530 --> 01:28.280
interface

23
01:28.280 --> 01:33.280
we're also going to create our very own class inside this ui.py.

24
01:34.370 --> 01:36.710
So it's been a while since we've created classes.

25
01:36.770 --> 01:40.910
So I want to do a quick reminder session on how to do that.

26
01:41.330 --> 01:45.740
So we use the class keyword and then we provide the name of the class. Now,

27
01:45.770 --> 01:48.890
in my case, I'm going to call this the QuizInterface.

28
01:49.550 --> 01:54.350
And remember that the way that you name classes is what this is called. Pascal

29
01:54.380 --> 01:56.000
case. So a capital letter,

30
01:56.240 --> 02:01.240
and then each word is not separated by any underscores or any dashes.

31
02:01.880 --> 02:03.170
So this is our class

32
02:03.260 --> 02:07.490
and then we're going to create our init inside this class.

33
02:08.060 --> 02:10.550
Now, if any of this is unfamiliar to you,

34
02:10.550 --> 02:14.660
then make sure that you haven't skipped the lessons on Object Oriented

35
02:14.660 --> 02:18.410
Programming and creating and using classes in Python.

36
02:18.740 --> 02:21.890
We covered that in day 17. So if you skipped that,

37
02:22.040 --> 02:25.580
be sure to head back before you proceed, because otherwise, the rest of this

38
02:25.880 --> 02:29.780
is not going to make any sense at all. In our class init,

39
02:29.840 --> 02:32.930
we're going to create our user interface.

40
02:33.140 --> 02:35.870
So we're going to create all the buttons and all of the layouts.

41
02:36.200 --> 02:40.670
And we start off by simply creating our window. Now this time though,

42
02:40.700 --> 02:45.380
instead of creating our window as just a simple variable,

43
02:45.710 --> 02:48.500
we're going to make it a property of this class.

44
02:48.530 --> 02:50.480
So we're going to add self in front of it.

45
02:51.050 --> 02:54.710
And then we're going to create it from the tkinter module.

46
02:54.770 --> 02:59.180
So let's go ahead and import everything from the tkinter module,

47
03:01.450 --> 03:06.450
and let's set our window as a new object from the tk class.

48
03:07.780 --> 03:11.920
Next, I'm going to change some aspects of the window. So for example,

49
03:11.920 --> 03:16.090
I'm going to change the title. So I'm going to set it to, um,

50
03:16.420 --> 03:19.090
Quizzler which is going to be the name of this app.

51
03:19.960 --> 03:23.470
We can continued like this inside the init function,

52
03:23.800 --> 03:28.510
which remember, is going to be called whenever we create a new object from this

53
03:28.510 --> 03:29.343
class.

54
03:29.590 --> 03:34.590
This is where we're also going to have our self.window.mainloop

55
03:36.340 --> 03:41.080
and that will set our program to run. In order to test this,

56
03:41.140 --> 03:43.180
we're going to go back to our main.py

57
03:43.570 --> 03:46.000
and we're going to import that class.

58
03:46.180 --> 03:49.870
So from ui import the QuizInterface,

59
03:50.290 --> 03:53.650
and then we're going to create that QuizInterface down here.

60
03:55.210 --> 03:57.010
I'm going to call it the quiz_ui

61
03:57.550 --> 04:01.990
and it's going to be initialized from our quiz interface. Now,

62
04:02.020 --> 04:04.360
if you remember, when we first learned about 

63
04:04.360 --> 04:09.360
tkinter I told you that tkinter works by having this endless loop

64
04:10.810 --> 04:13.090
essentially that's called the main loop.

65
04:13.900 --> 04:16.630
And this is a bit like a never ending while loop.

66
04:16.900 --> 04:21.130
It's constantly checking to see if it needs to update something in the graphical

67
04:21.130 --> 04:25.810
user interface, or if the user has interacted with it in some sort of way.

68
04:26.410 --> 04:31.270
So it will get confused if you have another while loop somewhere near it.

69
04:31.840 --> 04:34.060
So we actually have to comment out this while loop

70
04:34.420 --> 04:38.560
if we want this user interface to work properly. Now,

71
04:38.590 --> 04:40.810
whenever we want to test out our UI,

72
04:40.840 --> 04:44.200
all we have to do is to run our main.py.

73
04:44.860 --> 04:46.570
And once it hits this line,

74
04:46.600 --> 04:51.340
it's going to create a new object from our QuizInterface over here.

75
04:51.850 --> 04:55.090
And once it does that, it's going to hit the init method

76
04:55.420 --> 04:57.310
and it's going to create our new GUI.

77
04:57.940 --> 05:01.540
You can continue coding up your user interface inside this init

78
05:01.840 --> 05:03.880
and it will work just as it did before

79
05:04.030 --> 05:08.680
when you created just a very simple tkinter graphical user interface

80
05:08.710 --> 05:12.100
application. Here comes the challenging part.

81
05:12.670 --> 05:15.790
I want you to create this particular user interface,

82
05:16.300 --> 05:21.300
and I've created a slide that shows you all of the padding, the sizing,

83
05:21.610 --> 05:23.980
the fonts, the background color,

84
05:24.010 --> 05:26.440
and all of the components that go onto this screen.

85
05:27.070 --> 05:31.840
I want you to pause the video here and see if you can create this user interface

86
05:32.050 --> 05:35.380
inside the init method of the quiz interface class.

87
05:36.070 --> 05:38.020
Pause the video now and give that a go.

88
05:38.130 --> 05:38.963
<v 1>Okay.</v>

89
05:42.780 --> 05:43.200
<v 0>All right.</v>

90
05:43.200 --> 05:46.770
So we're going to continue where we left off here inside the init method.

91
05:47.190 --> 05:50.160
And we already started off our window property

92
05:50.190 --> 05:53.100
so we're going to continue making that a little bit better.

93
05:53.490 --> 05:56.940
So we're going to call the config method on this self.window,

94
05:57.350 --> 06:02.210
and we're going to change the padx and the pady so that we add 20 pixels

95
06:02.210 --> 06:05.420
of padding on all four sites. Now,

96
06:05.450 --> 06:08.180
the next thing I want to configure is the background color.

97
06:08.540 --> 06:10.280
And as I mentioned in this slide,

98
06:10.520 --> 06:13.610
we're going to use this theme color that I've already provided here,

99
06:13.940 --> 06:16.070
which is a nice sort of midnight blue.

100
06:16.580 --> 06:19.040
So I'm going to tap into the background attribute

101
06:19.130 --> 06:22.700
and I'm going to set it to this theme color. Now,

102
06:22.730 --> 06:25.130
if we go ahead and run our main file,

103
06:25.490 --> 06:28.550
then we can see our user interface show up.

104
06:30.830 --> 06:32.720
And it's now got the background color

105
06:32.900 --> 06:34.940
and it's a little bit bigger because of the padding.

106
06:35.870 --> 06:39.800
The next step is to create this label up here,

107
06:39.860 --> 06:42.320
which is just a very simple text label.

108
06:42.950 --> 06:46.730
So let's go ahead and create it as a property of this class.

109
06:47.000 --> 06:48.890
So I'm going to call it the score label,

110
06:49.400 --> 06:53.690
and I'm going to create it from the label class of tkinter. I'm going to set

111
06:53.690 --> 06:56.300
the text as just Score: 0.

112
06:57.020 --> 07:00.050
And I'm going to change the color of this text,

113
07:00.080 --> 07:03.410
which is the foreground, to white.

114
07:03.710 --> 07:07.580
That way it will actually be able to show up on this dark background.

115
07:08.510 --> 07:10.790
Now, in order for this label to show up, we,

116
07:10.790 --> 07:13.040
of course, have to give it some sort of layout.

117
07:13.340 --> 07:18.020
So we're going to use the grid and I'm going to set the row to zero

118
07:18.050 --> 07:21.980
cause it's the very top, and then the column to one.

119
07:22.490 --> 07:26.720
So this way it sticks to the right. At this point when we run it,

120
07:26.750 --> 07:28.460
because there is no column zero,

121
07:28.760 --> 07:32.390
it's still going to be just showing up on the screen on the left.

122
07:33.200 --> 07:38.200
And it's also got a white background making it impossible to see the white text.

123
07:39.320 --> 07:44.030
Let's go ahead and change the background of this label to the same theme color.

124
07:44.570 --> 07:48.890
And that way, when we run it, we actually see our label with its white text.

125
07:49.880 --> 07:54.050
That's the label done. And the next step is to create our canvas.

126
07:54.470 --> 07:59.470
Remember that our canvas is really useful because it allows us to layer lots of

127
07:59.540 --> 08:00.470
things on top of it.

128
08:01.220 --> 08:05.120
And we can also set its background and size very easily.

129
08:05.630 --> 08:09.890
So we're going to create this canvas from the canvas class and straight away,

130
08:09.890 --> 08:11.660
I'm going to set the width and height.

131
08:12.020 --> 08:17.020
So the width is going to be 300 and the height is going to be 250

132
08:19.490 --> 08:23.600
as we specified in the slide here. In addition,

133
08:23.600 --> 08:28.600
I'm going to change the background color to white so that it stands out almost

134
08:28.610 --> 08:33.610
like a card on the background. After I've created my canvas,

135
08:33.740 --> 08:38.090
I'm going to add some question_text onto the canvas.

136
08:38.300 --> 08:43.300
So I'm going to create this as the self.canvas.create_text

137
08:44.750 --> 08:48.860
and this is going to have a single attribute called text,

138
08:49.400 --> 08:54.400
and I'm going to set the text to say Some Question Text.

139
08:55.110 --> 08:58.170
So we don't actually have that at the moment. We'll just put in a placeholder.

140
08:59.040 --> 09:02.610
And if you want to, you can actually change the fill color of this text

141
09:02.640 --> 09:06.090
which is the color of the text to the theme color as well

142
09:06.210 --> 09:09.450
just to make it all matchy matchy. Now, finally,

143
09:09.480 --> 09:13.290
we're going to put our canvas onto the screen by giving it a grid.

144
09:13.890 --> 09:18.540
And this time we're going to set the row to one, so below the score label,

145
09:18.990 --> 09:21.390
and then the column I'm going to set it to zero.

146
09:21.810 --> 09:26.810
But then I'm going to set the column span to two so that it starts at column

147
09:27.210 --> 09:31.200
zero and spans two columns to column one.

148
09:31.620 --> 09:33.630
So now when I run this code,

149
09:33.780 --> 09:37.710
I actually get an error and the error is super obscure.

150
09:37.980 --> 09:41.520
Tells me tuple index out of range. Now, if you remember

151
09:41.520 --> 09:43.050
when we worked with tkinter,

152
09:43.080 --> 09:46.470
whenever we add an image or we add something to the canvas,

153
09:46.800 --> 09:51.300
we always have to provide a position as the first two arguments.

154
09:51.840 --> 09:56.700
And that is the tuple that represents the X and Y position of the text.

155
09:57.000 --> 09:58.920
We have to make sure that we don't forget that.

156
09:59.370 --> 10:01.500
So the first value is going to be the X,

157
10:01.530 --> 10:05.160
so that's going to be half of the width so that it's centered on the canvas.

158
10:05.490 --> 10:07.920
So that's 150, half of 300.

159
10:08.280 --> 10:13.050
And then the Y is going to be half of 250, which is going to be 125.

160
10:14.430 --> 10:15.900
Now, if we run this again,

161
10:15.930 --> 10:20.930
hopefully we won't encounter the same error and you can now see this card show

162
10:21.480 --> 10:24.330
up and our label show up on the right,

163
10:24.360 --> 10:28.920
because its in the second column and this is the first column and this canvas

164
10:28.950 --> 10:33.450
spans both columns. Now this text is a little bit small,

165
10:33.450 --> 10:38.400
so let's take a look at the slide and see what we need to change it to.

166
10:38.820 --> 10:42.810
So we want it to be arial font, 20 point size and italic.

167
10:43.800 --> 10:48.800
Let's go ahead and add that to our text. And because its getting a little bit

168
10:48.960 --> 10:49.680
crammed in here,

169
10:49.680 --> 10:54.680
I'm actually going to put this on two separate lines just so I can read it a

170
10:54.810 --> 10:56.790
little bit easier like this.

171
10:58.530 --> 11:03.530
Now we can add that font argument and we're going to set it to a tuple with the

172
11:03.570 --> 11:05.520
first item being the name of the font

173
11:05.910 --> 11:07.770
and then the second is the size of the font

174
11:07.950 --> 11:11.940
and finally we'll also make the text italic as well.

175
11:12.450 --> 11:16.770
So now lets run that again and you'll see the text is now much bigger and its been

176
11:16.770 --> 11:21.770
formatted in the way that we wanted it to. The next thing we want to do is to

177
11:21.930 --> 11:25.950
add a bit of padding between this canvas and the score.

178
11:26.400 --> 11:31.170
So we want to add 50 points of padding here and probably 50 here as well

179
11:31.170 --> 11:36.030
just to push everything a little bit further away from each other. To do that

180
11:36.390 --> 11:41.390
all we have to do is the tap into the canvas grid and then add a single pady.

181
11:42.630 --> 11:45.330
We don't want to add any more padding on the X axis.

182
11:45.390 --> 11:50.040
The original 20 is enough from the window. But we want to add 50

183
11:50.250 --> 11:55.250
so that this way the canvas has some padding on the top and the bottom like this. And it

184
11:56.380 --> 11:59.290
now looks a little bit more spaced out and easier to read.

185
12:00.370 --> 12:01.990
That's pretty much the canvas done.

186
12:02.230 --> 12:04.840
The last thing we need to add are the two buttons.

187
12:05.170 --> 12:09.910
So we'll add a true button and a false button,

188
12:09.970 --> 12:14.970
both created from the button class and neither of them are going to have to any

189
12:15.580 --> 12:16.413
text.

190
12:16.420 --> 12:21.420
Instead we're going to create a true_image from the PhotoImage class,

191
12:22.420 --> 12:25.750
tapping into the file that comes from this folder.

192
12:26.230 --> 12:30.460
So it's images/true.png.

193
12:31.060 --> 12:34.990
And that is the image that we're going to slot in to this button.

194
12:35.850 --> 12:36.683
<v 1>Right.</v>

195
12:38.130 --> 12:39.090
<v 0>Now. In addition,</v>

196
12:39.090 --> 12:43.680
I'm going to set the highlightthickness to zero. This way

197
12:43.680 --> 12:46.620
it doesn't have that weird, awkward border around the button.

198
12:47.430 --> 12:52.430
And I'm also going to put this button onto the screen using the grid method.

199
12:53.220 --> 12:55.830
So now we're onto a row two,

200
12:55.950 --> 12:59.580
so below the canvas, and the column

201
12:59.610 --> 13:04.140
we're going to set it to column zero. Now, depending on what you prefer,

202
13:04.140 --> 13:07.620
you can have the true button on the left or the true button on the right.

203
13:07.890 --> 13:11.070
It doesn't really matter cause it's so big and it's quite easy for the user to

204
13:11.070 --> 13:15.060
see. I'm going to set it on the left, so column zero.

205
13:15.270 --> 13:20.220
And when I run this code, you can see that show up. So using the same method,

206
13:20.250 --> 13:22.350
I'm going to create the false button.

207
13:28.200 --> 13:28.950
<v 1>Right.</v>

208
13:28.950 --> 13:33.870
<v 0>Now we have a true and a false button and we pretty much have our final user</v>

209
13:33.870 --> 13:36.930
interface completed. Now,

210
13:37.080 --> 13:41.250
one of the things you see here is almost everything that I've created inside my

211
13:41.250 --> 13:42.030
init,

212
13:42.030 --> 13:47.030
I've given it the 'self.' And remember from our lessons on OOP, this turns

213
13:48.270 --> 13:52.590
this into a property which can be accessed anywhere in the class.

214
13:53.130 --> 13:57.060
Now, some other things like the true image and the false image,

215
13:57.360 --> 14:01.050
I've not done that for because we're not going to use it anywhere else

216
14:01.290 --> 14:04.050
other than to set up our button right here.

217
14:04.770 --> 14:09.180
This, hopefully, will be a good review of what we learned about Object Oriented

218
14:09.180 --> 14:14.180
Programming and classes and objects as well as tkinter and all of the new stuff

219
14:14.820 --> 14:18.660
around APIs. But this completes the user interface

220
14:18.930 --> 14:21.210
and we're now ready to head over to the next lesson

221
14:21.310 --> 14:24.840
where we're going to fill some text into this question area.

222
14:25.140 --> 14:27.810
So for all of that and more, I'll see you there.