使用Python写一个定时锁屏软件

初衷

突发奇想写定时锁屏软件,是想限制连续专注时间,做到劳逸结合。最好是每45分钟休息一下,读篇文章/散个步/聊聊天。

操作系统Win10,
语言版本Python3.7.6
开发环境Pycharm

设计

1.实现锁屏

  代码:

# -*- coding: UTF-8 -*-
from ctypes import *

user32 = windll.LoadLibrary('user32.dll')
user32.LockWorkStation()

  测试效果:运行.py文件,系统会直接进入锁屏状态,需要输入锁屏密码来解锁。

	参考:《用python写个一键锁屏的小脚本》,
地址https://editor.csdn.net/md/?articleId=112380986
2.实现计时秒表

要求:
  计时可见。
  通过GUI(图形用户界面)进行操作。

计算时间差:
  time.time()返回当前时间的时间戳。

tkinter库:
  tkinter是一个使用Python语言构建的GUI工具包。允许采用GUI的方式执行你的Python脚本。

英文教程地址:
  https://python-textbok.readthedocs.io/en/1.0/Introduction_to_GUI_Programming.html在这里插入图片描述介绍的部分原文:

  事件的监听:Anything that happens in a user interface is an event.

  窗口的组件:GUI elements, such as buttons, menus and various kinds of entry fields and display areas.
  We call these elements widgets.

  窗口的树型结构:We are going to construct a tree of widgets for our GUI – each widget will have a parent widget, all the way up to the root window of our application.

Python中文版官方文档:

  tkinter教程地址,https://www.docs4dev.com/docs/zh/python/3.7.2rc1/all/library-tk.html。(感谢该项目的创建者和维护者)
在这里插入图片描述


(2)文档可以慢读,程序可以先写

  测试程序:

import tkinter
import time

star = time.time()


def gettime():
    elap = time.time() - star  # 获取时间差
    hours = int(elap / 3600)
    minutes = int(elap / 60 - hours * 60.0)
    seconds = int(elap - minutes * 60.0)

    var.set('%02d:%02d:%02d' % (hours, minutes, seconds))
    root.after(1, gettime)  # 每隔1ms调用函数自身获取时间


root = tkinter.Tk()
root.title('电子时钟')
var = tkinter.StringVar()
lb = tkinter.Label(root, textvariable=var, fg='orange', font=("微软雅黑", 100))  # 设置字体大小颜色
lb.pack()
gettime()
root.mainloop()

  测试效果:
在这里插入图片描述

  使用到的tkinter内容:

tk = tkinter.TK()	# 创建一个窗口的实例对象
tk.title()	# 设置窗口标题

tkinter.Stringvar()	# 窗口变量
lb = tkinter.Label(text="", fg="", bg="")	# 窗口标签,包含窗口变量
lb.pack()	# 一种理解是绑定事件
tk.mainloop()	# 进入事件循环,保持监听事件

3.重新分析需求。

  实现了计时器、锁屏的基本功能,接下来重新分析需求。

分析需求:
  需要输入时间吗,或采用定长时间锁屏?定长。
突然想到输入时间,可以有包时的效果,更改需求为输入时间。
  需要暂停或终止计时吗?不需要。

4.输入时间

  测试代码:

def get_text():
    global setime
    setime = int(entry1.get())
    root2.destroy()


def time_set():
    global entry1, root2, setime
    root2 = tkinter.Tk()
    root2.title('设置时间')
    root2.geometry('300x300')
    lb = tkinter.Label(root2, text="输入锁屏Minutes:")
    lb.pack()

    entry1 = tkinter.Entry(root2)
    entry1.pack()

    anniu = tkinter.Button(root2, text='GO', command=get_text)
    anniu.pack()
    root2.mainloop()
    

  参考:《python:从输入框中读取》,地址https://blog.csdn.net/hzliyaya/article/details/9321493?utm_source=blogxgwz0

5.集成测试

  测试代码(较单元测试略有修改):

# -*- coding: UTF-8 -*-

import tkinter
import time
from ctypes import *

def gettime():

    elap = time.time() - star  # 获取时间差
    hours = int(elap / 3600)
    minutes = int(elap / 60 - hours * 60.0)
    seconds = int(elap - minutes * 60.0)

    var.set('%02d:%02d:%02d' % (hours, minutes, seconds))
    root.after(1, gettime)  # 每隔1ms调用函数自身获取时间
    if minutes > setime-1:
        user32 = windll.LoadLibrary('user32.dll')
        user32.LockWorkStation()
        exit(0)

def timing():       # 计时器
    global root, var, star
    star = time.time()
    root = tkinter.Tk()
    root.title('计时器')
    var = tkinter.StringVar()
    lb = tkinter.Label(root, textvariable=var, fg='orange', font=("微软雅黑", 100))  # 设置字体大小颜色
    lb.pack()
    gettime()
    root.mainloop()

def get_text():
    global setime
    setime = int(entry1.get())
    root2.destroy()


def time_set():
    global entry1, root2, setime
    root2 = tkinter.Tk()
    root2.title('设置时间')
    root2.geometry('300x300')
    lb = tkinter.Label(root2, text="输入锁屏Minutes:")
    lb.pack()

    entry1 = tkinter.Entry(root2)
    entry1.pack()

    anniu = tkinter.Button(root2, text='GO', command=get_text)
    anniu.pack()
    root2.mainloop()

if __name__ == '__main__':
    time_set()
    timing()

测试图:

   输入0会立即锁屏
在这里插入图片描述
   输入2则关闭第一个窗口,打开第二个窗口开始计时:
在这里插入图片描述

6.打包成exe文件

  命令行执行:pyinstaller -w lock.py
在这里插入图片描述   在打包生成的dist目录中找到lock.exe,即为最终exe程序。
运行lock.exe,如图:
在这里插入图片描述

debug和优化

exe循环锁屏

遇到一个奇怪的情况,打包脚本生成的exe文件会循环锁屏。做了一个对比测试,如下图。

运行方式输入时间是否循环锁屏
直接运行py脚本0×
直接运行py脚本1×
直接运行py脚本2×
运行exe文件0×
运行exe文件1

蛮难受的问题,临时/最终解决方式:直接运行py脚本。

占用资源优化

发现问题,是因为开启脚本电脑风扇就会启动,说明CPU利用率提高。

对比CPU利用率如下,观察进程发现CPU占用率在20%初头。

  • 开启py脚本前,CPU和磁盘文件利用率基本都在10%以内。

  • 开启py脚本后,CPU利用率在20%-30%

原因分析:root.after(1, gettime),每隔1ms都会获取一次时间。

解决方式:每隔1秒获取一次时间,也就是1000毫秒。
(一分钟获取一次,计时器看上去就不是实时的,体验不好)

root.after(1000, gettime)

效果:进程的CPU占用率在1%以内。

最新代码
# -*- coding: UTF-8 -*-

import tkinter
import time
from ctypes import *

def gettime():

    elap = time.time() - star  # 获取时间差
    hours = int(elap / 3600)
    minutes = int(elap / 60 - hours * 60.0)
    seconds = int(elap - minutes * 60.0)

    var.set('%02d:%02d:%02d' % (hours, minutes, seconds))
    root.after(1000, gettime)  # 每隔1ms调用函数自身获取时间
    if minutes > setime-1:
        user32 = windll.LoadLibrary('user32.dll')
        user32.LockWorkStation()
        exit(0)

def timing():       # 计时器
    global root, var, star
    star = time.time()
    root = tkinter.Tk()
    root.title('计时器')
    var = tkinter.StringVar()
    lb = tkinter.Label(root, textvariable=var, fg='orange', font=("微软雅黑", 100))  # 设置字体大小颜色
    lb.pack()
    gettime()
    root.mainloop()

def get_text():
    global setime
    setime = int(entry1.get())
    root2.destroy()


def time_set():
    global entry1, root2, setime
    root2 = tkinter.Tk()
    root2.title('设置时间')
    root2.geometry('300x300')
    lb = tkinter.Label(root2, text="输入锁屏Minutes:")
    lb.pack()

    entry1 = tkinter.Entry(root2)
    entry1.pack()

    anniu = tkinter.Button(root2, text='GO', command=get_text)
    anniu.pack()
    root2.mainloop()

if __name__ == '__main__':
    time_set()
    timing()

闲谈

锁屏木马

  编写锁屏程序的过程中,由于没有做好循环控制,碰到了0秒循环锁屏的情况。幸好CSDN会自动保存草稿,心态被救。

  循环锁屏的情况是通过重启电脑的手段解决的,如果把该锁屏程序设置为开机自启呢?联想冰河木马修改注册表、自启动的方式,以及最近的incaseformat蠕虫病毒,这个锁屏程序似乎也可以写成一个木马。

  想象锁屏木马的效果,开机即无限锁屏。
如果像冰河木马一样修改注册表,单纯删除文件是无法清除的。
可以通过U盘、网页flash等方式传播这个恶作剧小程序。

  最简单直接的解决方式,就是重装操作系统。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值