I'm new to python. I saw an article saying, "Because you can easily make a timer with python, I recommend a timer for beginners!", So I decided to swallow it and make a timer. It's not fun just to measure the time, so we will add a function that "If you set an hourly wage, the salary will be calculated according to the working hours".
--Timer related --Timer that can be moved with the "Start", "Pause", and "Done" buttons --Calculate salary from hourly wage and timer time --Reset the timer during startup (to prevent extra salary if you accidentally press the start button)
--Money related --Change of hourly wage --Reset salary
--History related --Timer activation history (start date and time, end date and time, timer time) -↑ Delete this history (1 / all) --Display of total working hours
The screen at startup looks like this.
When you press the "Start" button, the timer will start and the "Start" button will change to the "Pause" button.
When you press the "Pause" button, the timer pauses and changes to the "Resume" button.
When you press the "Finish" button, the timer time is recorded and the salary is calculated using the set hourly wage. Press the "Reset" button to return to the state before the timer started without calculating the salary. By the way, if you press these buttons while the timer is not running, nothing happens.
To prevent accidental clicks, a confirmation window like this is displayed when the "Finish" and "Reset" buttons are pressed.
When you press the "Salary withdrawal" button, a confirmation window will be issued again to withdraw the salary (change "Salary: ○ Yen" to "Salary: 0 Yen").
On the "Record" tab, you can see the history of the timer. For example, "06/02 00: 12-00: 14 00:08" at the top is "Press the start button at 00:12 on 6/2 and press the finish button at 00:14. Timer at completion The notation of is 00:08 ".
I added this history function because I wanted to know when I could concentrate the most.
Each item can be selected in this way and can be deleted with the "Delete" button. You can delete all items with the "Delete All" button.
You can see the salary withdrawal record.
You can check / reset the total working hours and change the hourly wage.
If you enter a value other than an integer value in the hourly wage column, an error window will appear and the hourly wage will not be changed.
app.py
#-*-coding: utf-8 -*-
import tkinter as tk
from tkinter import ttk,messagebox
from time import time
import datetime
import pickle
class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.pack()
master.title("Attendance management")
master.geometry("350x170")
#Initial value setting
self.wage = 1000 #Hourly wage
self.have_money = 0 #Salary
self.total = 0 #Total time (seconds) of the currently running timer
self.record_list = [] #Timer time recording
self.money_record_list = [] #Salary withdrawal record
self.data_list = [self.wage,self.have_money,self.record_list,self.money_record_list,self.total]
#Data loading
self.load_data()
#Create tabs and content
self.create_tabs()
self.create_main(self.main)
self.create_record(self.record)
self.create_history(self.history)
self.create_setting(self.setting)
#Create tab/Installation
def create_tabs(self):
self.notebook = tk.ttk.Notebook()
self.main = tk.Frame(self.notebook)
self.setting = tk.Frame(self.notebook)
self.history = tk.Frame(self.notebook)
self.record = tk.Frame(self.notebook)
self.notebook.add(self.main, text="Main screen")
self.notebook.add(self.record, text="Record")
self.notebook.add(self.history, text="Drawer record")
self.notebook.add(self.setting, text="Setting")
self.notebook.pack(expand=True, fill="both")
#"Main screen" tab
def create_main(self,master):
lb_1 = tk.Label(master, text="Working hours")
lb_1.place(x=10, y=0)
self.canvas = tk.Canvas(master,width=290,height=80)
self.canvas.place(x=10,y=20)
self.spbt = tk.Button(master,text="start",command=self.start_pause_button,width=10)
self.spbt.place(x=250, y=20)
tk.Button(master,text="Done",command=self.stop_button_click,width=10).place(x=250, y=50)
tk.Button(master,text="reset",command=self.reset_button_click,width=10).place(x=250, y=80)
tk.Button(master,text="Payroll withdrawal",command=self.withdraw,width=10).place(x=10, y=115)
self.wage_var = tk.StringVar()
lb_2 = tk.Label(master,textvariable=self.wage_var)
self.wage_var.set("Hourly wage: {0}Circle".format(self.wage))
lb_2.place(x=10, y=90)
self.money_var = tk.StringVar()
lb_3 = tk.Label(master, textvariable=self.money_var)
self.money_var.set("Salary: {0}Circle".format(int(self.have_money)))
lb_3.place(x=100, y=90)
self.stop_time = 0.0
self.elapsed_time = 0.0 #Currently measuring time (time displayed on the timer) (seconds)
self.timer_running = False #True if the timer is running, False if it is stopped
master.after(50,self.update)
#"Record" tab
def create_record(self,master):
self.record_lb = tk.Listbox(master,width=42,height=8)
self.record_lb.place(x=0,y=0)
self.record_load() #Output the record saved in the dat file
tk.Button(master,text="Delete",command=self.del_record,width=10).place(x=260, y=0) #データを1件Delete
tk.Button(master,text="Delete all",command=self.del_all_records,width=10).place(x=260, y=30) #Delete all data
#Drawer record tab
def create_history(self,master):
self.money_record_lb = tk.Listbox(master,width=42,height=8)
self.money_record_lb.place(x=0,y=0)
self.money_record_load() #Output the withdrawal record saved in the dat file
tk.Button(master,text="Delete",command=self.del_money_record,width=10).place(x=260, y=0) #データ1件Delete
tk.Button(master,text="Delete all",command=self.del_all_money_records,width=10).place(x=260, y=30) #Delete all data
#"Settings" tab
def create_setting(self,master):
#Change of hourly wage
lb_1 = tk.Label(master, text="・ Hourly wage")
lb_1.place(x=5,y=3)
value = tk.StringVar()
value.set(self.wage)
self.wage_sp = tk.Spinbox(master,textvariable=value,from_=0,to=100000000,width=8,increment=50)
self.wage_sp.place(x=50,y=6)
tk.Button(master,text="Change",command=self.chg_wage,width=5).place(x=120, y=2)
#Reset total working hours
self.total_var = tk.StringVar()
lb_2 = tk.Label(master, textvariable=self.total_var)
self.str_total = self.strtime(self.total)
self.total_var.set("・ Total working time{0}".format(self.str_total))
lb_2.place(x=5,y=40)
tk.Button(master,text="reset",command=self.reset_total_click,width=5).place(x=135, y=35)
#start/When the pause button is pressed
def start_pause_button(self):
if self.timer_running:
self.pause_timer()
self.spbt["text"] = "Resume"
else:
#Get the time when you press "Start" instead of "Resume"
if not self.elapsed_time:
self.dt_start = datetime.datetime.now() #Get timer start time (to save as record)
self.start_timer()
self.spbt["text"] = "pause"
#Timer start
def start_timer(self):
if not self.timer_running:
self.start_time = time() - self.elapsed_time
self.timer_running = True
#Timer pause
def pause_timer(self):
if self.timer_running:
self.stop_time = time() - self.start_time #Timer display time when the pause button is pressed
self.timer_running = False
#When the Done button is pressed
def stop_button_click(self):
if self.elapsed_time:
msgbox = messagebox.askyesno("Verification","Are you sure you want to complete the recording?")
if msgbox:
self.start_time = time()
self.add_wage()
self.add_total()
self.dt_stop = datetime.datetime.now()
self.new_record()
self.spbt["text"] = "start"
self.stop_time = 0.0
self.elapsed_time = 0.0
self.timer_running = False
self.save_data()
#When the reset button is pressed
def reset_button_click(self):
if self.elapsed_time:
msgbox = messagebox.askyesno("Verification","Do you want to reset the stopwatch?")
if msgbox:
self.spbt["text"] = "start"
self.resettimer()
#Timer reset
def resettimer(self):
self.start_time = time()
self.stop_time = 0.0
self.elapsed_time = 0.0
self.timer_running = False
#Update timer time
def update(self):
self.canvas.delete("time")
if self.timer_running:
self.elapsed_time = time() - self.start_time
elapsed_time_str = self.strtime(self.elapsed_time)
self.canvas.create_text(200,40,text=elapsed_time_str,font=("Helvetica",40,"bold"),fill="black",tag="time",anchor="e")
else:
stop_time_str = self.strtime(self.stop_time)
self.canvas.create_text(200,40,text=stop_time_str,font=("Helvetica",40,"bold"),fill="black",tag="time",anchor="e")
self.master.after(50,self.update)
#Add salary when timer stops
def add_wage(self):
self.have_money += int(self.wage) * self.elapsed_time / 3600
self.money_var.set("Salary: {0}Circle".format(int(self.have_money)))
#Record the previous record
def new_record(self):
start_date = self.dt_start.strftime("%m/%d")
start_time = self.dt_start.strftime("%H:%M")
stop_time = self.dt_stop.strftime("%H:%M")
elapsed_time = self.strtime(self.elapsed_time)
str_record = "{0} {1}~{2} {3}".format(start_date,start_time,stop_time,elapsed_time)
self.record_lb.insert(0,str_record)
self.record_list.insert(0,str_record)
#Delete record (1 case)
def del_record(self):
index = self.record_lb.curselection()
if index:
msgbox = messagebox.askyesno("Verification","Are you sure you want to delete the selected record?")
if msgbox:
self.record_lb.delete(int(index[0]))
self.record_list.pop(int(index[0]))
self.record_lb.select_set(int(index[0])-1)
self.save_data()
#Delete all records
def del_all_records(self):
print(self.record_lb.size())
if self.record_lb.size() != 0:
msgbox = messagebox.askyesno("Verification","Are you sure you want to delete all records?")
if msgbox:
self.record_lb.delete(0,tk.END)
self.record_list.clear()
self.save_data()
#Payroll withdrawal
def withdraw(self):
if self.have_money:
msgbox = messagebox.askyesno("Verification","Do you want to withdraw your salary?")
if msgbox:
self.dt_wd = datetime.datetime.now()
self.add_money_record()
self.have_money = 0
self.money_var.set("Salary: {0}Circle".format(int(self.have_money)))
self.save_data()
#Added last payroll withdrawal record
def add_money_record(self):
wd_time = self.dt_wd.strftime("%m/%d %H:%M")
record_money = int(self.have_money)
str_money_record = "{0} -{1}Circle".format(wd_time,record_money)
self.money_record_lb.insert(0,str_money_record)
self.money_record_list.insert(0,str_money_record)
#Delete withdrawal record (1 case)
def del_money_record(self):
index = self.money_record_lb.curselection()
if index:
msgbox = messagebox.askyesno("Verification","Are you sure you want to delete the selected record?")
if msgbox:
self.money_record_lb.delete(int(index[0]))
self.money_record_list.pop(int(index[0]))
self.money_record_lb.select_set(int(index[0])-1)
self.save_data()
#Delete all withdrawal records
def del_all_money_records(self):
if self.money_record_lb.size() != 0:
msgbox = messagebox.askyesno("Verification","Are you sure you want to delete all records?")
if msgbox:
self.money_record_lb.delete(0,tk.END)
self.money_record_list.clear()
self.save_data()
#Change of hourly wage
def chg_wage(self):
if self.wage_sp.get().isnumeric():
self.wage = self.wage_sp.get()
self.wage_var.set("Hourly wage: {0}Circle".format(self.wage))
self.save_data()
else:
messagebox.showinfo("error","Please enter the hourly wage as an integer value")
#Update total working hours
def add_total(self):
self.total += self.elapsed_time
self.str_total = self.strtime(self.total)
self.total_var.set("・ Total working time{0}".format(self.str_total))
#When the reset button for total working hours is pressed
def reset_total_click(self):
if self.total:
msgbox = messagebox.askyesno("Verification","Do you want to reset the total working time?")
if msgbox:
self.total = 0
self.str_total = self.strtime(self.total)
self.total_var.set("・ Total working time{0}".format(self.str_total))
self.save_data()
#self.record_lb load
def record_load(self):
if self.record_lb.size() == 0:
for i in self.record_list:
self.record_lb.insert(tk.END,i) #List record_List element of list box record_insert into lb
#self.money_record_lb load
def money_record_load(self):
if self.money_record_lb.size() == 0:
for i in self.money_record_list:
self.money_record_lb.insert(tk.END,i) #List money_record_List elements of list box money_record_insert into lb
#Data acquisition
def load_data(self):
with open("log.dat","rb") as fp:
load_list = pickle.load(fp)
count = 0
for i in load_list:
self.data_list[count] = i
count += 1
self.wage = self.data_list[0]
self.have_money = self.data_list[1]
self.record_list = self.data_list[2]
self.money_record_list = self.data_list[3]
self.total = self.data_list[4]
#Data storage
def save_data(self):
data_list = [self.wage,self.have_money,self.record_list,self.money_record_list,self.total]
with open("log.dat","wb") as fp:
pickle.dump(data_list,fp)
#Time h:mm:Convert to str type in the form of ss
def strtime(self,time):
hour = int(time / 3600)
min = int((time / 60) % 60)
sec =int(time % 60)
if hour == 0:
if min < 10:
if sec < 10:
strtime = "0{min}:0{sec}".format(min=min,sec=sec)
else:
strtime = "0{min}:{sec}".format(min=min,sec=sec)
else:
if sec < 10:
strtime = "{min}:0{sec}".format(min=min,sec=sec)
else:
strtime = "{min}:{sec}".format(min=min,sec=sec)
else:
if min < 10:
if sec < 10:
strtime = "{hour}:0{min}:0{sec}".format(hour=hour,min=min,sec=sec)
else:
strtime = "{hour}:0{min}:{sec}".format(hour=hour,min=min,sec=sec)
else:
if sec < 10:
strtime = "{hour}:{min}:0{sec}".format(hour=hour,min=min,sec=sec)
else:
strtime = "{hour}:{min}:{sec}".format(hour=hour,min=min,sec=sec)
return strtime
def main():
root = tk.Tk()
root.resizable(width=False, height=False)
app = Application(master=root)
app.mainloop()
if __name__ == "__main__":
main()
It feels pretty good.
I set the hourly wage to 300 yen and use the rule that working hours x 300 yen can be used as a hobby. If you work for 5 hours, you can go to a manga cafe for 8 hours! Do! !! !! I have to study for 20 hours to buy a new game! !! Do! !! !! It helps to maintain motivation.
It's only a short time since I started to touch python, and I think there is a place in the code that says "this is better". I would like to use it for future study, so if you notice such a thing, I would appreciate it if you could let me know in the comments.
Recommended Posts