Would you like to inspect the original subtitles? These are the user uploaded subtitles that are being translated:
1
00:00:00,540 --> 00:00:01,560
In the last lesson,
2
00:00:01,589 --> 00:00:05,880
we completed the user interface for our Pomodoro timer,
3
00:00:06,450 --> 00:00:11,130
and we've managed to get all the components that we need onto our graphical user
4
00:00:11,130 --> 00:00:16,050
interface. Now, the next step is to actually give it some functionality.
5
00:00:16,770 --> 00:00:21,480
I want to be able to create some sort of countdown mechanism that just does
6
00:00:21,480 --> 00:00:24,000
something really simple. For example,
7
00:00:24,000 --> 00:00:28,830
if it was just able to count down from five, four, three, two,
8
00:00:29,220 --> 00:00:33,600
one going down by one each time, that would be great.
9
00:00:34,110 --> 00:00:36,420
That's what we're going to be working on in this lesson.
10
00:00:36,480 --> 00:00:40,530
And we're going to go and see the countdown mechanism section to do that.
11
00:00:41,490 --> 00:00:46,470
One of the ways that you might think about approaching this is to use our time
12
00:00:46,470 --> 00:00:47,303
module
13
00:00:47,340 --> 00:00:52,020
cause we've seen before that we can say time.sleep and we can tell it to
14
00:00:52,020 --> 00:00:53,550
sleep for a second.
15
00:00:54,000 --> 00:00:58,980
So then we could maybe set up a while loop and while something or other is true,
16
00:00:59,280 --> 00:01:04,260
go ahead and sleep for one second. And then afterwards just,
17
00:01:04,319 --> 00:01:04,590
you know,
18
00:01:04,590 --> 00:01:09,240
subtract one from some sort of counter. So that we could start count at five
19
00:01:09,240 --> 00:01:14,240
and then each time we subtract by one and then each time we just simply update
20
00:01:15,360 --> 00:01:16,890
our label here,
21
00:01:17,250 --> 00:01:21,750
which we created in the canvas to whatever value count might be.
22
00:01:22,560 --> 00:01:24,990
Now, that sounds great in principle.
23
00:01:25,200 --> 00:01:30,200
The only problem is that we're working within a graphical user interface
24
00:01:30,690 --> 00:01:31,523
program.
25
00:01:32,310 --> 00:01:36,750
The reason why that's relevant is because if we think about a command line
26
00:01:36,750 --> 00:01:38,640
program, say for example,
27
00:01:38,640 --> 00:01:43,020
if we were to get our console to do something, print
28
00:01:43,080 --> 00:01:43,980
hello, well,
29
00:01:43,980 --> 00:01:48,980
it's only going to do something when you actually give it an instruction and you
30
00:01:49,380 --> 00:01:50,213
hit enter.
31
00:01:50,760 --> 00:01:55,530
It doesn't really need to keep an eye out for what you might do in between.
32
00:01:56,130 --> 00:01:59,190
But a graphical user interface is a little bit different.
33
00:01:59,520 --> 00:02:03,690
It needs to keep watching the screen to see whether
34
00:02:03,690 --> 00:02:06,870
if a user clicks on a button, for example.
35
00:02:07,350 --> 00:02:12,350
So it's basically going to refresh and keep listening for events.
36
00:02:13,110 --> 00:02:14,880
So every fraction of a second,
37
00:02:14,880 --> 00:02:16,890
it's going to keep checking, did something happene, did
38
00:02:16,920 --> 00:02:20,760
something happen, did something happen. And the moment when it does,
39
00:02:20,850 --> 00:02:24,510
then it's got to react. It's got to react to that event.
40
00:02:25,050 --> 00:02:30,030
In this case, we tend to call these types of GUI programs event-driven.
41
00:02:30,690 --> 00:02:35,040
And the way that it's driven is through our main loop.
42
00:02:35,490 --> 00:02:39,450
So when we set up our window and we start off the main loop,
43
00:02:39,780 --> 00:02:44,780
it's basically looping through and every millisecond it's checking to see did
44
00:02:44,940 --> 00:02:47,730
something happen, did something happen, did something happen?
45
00:02:48,210 --> 00:02:51,090
So that means if we have another loop in our program,
46
00:02:51,120 --> 00:02:55,200
it actually won't be able to reach the main loop. And in this case,
47
00:02:55,230 --> 00:02:57,780
when you actually try to run it, nothing happens.
48
00:02:57,840 --> 00:02:59,830
Our program doesn't even launch.
49
00:03:00,340 --> 00:03:05,260
So we have to rethink this and we have to do it a little bit differently. In
50
00:03:05,260 --> 00:03:08,950
order to create interactive and interesting programs,
51
00:03:09,370 --> 00:03:12,640
you kind of need something to happen on screen, right?
52
00:03:12,640 --> 00:03:16,750
Every so often. You need this timing mechanism. Luckily,
53
00:03:16,780 --> 00:03:18,820
tkinter already thought of this.
54
00:03:19,150 --> 00:03:23,800
And we can in fact use one of the builtin methods to every widget.
55
00:03:24,220 --> 00:03:26,140
So if we tap into our window widget,
56
00:03:26,290 --> 00:03:31,290
we can get hold of a method called after and after is quite simple.
57
00:03:32,230 --> 00:03:36,760
It's a method that takes an amount of time that it should wait
58
00:03:37,270 --> 00:03:39,190
and then after that amount of time,
59
00:03:39,460 --> 00:03:44,460
it simply calls a particular function that you tell it to call passing in any
60
00:03:44,650 --> 00:03:48,760
arguments that you want to give it. Here's how it works.
61
00:03:48,820 --> 00:03:53,820
We call window.after, we first provide the amount of time to wait in
62
00:03:54,460 --> 00:03:58,720
milliseconds. So if we want one second, then that's 1000 milliseconds.
63
00:03:59,320 --> 00:04:02,200
Next we pass in a function to call.
64
00:04:02,530 --> 00:04:07,390
So let's create a function up here. Let's just call it, say something,
65
00:04:07,990 --> 00:04:10,330
and then we'll pass in the thing,
66
00:04:12,610 --> 00:04:16,420
like this. And then all we do is we just print that thing.
67
00:04:16,959 --> 00:04:18,760
So super simple function.
68
00:04:18,790 --> 00:04:23,790
And then we give the name of this function as the function to call after 1000
69
00:04:24,310 --> 00:04:25,143
milliseconds.
70
00:04:25,600 --> 00:04:29,590
Now the final thing in this list of arguments,
71
00:04:29,920 --> 00:04:34,090
if I just go ahead and cut that and show you again, when it gives me the prompt,
72
00:04:34,510 --> 00:04:39,010
the last thing is actually a *args.
73
00:04:39,490 --> 00:04:44,230
This, if you remember, allows us to put in an unlimited number
74
00:04:44,290 --> 00:04:46,090
of positional arguments.
75
00:04:46,600 --> 00:04:50,890
What that means is we can give as many arguments as we want
76
00:04:51,220 --> 00:04:56,220
and those arguments, in this case, is simply going to be passed to the function
77
00:04:56,350 --> 00:04:59,920
that we want to call. So in this case, it's going to be that thing.
78
00:05:00,190 --> 00:05:03,580
So if I put hello here then I run my code,
79
00:05:03,940 --> 00:05:07,990
you can see that after 1000 milliseconds, basically one second,
80
00:05:08,440 --> 00:05:10,750
it calls this function,
81
00:05:10,810 --> 00:05:15,400
say_something, and it passes this hello as the input
82
00:05:15,580 --> 00:05:18,370
to that function. As I said,
83
00:05:18,400 --> 00:05:22,000
you can have an infinite amount of positional arguments.
84
00:05:22,330 --> 00:05:26,530
So let's put in some other arguments which we'll call a,
85
00:05:26,530 --> 00:05:27,363
b, and c,
86
00:05:27,610 --> 00:05:32,320
and then we'll print a, print b, and print c.
87
00:05:33,970 --> 00:05:36,640
And now instead of passing in hello,
88
00:05:36,670 --> 00:05:41,650
we're going to pass in lots of positional parameters. So we'll say 3, 5,
89
00:05:41,680 --> 00:05:44,500
and 8. Now, when I hit run,
90
00:05:44,560 --> 00:05:46,840
you will see it waits for one second
91
00:05:47,170 --> 00:05:51,850
and then it passes all three of these parameters to say something
92
00:05:52,270 --> 00:05:55,480
and it goes ahead and prints all of those out at once.
93
00:05:56,050 --> 00:06:01,010
So this is how the after method works. But what we wanted to do though,
94
00:06:01,370 --> 00:06:03,920
is we want it to repeat itself,
95
00:06:04,010 --> 00:06:09,010
to essentially loop. One way of getting that behavior is to simply put this
96
00:06:10,760 --> 00:06:11,240
method,
97
00:06:11,240 --> 00:06:16,240
call somewhere inside a function and then call itself.
98
00:06:16,370 --> 00:06:20,930
So here's what I mean. Let's create a function called a count_down,
99
00:06:21,740 --> 00:06:26,740
and this is going to take a input in the form of the number to count down by.
100
00:06:28,550 --> 00:06:32,270
And then inside this function, we call window.after.
101
00:06:32,720 --> 00:06:35,510
And we say that after 1000 milliseconds,
102
00:06:35,750 --> 00:06:40,750
call this function count_down and then pass in a count number.
103
00:06:44,570 --> 00:06:47,390
If that count number started out as 5,
104
00:06:47,630 --> 00:06:50,840
then we want to say count - 1.
105
00:06:51,320 --> 00:06:55,700
Now all we have to do is to call this countdown method.
106
00:06:56,030 --> 00:07:00,530
So let's call count_down and passing the starting count,
107
00:07:00,590 --> 00:07:04,430
let's say 5 seconds. So now when I run the code,
108
00:07:04,430 --> 00:07:07,760
it's going to call this method passing in 5 over here,
109
00:07:08,300 --> 00:07:11,720
and then it's going to wait for one second,
110
00:07:12,110 --> 00:07:17,060
and then it's going to call this function count_down passing in five minus one
111
00:07:17,240 --> 00:07:21,920
so it becomes four. And then afterward it repeats again, becomes three,
112
00:07:21,950 --> 00:07:26,180
two, one. So now if we catch that number
113
00:07:26,360 --> 00:07:30,500
which we can print, then we'll be able to see it count down
114
00:07:30,530 --> 00:07:34,190
when we run the code; five, four, three,
115
00:07:34,580 --> 00:07:38,390
two, one. One every second,
116
00:07:38,450 --> 00:07:42,770
and it basically keeps on going and it even continues to the negatives.
117
00:07:43,310 --> 00:07:46,310
So if we don't want it to go to negative time,
118
00:07:46,340 --> 00:07:49,220
then all we have to do is add an if statement.
119
00:07:49,640 --> 00:07:54,620
If count is greater than zero, then go ahead and execute this line of code.
120
00:07:55,880 --> 00:07:59,780
So now it'll go from five, four, three, two,
121
00:07:59,810 --> 00:08:02,570
one, zero, and then it will stop.
122
00:08:03,470 --> 00:08:08,450
This is the kind of behavior that we would need if we want to update our
123
00:08:08,450 --> 00:08:11,180
countdown in our Pomodoro timer.
124
00:08:11,900 --> 00:08:14,180
So how can we instead of printing
125
00:08:14,180 --> 00:08:19,180
the count actually change this text on our canvas? We'll,
126
00:08:19,820 --> 00:08:24,820
the way that we do that is by assigning this text a variable.
127
00:08:25,430 --> 00:08:28,460
So I'm going to call it timer_text
128
00:08:29,870 --> 00:08:34,870
and now that we've got timer_text being a set as the text that was created in
129
00:08:35,360 --> 00:08:38,870
the canvas, then we can access it right here.
130
00:08:39,620 --> 00:08:44,120
And the way that we'd change a piece of text or anything for that matter in a
131
00:08:44,120 --> 00:08:48,110
canvas is slightly different from how we would do for a label.
132
00:08:48,530 --> 00:08:52,070
If it was just the title label that we wanted to change, we would say title_
133
00:08:52,070 --> 00:08:56,310
label.config, and then let's change the text to something new.
134
00:08:56,940 --> 00:08:58,920
But to change a canvas element,
135
00:08:58,950 --> 00:09:02,640
you actually have to tap into the particular canvas you want to change and
136
00:09:03,240 --> 00:09:08,220
Then you call a method called itemconfig. And then in this method,
137
00:09:08,280 --> 00:09:12,240
you pass in the particular item that you actually want to configure,
138
00:09:12,540 --> 00:09:14,910
so in our case it's the timer_text,
139
00:09:15,570 --> 00:09:20,570
and then you pass in the thing about it that you actually want to change in
140
00:09:20,970 --> 00:09:24,300
terms of a kwarg, so this is a keyword argument.
141
00:09:24,870 --> 00:09:28,380
We're going to change the text to the current count.
142
00:09:28,650 --> 00:09:31,620
Now notice how this is not the string count,
143
00:09:31,830 --> 00:09:34,290
because then it would just show that word,
144
00:09:34,620 --> 00:09:39,270
but its actually the live countdown time. At this point in time
145
00:09:39,300 --> 00:09:40,500
if I run the code,
146
00:09:40,500 --> 00:09:45,500
I actually get a error and it tells us that the name canvas is not defined
147
00:09:46,320 --> 00:09:50,940
and that's because I'm calling this method countdown before I actually created
148
00:09:50,940 --> 00:09:51,690
the canvas.
149
00:09:51,690 --> 00:09:56,250
So if I move that to below this line and I run it again,
150
00:09:56,280 --> 00:09:58,020
then you'll see it actually work.
151
00:09:58,320 --> 00:10:02,370
And you see it starts out from five and it counts down to zero.
152
00:10:03,180 --> 00:10:08,180
Now how can we tie that behavior to the start button so that I can press the
153
00:10:08,250 --> 00:10:13,140
start button and then and only then does it start counting down from five,
154
00:10:13,140 --> 00:10:17,700
four, three, two, one? Well, let's go ahead and add
155
00:10:17,760 --> 00:10:22,500
another function and I'm gonna add it in the timer mechanism section and I'm
156
00:10:22,500 --> 00:10:24,120
going to call it start_timer.
157
00:10:24,900 --> 00:10:27,750
Now this function is super simple.
158
00:10:27,930 --> 00:10:32,930
All it's going to do is it's going to be responsible for calling that function
159
00:10:33,030 --> 00:10:36,660
countdown and it's going to count down from five seconds.
160
00:10:36,810 --> 00:10:39,840
So I'll move that inside the start_timer.
161
00:10:40,500 --> 00:10:45,500
And now the start timer is going to be the function that needs to be triggered
162
00:10:47,070 --> 00:10:49,560
when the start button gets pressed.
163
00:10:49,920 --> 00:10:53,280
Do you remember how to tie a function to a button in
164
00:10:53,280 --> 00:10:58,260
tkinter? Pause the video and see if you can solve this challenge so that you'll
165
00:10:58,260 --> 00:11:03,260
be able to run the code, hit start and the timer to start counting down.
166
00:11:06,630 --> 00:11:11,630
So the keyword argument is command and all we have to do is to tie it to the
167
00:11:12,210 --> 00:11:15,990
start_timer function, but without the parentheses.
168
00:11:16,500 --> 00:11:19,920
So now when I hit run and I click start,
169
00:11:20,340 --> 00:11:24,840
it starts the timer setting that text from five, four, three,
170
00:11:24,930 --> 00:11:25,763
two, one.
171
00:11:26,220 --> 00:11:31,220
So the main loop is listening and when the user interacts with the start button
172
00:11:31,890 --> 00:11:36,660
it actually calls the start_timer function which calls the count_down function
173
00:11:36,960 --> 00:11:39,900
and get it to count down from five seconds.
174
00:11:40,560 --> 00:11:43,980
Now we don't actually want to count down from five seconds.
175
00:11:44,010 --> 00:11:48,750
We want to count down in minutes because we're probably not going to be working
176
00:11:48,750 --> 00:11:50,130
for five seconds at a time.
177
00:11:50,160 --> 00:11:54,040
We're going to be working for 25 minutes or having a minute break.
178
00:11:54,580 --> 00:11:59,580
So how can I change this countdown to interpret this instead of as five seconds
179
00:12:01,390 --> 00:12:04,990
to five minutes? Well, let's have a think about that.
180
00:12:05,680 --> 00:12:09,850
If we wanted to count down, let's say one minute,
181
00:12:10,240 --> 00:12:14,230
then that in terms of seconds would be 60 seconds.
182
00:12:14,860 --> 00:12:18,670
All we have to do is to take the number of minutes that we want to count down
183
00:12:18,670 --> 00:12:22,540
by and multiply it by 60. In this case,
184
00:12:22,540 --> 00:12:27,040
if we wanted to count down it by five minutes instead of five seconds,
185
00:12:27,400 --> 00:12:30,160
all we have to do is multiply by 60.
186
00:12:30,670 --> 00:12:33,880
So then when we call this function count_down,
187
00:12:34,150 --> 00:12:36,790
instead of getting five seconds to count down,
188
00:12:36,820 --> 00:12:39,190
we get 300 seconds to count from.
189
00:12:39,880 --> 00:12:44,470
But now if we run our code, you can see it's going to start from 300.
190
00:12:44,740 --> 00:12:49,240
It's going to go down all the way down to zero. Now in terms of time,
191
00:12:49,390 --> 00:12:54,040
that is five minutes, but this is not a very good way to visualize it.
192
00:12:54,370 --> 00:12:58,570
Nobody thinks in terms of 288 seconds remaining, right?
193
00:12:59,140 --> 00:13:04,140
So we have to format this count so that we can display it in the format of
194
00:13:04,720 --> 00:13:09,010
00:00 like the usual kind of time, where for example,
195
00:13:09,010 --> 00:13:14,010
you have one minute and 35 seconds remaining or something like that.
196
00:13:15,520 --> 00:13:20,520
So how can we create something like this? If we have the count in terms of
197
00:13:20,680 --> 00:13:21,220
seconds,
198
00:13:21,220 --> 00:13:26,220
so let's say we have 300, and we wanted to know how many minutes where in that
199
00:13:26,800 --> 00:13:31,800
then all we have to do is take 300 and then divide it by 60 and we would get
200
00:13:32,680 --> 00:13:37,150
5, so that's 5 minutes. But what if the countdown has already been going
201
00:13:37,210 --> 00:13:42,210
and instead we had 245 seconds remaining?
202
00:13:42,790 --> 00:13:43,000
Well,
203
00:13:43,000 --> 00:13:48,000
we can actually get hold of how many minutes and seconds that is equivalent to.
204
00:13:50,020 --> 00:13:54,430
And the way we would do that is by taking that number, say 245,
205
00:13:54,760 --> 00:13:56,920
dividing it by 60 seconds
206
00:13:57,280 --> 00:14:02,280
and we would get a number 245 / 60 is 4.08,
207
00:14:05,440 --> 00:14:06,820
3 recurring.
208
00:14:07,570 --> 00:14:12,570
If we rounded that number down to get rid of all of the decimal places,
209
00:14:13,240 --> 00:14:16,060
then that would be equal to 4 minutes.
210
00:14:16,810 --> 00:14:21,810
And then if we want to get hold of how many seconds there are after we've gotten
211
00:14:22,420 --> 00:14:23,620
hold of the four minutes,
212
00:14:24,010 --> 00:14:29,010
then the way we do that is to use the modular because remember the modular
213
00:14:29,650 --> 00:14:34,450
divides a number by another number, so 245 divided by 60,
214
00:14:34,870 --> 00:14:37,240
and then it will give us the remainder.
215
00:14:37,420 --> 00:14:42,280
How much is left after it's cleanly divided. And in this case,
216
00:14:42,340 --> 00:14:47,340
this would actually be the number of seconds remaining after the four minutes
217
00:14:48,100 --> 00:14:51,650
has been taken away. So let's write this code out.
218
00:14:52,550 --> 00:14:57,550
The count minutes would be the count divided by 60,
219
00:14:59,780 --> 00:15:04,330
but then we have to round it down so that we get rid of all of the remainder.
220
00:15:04,330 --> 00:15:09,110
Now we don't want to round it so that if it was something like 3.6
221
00:15:09,170 --> 00:15:10,640
it becomes 4.
222
00:15:10,910 --> 00:15:15,770
We actually just want to get rid of everything after the decimal place. To do
223
00:15:15,770 --> 00:15:16,310
that,
224
00:15:16,310 --> 00:15:21,310
the easiest way is to import the math module and then use a function called math
225
00:15:23,870 --> 00:15:27,800
.floor and this math.floor,
226
00:15:27,830 --> 00:15:32,830
if I hover over it, is going to return the largest whole number that is less than
227
00:15:36,020 --> 00:15:37,310
or equal to x.
228
00:15:37,790 --> 00:15:42,790
If this was a 4.8, then the largest hole number less than 4.8 is 4.
229
00:15:46,250 --> 00:15:47,960
So that's basically what this is going to do.
230
00:15:48,170 --> 00:15:51,020
And this is going to give us the number of minutes. Now,
231
00:15:51,020 --> 00:15:53,000
the next thing we want to do is to know, well,
232
00:15:53,000 --> 00:15:58,000
how many seconds is left after we've taken away the minutes. To do this,
233
00:15:58,700 --> 00:15:59,660
we're going to do counts
234
00:15:59,720 --> 00:16:03,200
and then we're going to use the modulo to divide it by 60.
235
00:16:03,770 --> 00:16:08,770
So the modulo is going to give us the remainder number of seconds after we've
236
00:16:09,440 --> 00:16:12,650
cleanly divided it by 600. For example,
237
00:16:12,650 --> 00:16:16,250
if we had 100 seconds and we divide that by 60, well,
238
00:16:16,250 --> 00:16:17,870
that's going to be equal to one.
239
00:16:18,290 --> 00:16:23,290
So we can minus 60 from 100 and we get 40 as the remainder.
240
00:16:25,010 --> 00:16:27,830
That is what we will get after doing the modulo.
241
00:16:28,430 --> 00:16:31,220
So that's basically the number of seconds that remains.
242
00:16:32,240 --> 00:16:36,260
So now that we've got the minute and the second, we can actually change this
243
00:16:36,260 --> 00:16:41,260
count to use an f-string and we can format it so that we add the count minute
244
00:16:42,170 --> 00:16:43,003
first,
245
00:16:43,130 --> 00:16:48,130
and then we add a colon and then we add our count in seconds.
246
00:16:49,430 --> 00:16:53,900
Now look at what happens. We're going to try and count down five minutes.
247
00:16:54,260 --> 00:16:58,490
So we get hold of the number of seconds, we pass it over to this function,
248
00:16:58,880 --> 00:17:03,080
we work out what the count is equivalent to in minutes and seconds
249
00:17:03,470 --> 00:17:06,920
and then afterwards we subtract one second each time.
250
00:17:07,520 --> 00:17:10,310
So now when I run the code and I hit start,
251
00:17:10,640 --> 00:17:14,270
notice how it starts from 5 minutes, goes down to 4 minutes,
252
00:17:14,270 --> 00:17:15,980
50, 59,
253
00:17:16,069 --> 00:17:19,310
and then it keeps ongoing like a real timer.
254
00:17:20,180 --> 00:17:21,440
That's pretty cool.
255
00:17:21,650 --> 00:17:26,650
The only thing left to figure out is how can we get it to not display 5:0?
256
00:17:27,349 --> 00:17:32,060
How can we get it to display 5:00
257
00:17:32,840 --> 00:17:36,260
like you would see on a clock? To find out how to do that
258
00:17:36,290 --> 00:17:39,170
we have to learn about Python dynamic typing.
259
00:17:39,440 --> 00:17:43,370
We have to understand how that works and that is what we're going to be talking
260
00:17:43,370 --> 00:17:46,340
about in the next lesson. So I'll see you there.
24071
Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.