[Python] I tried to make an application that calculates salary according to working hours with tkinter

Background

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".

Functions you want to add

--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

environment

What I actually made

Main screen tab

2020-06-02.png The screen at startup looks like this.

2020-06-02 (1).png When you press the "Start" button, the timer will start and the "Start" button will change to the "Pause" button.

2020-06-02 (2).png 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.

2020-06-02 (3).png To prevent accidental clicks, a confirmation window like this is displayed when the "Finish" and "Reset" buttons are pressed.

2020-06-02 (5).png 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").

Recording tab

image.png 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.

image.png 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.

Drawer recording tab

image.png You can see the salary withdrawal record.

Settings tab

image.png You can check / reset the total working hours and change the hourly wage.

1591025774093.jpg 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.

Source code

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()

Try using this app

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.

Finally

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

[Python] I tried to make an application that calculates salary according to working hours with tkinter
I tried to make an OCR application with PySimpleGUI
I tried to make a simple mail sending application with tkinter of Python
I tried to make GUI tic-tac-toe with Python and Tkinter
I tried to make a 2channel post notification application with Python
I tried to make a todo application using bottle with python
I tried to make an image similarity function with Python + OpenCV
I tried to make an original language "PPAP Script" that imaged PPAP (Pen Pineapple Appo Pen) with Python
I tried to implement an artificial perceptron with python
I tried to make various "dummy data" with Python faker
I tried to make a stopwatch using tkinter in python
[1 hour challenge] I tried to make a fortune-telling site that is too suitable with Python
I tried to make a generator that generates a C # container class from CSV with Python
[5th] I tried to make a certain authenticator-like tool with python
I tried to make an activity that collectively sets location information
[2nd] I tried to make a certain authenticator-like tool with python
[3rd] I tried to make a certain authenticator-like tool with python
[Python] A memo that I tried to get started with asyncio
I tried to make a periodical process with Selenium and Python
[4th] I tried to make a certain authenticator-like tool with python
[Python] Simple Japanese ⇒ I tried to make an English translation tool
[1st] I tried to make a certain authenticator-like tool with python
I tried sending an email with python.
Python: I tried to make a flat / flat_map just right with a generator
I tried to make an open / close sensor (Twitter cooperation) with TWE-Lite-2525A
I tried to make a calculator with Tkinter so I will write it
[AWS] [GCP] I tried to make cloud services easy to use with Python
I tried to make a traffic light-like with Raspberry Pi 4 (Python edition)
I tried to discriminate a 6-digit number with a number discrimination application made with python
[Zaif] I tried to make it easy to trade virtual currencies with Python
I want to make a game with Python
I tried to get CloudWatch data with Python
I tried to output LLVM IR with Python
I tried to detect an object with M2Det!
I tried to automate sushi making with python
I tried sending an email with SendGrid + Python
I tried to make a periodical process with CentOS7, Selenium, Python and Chrome
[Patent analysis] I tried to make a patent map with Python without spending money
[ES Lab] I tried to develop a WEB application with Python and Flask ②
[Python] I tried to make a Shiritori AI that enhances vocabulary through battles
I tried to make Kana's handwriting recognition Part 3/3 Cooperation with GUI using Tkinter
I tried to implement Minesweeper on terminal with python
I tried to get started with blender python script_Part 01
I tried to touch the CSV file with Python
I tried to draw a route map with Python
I tried to solve the soma cube with python
Continuation ・ I tried to make Slackbot after studying Python3
I tried to get started with blender python script_Part 02
I tried to automatically generate a password with Python3
I tried to solve the problem with Python Vol.1
I tried to analyze J League data with Python
I tried to find an alternating series with tensorflow
Make an application using tkinter an executable file with cx_freeze
I tried to solve AOJ's number theory with Python
I tried to make a real-time sound source separation mock with Python machine learning
[Mac] I want to make a simple HTTP server that runs CGI with Python
I tried to build an environment for machine learning with Python (Mac OS X)
I tried to find the entropy of the image with python
I tried fp-growth with python
I tried scraping with Python
I tried to simulate how the infection spreads with Python