This article was written as the 9th day article of IS17er Advent Calendar. Click here for the article on Day 8.
I made a timer app that can be started from the terminal using a library called Tkinter in Python. You can see how it works by looking at the image. Please use it by all means!
Recently, my concentration has dropped, and when I was sitting in front of my computer, two hours had passed before I knew it, so I made a timer that can be easily started from the terminal so that I can concentrate for a short time and manage the time. I decided to do it (yesterday evening).
(When I was writing this section, I wasn't writing the program yet)
As an image of the application to be created this time, for example
$ tmr 5m30s -t kadai
The image is that if you hit a command like this, a small window will appear in the upper right corner of the screen and count down. -t
is optionally the title of the timer. Even if I implement a very complicated function, I will not use it, so I wonder if this is all right for the time being. I wonder if there is an optional notification sound like Slack. After that, if the color changes randomly every time you start it, you can use it without getting bored.
I haven't written a desktop application at all because it's usually a web-based application, but when I googled it a bit, Tkinter seems to be fun, so I wrote this. I decided to use it. It seems that you can easily create a GUI with Python using Tkinter.
The code was about 100 lines, so paste it all. Because of this shortness, I made it into one file. Feel free to customize it.
tmr.py
#!/usr/bin/env python
# -*- coding: utf8 -*-
import sys
import re
import argparse
import random
import Tkinter as tk
class App():
def __init__(self):
self.window_size = 150
self.fps = 10
self.font_size = 23
self.option = self.parse_args()
self.time = self.get_timesec()
self.period = self.time
self.root = self.set_root()
self.canvas = self.set_canvas()
self.label = self.set_label()
self.progress = self.init_progress()
self.update()
self.run()
def parse_args(self):
parser = argparse.ArgumentParser(description="Show simple countdown timer on desktop.")
parser.add_argument("period", action="store", type=str, help="Set period for your timer.")
parser.add_argument("-t", dest="title", action="store", default="Timer", help="Set title for your timer.")
parser.add_argument("-n", dest="notify", action="store_false", default=True, help="Disable notification.")
return parser.parse_args()
def get_timesec(self):
if re.search("\A(?:\d+h)?(?:\d+m)?(?:\d+s)?$", self.option.period) is None:
print "Incorrect format of period:", self.option.period
print "Set period like 10m30s"
sys.exit()
time = 0
if re.search("\d+h", self.option.period) is not None:
time += int(re.search("\d+h", self.option.period).group(0)[:-1]) * 3600
if re.search("\d+m", self.option.period) is not None:
time += int(re.search("\d+m", self.option.period).group(0)[:-1]) * 60
if re.search("\d+s", self.option.period) is not None:
time += int(re.search("\d+s", self.option.period).group(0)[:-1])
if time > 9 * 3600 + 59 * 60 + 59:
print "Too long period."
sys.exit()
return time
def set_root(self):
root = tk.Tk()
root.resizable(0,0)
window_size = self.window_size
colors = ["#f44336", "#E91E63", "#9C27B0", "#673AB7", "#3F51B5", "#2196F3", "#03A9F4", "#00BCD4", "#009688", "#4CAF50", "#8BC34A", "#CDDC39", "#FFEB3B", "#FFC107", "#FF9800", "#FF5722", "#795548", "#9E9E9E", "#607D8B"]
root.title(self.option.title)
root.geometry("%dx%d+%d+%d" % (window_size, window_size, root.winfo_screenwidth() - window_size, 0))
root.configure(bg=random.choice(colors))
root.attributes("-alpha", 0.5)
root.attributes("-topmost", True)
return root
def set_label(self):
window_size = self.window_size
label = self.canvas.create_text((window_size / 2, window_size / 2), text="")
self.canvas.itemconfig(label, font=("Menlo-Regular", self.font_size))
return label
def set_canvas(self):
window_size = self.window_size
canvas = tk.Canvas(self.root, width=window_size, height=window_size, highlightthickness=0)
canvas.grid()
return canvas
def format_time(self, timesec):
m, s = divmod(timesec, 60)
h, m = divmod(m, 60)
if h == 0:
if m == 0:
return "%02ds" % (s)
else:
return "%02dm%02ds" % (m, s)
else:
return "%dh%02dm%02ds" % (h, m, s)
def init_progress(self):
color = self.root["bg"]
window_size = self.window_size
progress = self.canvas.create_arc(window_size * 0.1, window_size * 0.1, window_size * 0.9, window_size * 0.9, style="arc", width="%d" % (window_size / 15), outline=color, start=90, extent=360)
return progress
def update(self):
window_size = self.window_size
self.canvas.itemconfig(self.label, text=self.format_time(self.time))
extent = 360.0 * self.time / self.period
self.canvas.itemconfig(self.progress, start=450-extent, extent=extent)
self.time -= 1.0 / self.fps
if self.time < 0:
if self.option.notify:
print '\a'
sys.exit()
self.root.after(1000 / self.fps, self.update)
def run(self):
self.root.mainloop()
app = App()
I wrote it on GitHub, but here I dare not clone it.
chmod 755 tmr
export PATH = $ PATH: / Users / [username] / timer
to `~ / .bash_rc``` or
`~ / .bash_profile```. If you don't understand this, google the addition of PATH.`source ~ / .bash_rc``` or
`source ~ / .bash_profile``` and restart the terminalActually, there are quite a few, but for the time being, there are some.
It's a regular expression that everyone loves.
"\A(?:\d+h)?(?:\d+m)?(?:\d+s)?$"This is the beginning"\A(?:\d+h)?(?:\d+m)?(?:\d+s)?\z"I wrote that and mass-produced None forever. Get used to regular expressions.
#### How to write code concisely
Python comes with a large number of useful functions as standard, so it's a good idea to look it up first if you want to write something yourself. In most cases, it's faster to write it yourself, but it's still a bad practice because the corner case processing is troublesome and readability is reduced, so I just googled the existing functions. Moreover, in the case of Python, multiple existing functions often behave in the same way, so it took time to choose a library so that there was a good sense of unity among the existing functions. This may be an occupational disease.
## at the end
You can clone it from [GitHub](https://github.com/xuzijian629/timer), so please use it (if you have trouble, you can copy the code as it is). I'm glad to cry if you star! Also, notification sounds etc. are not implemented at the time of writing, so I may add them later.
As an aside, on the Mac there is a genius command called `` `say```
```$ sleep 100 &&say end```
If you do something like that, it will read "End" after 100 seconds (if the language is set to Japanese).
Well then, See you tomorrow~
[Addition] Notification sound has been implemented (the above code has been corrected).
```print '\a'```
You can go! Isn't it a Python god ...!
Recommended Posts